How get all matching positions in a string?

前端 未结 3 1855
轻奢々
轻奢々 2021-01-29 14:46

I have a column flag_acumu in a table in PostgreSQL with values like:

\'SSNSSNNNNNNNNNNNNNNNNNNNNNNNNNNNNSNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN\'         


        
相关标签:
3条回答
  • 2021-01-29 15:04

    In Postgres 9.4 or later you can conveniently use unnest() in combination with WITH ORDINALITY:

    SELECT *
    FROM   dh12 d
    JOIN   unnest(string_to_array(d.flag_acumu, NULL))
              WITH ORDINALITY u(elem, the_pos) ON u.elem = 'S'
    WHERE  d.flag_acumu LIKE '%S%'  -- optional, see below
    ORDER  BY d.codn_conce, u.the_pos;
    

    This returns one row per match. WHERE d.flag_acumu LIKE '%S%' is optional to quickly eliminate source rows without any matches. Pays if there are more than a few such rows.

    Detailed explanation and alternatives for older versions:

    • PostgreSQL unnest() with element number
    0 讨论(0)
  • 2021-01-29 15:24

    This works too. And a bit faster I think.

    create or replace function findAllposition(_pat varchar, _tar varchar) 
    returns int[] as
    $body$
    declare _poslist int[]; _pos int;
    begin
    
    _pos := position(_pat in _tar);
    while (_pos>0)
    loop
    
        if array_length(_poslist,1) is null then
            _poslist := _poslist || (_pos);
        else
            _poslist := _poslist || (_pos + _poslist[array_length(_poslist,1)] + 1);
        end if;
    
        _tar := substr(_tar, _pos + 1, length(_tar));
        _pos := position(_pat in _tar);
    
    end loop;
    return _poslist;
    
    end;
    $body$
    language plpgsql;
    

    Will return a position list which is an int array.

    {position1, position2, position3, etc.}
    
    0 讨论(0)
  • 2021-01-29 15:25

    Since you didn't specify your needs to a point in which one could answer properly, I'm going with my assumption that you want a list of positions of occurence of a substring (can be more than 1 character long).

    Here's the function to do that using:

    • FOR .. LOOP control structure,
    • function substr(text, int, int).

    CREATE OR REPLACE FUNCTION get_all_positions_of_substring(text, text)
    RETURNS text
    STABLE
    STRICT
    LANGUAGE plpgsql
    AS $$
    DECLARE
      output_text TEXT := '';
    BEGIN
    
    FOR i IN 1..length($1)
    LOOP
      IF substr($1, i, length($2)) = $2 THEN
        output_text := CONCAT(output_text, ';', i);
      END IF;
    END LOOP;
    
    -- Remove first semicolon
    output_text := substr(output_text, 2, length(output_text));
    
    RETURN output_text;
    END;
    $$;
    

    Sample call and output

    postgres=# select * from get_all_positions_of_substring('soklesocmxsoso','so');
     get_all_positions_of_substring
    --------------------------------
     1;6;11;13
    
    0 讨论(0)
提交回复
热议问题