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;