Postgresql CHỌN nếu chuỗi chứa


105

Vì vậy, tôi có một trong Postgresql của mình:

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

Để đơn giản hóa vấn đề của tôi, điều tôi muốn làm là CHỌN 'id' từ TAG_TABLE khi chuỗi "aaaaaaaa" chứa 'tag_name'. Vì vậy, lý tưởng nhất, nó chỉ nên trả về "1", là ID cho tên thẻ 'aaa'

Đây là những gì tôi đang làm cho đến nay:

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

Nhưng rõ ràng, điều này không hiệu quả, vì postgres nghĩ rằng '% tag_name%' có nghĩa là một mẫu chứa chuỗi con 'tag_name' thay vì giá trị dữ liệu thực tế trong cột đó.

Làm cách nào để chuyển tag_name vào mẫu ??

Câu trả lời:


131

Bạn nên sử dụng 'tag_name' bên ngoài dấu ngoặc kép; thì nó được hiểu là một trường của bản ghi. Nối bằng '||' với các dấu phần trăm theo nghĩa đen:

SELECT id FROM TAG_TABLE WHERE 'aaaaaaaa' LIKE '%' || tag_name || '%';

5
điều gì xảy ra khi tag_name là "; drop table TAG_TABLE; --"?
Denis de Bernardy

24
@Denis: Không có gì xảy ra. Bạn không nhận được hàng, bởi vì WHEREmệnh đề đánh giá đến FALSE. Câu lệnh không động, chỉ có các giá trị được nối với nhau, không có cơ hội cho SQL injection.
Erwin Brandstetter

1
không nên đảo ngược thứ tự của aaaa và tag_name? ý tôi là bạn nên đặt tên cột sau vị trí
user151496

@ user151496 Không vì mẫu phải nằm ở phía bên phải của LIKEtừ khóa.
jpmc 26

4
Hãy lưu ý rằng việc sử dụng các biến trong một LIKEmẫu có thể gây ra hậu quả không mong muốn khi các biến đó chứa dấu gạch dưới (_) hoặc ký tự phần trăm (%). Có thể cần phải thoát các ký tự này, ví dụ với hàm này: CREATE OR REPLACE FUNCTION quote_for_like(text) RETURNS text LANGUAGE SQL IMMUTABLE AS $$ SELECT regexp_replace($1, '([\%_])', '\\\1', 'g'); $$;(từ người dùng MatheusOl từ kênh IRC #postgresql trên Freenode).
Martin von Wittich

46

Cá nhân tôi thích cú pháp đơn giản hơn của toán tử ~.

SELECT id FROM TAG_TABLE WHERE 'aaaaaaaa' ~ tag_name;

Đáng đọc qua Sự khác biệt giữa LIKE và ~ trong Postgres để hiểu sự khác biệt. `


2
Điều này chỉ hoạt động khi tag_namelà một REGEX thích hợp. Khá rủi ro.
Jakub Fedyczak

@JakubFedyczak để khớp với tag_name theo nghĩa đen mà bạn có thể sử dụng ***=được đề cập trong postgresql.org/docs/current/static/functions-matching.html . Tuy nhiên, tôi thấy rằng chậm hơn nhiều so với strpos/ positiongiải pháp.
phunehehe

27

Một cách thích hợp để tìm kiếm một chuỗi con là để sử dụng positionchức năng thay vì likebiểu hiện, đòi hỏi thoát %, _và một ký tự thoát ( \theo mặc định):

SELECT id FROM TAG_TABLE WHERE position(tag_name in 'aaaaaaaaaaa')>0;

Đây là cách đúng đắn để làm điều này. Không ai nên sử dụng các phương pháp hacky regex.
khol

LIKEILIKEcó thể sử dụng gincác chỉ số. positionkhông thể.
Eugene Pakhomov

14

Ngoài các giải pháp với 'aaaaaaaa' LIKE '%' || tag_name || '%'position(đảo ngược thứ tự của args) và strpos.

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

Bên cạnh những gì hiệu quả hơn (LIKE có vẻ kém hiệu quả hơn, nhưng một chỉ mục có thể thay đổi mọi thứ), có một vấn đề rất nhỏ với LIKE: tag_name tất nhiên không nên chứa %và đặc biệt là _(ký tự đại diện một ký tự), để không có kết quả dương tính giả.


2
Tôi đã phải thay thế strpos bằng vị trí, vì strpos luôn trả về 0 cho tôi
jcf

-2
SELECT id FROM TAG_TABLE WHERE 'aaaaaaaa' LIKE '%' || "tag_name" || '%';

tag_name phải nằm trong dấu ngoặc kép nếu không nó sẽ báo lỗi vì tag_name không tồn tại


2
Điều này hoàn toàn ngược lại với câu trả lời được chấp nhận . Bạn đang concatenating như chuỗi trong khi nó cần phải được một cột ...
Suraj Rao
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.