Symbol wieloznaczny PostgreSQL TAK jak dowolna lista słów

156

Mam prostą listę ~ 25 słów. Mam pole varchar w PostgreSQL, powiedzmy, że jest to lista ['foo', 'bar', 'baz']. Chcę znaleźć dowolny wiersz w mojej tabeli, który zawiera którekolwiek z tych słów. To zadziała, ale chciałbym coś bardziej eleganckiego.

select *
from table
where (lower(value) like '%foo%' or lower(value) like '%bar%' or lower(value) like '%baz%')
chmullig
źródło

Odpowiedzi:

165

Możesz użyć SIMILAR TOoperatora Postgresa , który obsługuje alternacje, tj

select * from table where lower(value) similar to '%(foo|bar|baz)%';
Nordic Mainframe
źródło
1
Regex może to trochę przyspieszyć
około niebieskiego.
Skąd to wiedziałeś ? większość dokumentacji, którą przeczytałem, mówi, że wyrażenia regularne są wolniejsze i LIKE% ...
DestyNova
5
Według dba.stackexchange.com/a/10696/27757 SIMILAR TO jest wewnętrznie tłumaczone na wyszukiwanie wyrażeń regularnych
Mark K Cowan
Myślę, że używanie lower()jest nieskuteczne, ponieważ najpierw konwertuje każdy ciąg na małe litery, co jest bardziej kosztowne niż tylko dopasowanie
bez rozróżniania
228

PostgreSQL obsługuje również pełne wyrażenia regularne POSIX :

select * from table where value ~* 'foo|bar|baz';

Jest ~*to dopasowanie bez rozróżniania wielkości liter, rozróżnia wielkość liter ~.

Inną opcją jest użycie DOWOLNEGO :

select * from table where value  like any (array['%foo%', '%bar%', '%baz%']);
select * from table where value ilike any (array['%foo%', '%bar%', '%baz%']);

Możesz użyć DOWOLNEGO z dowolnym operatorem, który zwraca wartość logiczną. Podejrzewam, że opcje regex byłyby szybsze, ale KAŻDY jest przydatnym narzędziem, które należy mieć w swoim zestawie narzędzi.

mu jest za krótkie
źródło
Co ciekawe, chociaż obie te metody są bardziej eleganckie niż rozwiązanie @chmulliga (a więc +1), sprawdzając przynajmniej 3 opcje, wykonują się one znacznie wolniej na dużych tabelach (w moim przypadku 91,5 miliona rekordów). Używając któregokolwiek z nich, zauważyłem około dwukrotny wzrost czasu. Masz jakiś pomysł, dlaczego tak może być?
sage88,
@ sage88 Nie wiem z góry, ale Erwin Brandstetter może i dodanie indeksów trygramowych może pomóc.
mu jest za krótkie
13

Właściwie jest do tego operator w PostgreSQL:

SELECT *
FROM table
WHERE lower(value) ~~ ANY('{%foo%,%bar%,%baz%}');
jlandercy
źródło
6
~~jest po prostu inna nazwa like: „Operator ~~odpowiada LIKE, a ~~*odpowiada ILIKEIstnieją również. !~~i !~~*podmioty, które reprezentują NOT LIKEi NOT ILIKEodpowiednio Wszystkie te podmioty są specyficzne dla PostgreSQL.”. . I '{%foo%,%bar%,%baz%}'jest formą tekstową array['%foo%', '%bar%', '%baz%'].
mu jest za krótkie
Czy zatem ilike może być używany z dowolną & tablicą w ten sam sposób? Wygląda to porządnie, jeśli nie ma potrzeby stosowania fantazyjnych wyrażeń regularnych. A może mimo to zostanie przetłumaczone wewnętrznie na wyrażenia regularne?
mlt
@mlt To dobre pytanie, przeczytanie tego dokumentu nie daje jednoznacznej odpowiedzi. SIMILAR TOkonwertuje na wyrażenie regularne, ~operator oznacza wyrażenie regularne POSIX, ale nie jest to jasne dla LIKE.
jlandercy
0

Jednym „eleganckim” rozwiązaniem byłoby użycie wyszukiwania pełnotekstowego: http://www.postgresql.org/docs/9.0/interactive/textsearch.html . Następnie należy użyć zapytań wyszukiwania pełnotekstowego.

Kalendae
źródło
1
Głosuj przeciw, bo to tylko link, który lepiej nadawałby się jako komentarz.
toraritte