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 ??

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 || '%';

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. `


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;

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.


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


2
Ini adalah kebalikan dari jawaban yang diterima . Anda merangkai sebagai string sementara itu perlu menjadi kolom ...
— Suraj Rao
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.