Wildcard PostgreSQL SEPERTI untuk setiap daftar kata

156

Saya punya daftar sederhana ~ 25 kata. Saya memiliki bidang varchar di PostgreSQL, katakanlah daftar itu ['foo', 'bar', 'baz']. Saya ingin menemukan baris di meja saya yang memiliki kata-kata itu. Ini akan berhasil, tetapi saya ingin sesuatu yang lebih elegan.

select *
from table
where (lower(value) like '%foo%' or lower(value) like '%bar%' or lower(value) like '%baz%')
chmullig
sumber

Jawaban:

166

Anda dapat menggunakan SIMILAR TOoperator Postgres yang mendukung pergantian, yaitu

select * from table where lower(value) similar to '%(foo|bar|baz)%';
Mainframe Nordik
sumber
1
Regex mungkin mempercepat ini sedikit: dba.stackexchange.com/questions/10694/…
kira
Bagaimana kamu bisa tahu ? sebagian besar dokumentasi yang saya baca mengatakan bahwa regex lebih lambat dan LIKE% ...
DestyNova
5
Menurut dba.stackexchange.com/a/10696/27757 SIMILAR TO diterjemahkan secara internal ke pencarian regex
Mark K Cowan
Saya pikir menggunakan lower()tidak efektif karena pertama-tama akan mengkonversi setiap string menjadi huruf kecil, yang lebih mahal daripada hanya pertandingan dengan huruf besar-kecil
gilad mayani
229

PostgreSQL juga mendukung ekspresi reguler POSIX lengkap :

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

Ini ~*untuk pertandingan yang tidak peka huruf besar kecil, ~peka huruf besar kecil.

Pilihan lain adalah menggunakan APA PUN :

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

Anda dapat menggunakan APA SAJA dengan operator apa pun yang menghasilkan boolean. Saya menduga bahwa opsi regex akan lebih cepat tetapi APAPUN adalah alat yang berguna untuk ada di kotak peralatan Anda.

mu terlalu pendek
sumber
Menariknya, walaupun kedua metode ini lebih elegan daripada solusi @chmullig (jadi +1), ketika memeriksa 3 opsi setidaknya, mereka mengeksekusi lebih lambat secara signifikan pada tabel besar (91,5 juta catatan dalam kasus saya). Saya melihat peningkatan waktu sekitar 2x ketika menggunakan salah satu dari ini. Adakah yang tahu mengapa itu terjadi?
sage88
@ sage88 Saya tidak tahu dari atas kepala saya tetapi Erwin Brandstetter mungkin dan menambahkan indeks trigram mungkin membantu.
mu terlalu pendek
13

Sebenarnya ada operator untuk itu di PostgreSQL:

SELECT *
FROM table
WHERE lower(value) ~~ ANY('{%foo%,%bar%,%baz%}');
jlandercy
sumber
6
~~hanyalah nama lain untuk like: "Operator ~~setara dengan LIKE, dan ~~*sesuai dengan ILIKE. Ada juga !~~dan !~~*operator yang mewakili NOT LIKEdan NOT ILIKE, masing-masing. Semua operator ini adalah khusus PostgreSQL." . Dan '{%foo%,%bar%,%baz%}'merupakan bentuk teks dari array['%foo%', '%bar%', '%baz%'].
mu terlalu pendek
Jadi bisa ilike digunakan dengan setiap & array dalam cara yang sama? Ini terlihat bersih jika tidak perlu untuk regex mewah. Atau apakah itu akan diterjemahkan menjadi regex secara internal?
mlt
@mlt Itu pertanyaan yang bagus, membaca dokumen tidak memberikan jawaban eksplisit. SIMILAR TOdikonversi menjadi Ekspresi Reguler, ~operator adalah singkatan dari Ekspresi Reguler POSIX, tetapi ini tidak jelas untuk LIKE.
jlandercy
0

Satu solusi 'elegan' adalah dengan menggunakan pencarian teks lengkap: http://www.postgresql.org/docs/9.0/interactive/textsearch.html . Maka Anda akan menggunakan permintaan pencarian teks lengkap.

Kalendae
sumber
1
Downvote, karena ini hanya tautan yang akan lebih cocok sebagai komentar.
toraritte