How get all matching positions in a string?

我与影子孤独终老i 提交于 2019-12-04 07:13:04

问题


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

'SSNSSNNNNNNNNNNNNNNNNNNNNNNNNNNNNSNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN'

I need to show all positions with an 'S'. With this code, I only get the first such position, but not the later ones.

SELECT codn_conce, flag_acumu, position('S' IN flag_acumu) AS the_pos 
FROM dh12 
WHERE position('S' IN flag_acumu) != 0 
ORDER BY the_pos ASC;

How to get all of them?


回答1:


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



回答2:


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



回答3:


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.}


来源:https://stackoverflow.com/questions/34495881/how-get-all-matching-positions-in-a-string

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!