PILIH Postgresql jika string berisi

105

Jadi saya punya di Postgresql saya:

TAG_TABLE
==========================
id            tag_name       
--------------------------
1             aaa
2             bbb
3             ccc

Untuk menyederhanakan masalah saya, Yang ingin saya lakukan adalah PILIH 'id' dari TAG_TABLE ketika string "aaaaaaaa" berisi 'tag_name'. Idealnya, ini hanya mengembalikan "1", yang merupakan ID untuk nama tag 'aaa'

Inilah yang saya lakukan sejauh ini:

SELECT id FROM TAG_TABLE WHERE 'aaaaaaaaaaa' LIKE '%tag_name%'

Tapi jelas, ini tidak berfungsi, karena postgres berpikir bahwa '% tag_name%' berarti pola yang berisi substring 'tag_name' alih-alih nilai data aktual di bawah kolom itu.

Bagaimana cara mengirimkan tag_name ke pola ??

pengguna2436815
sumber

Jawaban:

131

Anda harus menggunakan 'tag_name' di luar tanda kutip; kemudian diartikan sebagai field of the record. Gabungkan menggunakan '||' dengan tanda persen literal:

SELECT id FROM TAG_TABLE WHERE 'aaaaaaaa' LIKE '%' || tag_name || '%';
Frans van Buul
sumber
5
apa yang terjadi saat tag_name "; drop table TAG_TABLE; --"?
Denis de Bernardy
24
@Denis: Tidak ada yang terjadi. Anda tidak mendapatkan baris, karena WHEREklausa mengevaluasi ke FALSE. Pernyataan tersebut tidak dinamis, hanya nilai yang digabungkan, tidak ada peluang untuk injeksi SQL.
Erwin Brandstetter
1
Bukankah seharusnya urutan aaaa dan tag_name dibalik? Maksud saya, Anda harus meletakkan nama kolom setelah where
user151496
@ user151496 Tidak karena polanya harus berada di sisi kanan LIKEkata kunci.
jpmc26
4
Berhati-hatilah bahwa menggunakan variabel dalam LIKEpola mungkin memiliki konsekuensi yang tidak diinginkan saat variabel tersebut berisi garis bawah (_) atau persen karakter (%). Mungkin perlu untuk keluar dari karakter ini, misalnya dengan fungsi ini: CREATE OR REPLACE FUNCTION quote_for_like(text) RETURNS text LANGUAGE SQL IMMUTABLE AS $$ SELECT regexp_replace($1, '([\%_])', '\\\1', 'g'); $$;(dari pengguna MatheusOl dari saluran IRC #postgresql di Freenode).
Martin von Wittich
46

Saya pribadi lebih suka sintaks yang lebih sederhana dari ~ operator.

SELECT id FROM TAG_TABLE WHERE 'aaaaaaaa' ~ tag_name;

Layak dibaca Perbedaan antara LIKE dan ~ di Postgres untuk memahami perbedaannya. `

keithhackbarth
sumber
2
Ini hanya berfungsi jika tag_nameREGEX tepat. Cukup beresiko.
Jakub Fedyczak
@JakubFedyczak untuk mencocokkan tag_name literal yang dapat Anda gunakan ***=yang disebutkan di postgresql.org/docs/current/static/functions-matching.html . Namun saya telah menemukan bahwa menjadi terlalu lambat dibandingkan dengan strpos/ positionsolutions.
phunehehe
27

Cara yang tepat untuk mencari substring adalah dengan menggunakan positionfungsi alih-alih likeekspresi, yang membutuhkan pelolosan %, _dan karakter pelolosan ( \secara default):

SELECT id FROM TAG_TABLE WHERE position(tag_name in 'aaaaaaaaaaa')>0;
Tometzky
sumber
Ini adalah cara yang benar untuk melakukan ini. Tidak ada yang boleh menggunakan pendekatan hacky regex.
khol
LIKEdan ILIKEdapat menggunakan ginindeks. positiontidak bisa.
Eugene Pakhomov
14

Selain solusi dengan 'aaaaaaaa' LIKE '%' || tag_name || '%'ada position(urutan argumen dibalik) dan strpos.

SELECT id FROM TAG_TABLE WHERE strpos('aaaaaaaa', tag_name) > 0

Selain apa yang lebih efisien (LIKE terlihat kurang efisien, tetapi indeks dapat mengubah banyak hal), ada masalah yang sangat kecil dengan LIKE: tag_name tentu saja tidak boleh berisi %dan terutama _(wildcard karakter tunggal), untuk tidak memberikan positif palsu.

Joop Eggen
sumber
2
Saya harus mengganti strpos dengan posisi, karena strpos selalu mengembalikan 0 untuk saya
jcf
-2
SELECT id FROM TAG_TABLE WHERE 'aaaaaaaa' LIKE '%' || "tag_name" || '%';

tag_name harus di kutip jika tidak maka akan memberikan kesalahan karena tag_name tidak ada

Shweta Verma
sumber
2
Ini adalah kebalikan dari jawaban yang diterima . Anda merangkai sebagai string sementara itu perlu menjadi kolom ...
Suraj Rao