CountMatches() эквивалентный запрос Postgres

Мы знаем, что функция stringutils CountMatches() - CountMatches - подсчитывает количество вхождений одной строки в другую. Мне нужен эквивалентный запрос в postgresql для подсчета количества вхождений одной строки в другую.

Любая идея была бы оценена

3 ответа

Вы можете использовать regexp_matches с жадным переключателем:

select count ( * )
from regexp_matches ( 'abc abc', 'ab', 'g' ); -- result is 2

regexp_matches()

Решение с regexp_matches() То, что @Igor предложил и реализовал @Tomasz, коротко и элегантно, но имеет два недостатка:

  • Регулярные выражения являются мощными, но обычно намного медленнее, чем простые функции.
  • Совокупный шаг делает нетривиальной интеграцию в большие запросы.

Чтобы использовать его в запросе с несколькими исходными строками:

SELECT t.*, count(match) AS ct
FROM   tbl t
LEFT   JOIN LATERAL regexp_matches(t.string, 'ab', 'g') match ON TRUE
GROUP  BY t.tbl_id
ORDER  BY t.tbl_id;

Или же:

SELECT t.*, m.ct
FROM   tbl t
LEFT   JOIN LATERAL (
   SELECT count(*) AS ct
   FROM   regexp_matches(t.string, 'ab', 'g')
   ) m ON TRUE
ORDER  BY t.tbl_id;

replace() / length()

Выражение не так элегантно, но должно быть быстрее и его можно использовать на множествах проще:

SELECT (length(col) - length(replace(col, 'match', ''))) / length('match') AS ct;

Вы можете обернуть это в простую функцию SQL:

CREATE OR REPLACE FUNCTION f_count_matches(_string text, _match text)
  RETURNS int LANGUAGE sql IMMUTABLE STRICT AS
$$
SELECT (length(_string) - length(replace(_string, _match, ''))) / length(_match)
$$;

Затем:

SELECT f_count_matches('abc cab,xabx abab', 'ab');

SQL Fiddle демонстрирует все.

PostgreSQL не имеет этой функции, но вы можете обойти это следующим образом:

SELECT array_length(regexp_split_to_array('axbxcxdxexfxg','b'),1)-1;  -- returns 1
SELECT array_length(regexp_split_to_array('axbxcxdxexfxg','x'),1)-1;  -- returns 6
SELECT array_length(regexp_split_to_array('axbxcxdxexfxg','z'),1)-1;  -- returns 0

Могут быть крайние случаи, которые не работают правильно.

regexp_split_to_array создает массив с несовпадающими частями. Количество элементов в массиве на один больше, чем количество совпадений (по крайней мере, для обычных случаев). Так, array_length а также -1 произвести подсчет совпадений.

CREATE FUNCTION num_matches(string text,pattern text)
RETURNS int AS $$
    SELECT array_length(regexp_split_to_array(string,pattern),1)-1;
$$ LANGUAGE SQL STABLE;
Другие вопросы по тегам