Postgresql SELECT หากมีสตริง


108

ดังนั้นฉันจึงมีใน Postgresql ของฉัน:

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

เพื่อให้ปัญหาของฉันง่ายขึ้นสิ่งที่ฉันต้องการทำคือ SELECT "id" จาก TAG_TABLE เมื่อสตริง "aaaaaaaa" มี "tag_name" ตามหลักการแล้วควรส่งคืนเฉพาะ "1" ซึ่งเป็น ID สำหรับชื่อแท็ก "aaa"

นี่คือสิ่งที่ฉันกำลังทำอยู่:

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

แต่เห็นได้ชัดว่าสิ่งนี้ไม่ได้ผลเนื่องจาก postgres คิดว่า '% tag_name%' หมายถึงรูปแบบที่มีสตริงย่อย 'tag_name' แทนที่จะเป็นค่าข้อมูลจริงในคอลัมน์นั้น

ฉันจะส่ง tag_name ไปยังรูปแบบได้อย่างไร ??

คำตอบ:


135

คุณควรใช้ 'tag_name' นอกเครื่องหมายคำพูด จากนั้นตีความว่าเป็นฟิลด์ของบันทึก เชื่อมต่อกันโดยใช้ '||' ด้วยเครื่องหมายเปอร์เซ็นต์ตามตัวอักษร:

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

5
hapoens เมื่อ tag_name คือ"; drop table TAG_TABLE; --"อะไร?
Denis de Bernardy

24
@ เดนิส: ไม่มีอะไรเกิดขึ้น คุณจะได้รับไม่มีแถวเพราะประเมินข้อที่จะWHERE FALSEคำสั่งไม่ได้เป็นแบบไดนามิกมีเพียงค่าที่ต่อกันไม่มีโอกาสสำหรับการแทรก SQL
Erwin Brandstetter

1
ไม่ควรเป็นลำดับของ aaaa และ tag_name ที่กลับรายการ? ฉันหมายความว่าคุณควรใส่ชื่อคอลัมน์ตามหลัง
user151496

@ user151496 ไม่ใช่เพราะรูปแบบต้องอยู่ทางด้านขวาของLIKEคีย์เวิร์ด
jpmc26

4
ระวังว่าการใช้ตัวแปรในLIKEรูปแบบอาจส่งผลที่ไม่ได้ตั้งใจเมื่อตัวแปรเหล่านั้นมีเครื่องหมายขีดล่าง (_) หรืออักขระเปอร์เซ็นต์ (%) อาจจำเป็นต้องหลีกเลี่ยงอักขระเหล่านี้ตัวอย่างเช่นเมื่อใช้ฟังก์ชันนี้: CREATE OR REPLACE FUNCTION quote_for_like(text) RETURNS text LANGUAGE SQL IMMUTABLE AS $$ SELECT regexp_replace($1, '([\%_])', '\\\1', 'g'); $$;(จากผู้ใช้ MatheusOl จากช่อง #postgresql IRC บน Freenode)
Martin von Wittich

46

โดยส่วนตัวแล้วฉันชอบไวยากรณ์ที่ง่ายกว่าของตัวดำเนินการ ~

SELECT id FROM TAG_TABLE WHERE 'aaaaaaaa' ~ tag_name;

ควรค่าแก่การอ่านผ่านความแตกต่างระหว่าง LIKE และ ~ ใน Postgresเพื่อทำความเข้าใจความแตกต่าง `


2
สิ่งนี้ใช้ได้เฉพาะเมื่อtag_nameเป็น REGEX ที่เหมาะสมเท่านั้น ค่อนข้างเสี่ยง
Jakub Fedyczak

@JakubFedyczak เพื่อให้ตรงกับตัวอักษร tag_name คุณสามารถใช้***=ซึ่งเป็นที่กล่าวถึงในpostgresql.org/docs/current/static/functions-matching.html อย่างไรก็ตามฉันพบว่าช้าเกินไปเมื่อเทียบกับstrpos/ positionโซลูชัน
phunehehe

28

วิธีการที่เหมาะสมในการค้นหาสตริงย่อยคือการใช้งานpositionฟังก์ชั่นแทนการlikeแสดงออกซึ่งจะต้องมีการหลบหนี%, _และตัวหนี ( \ค่าเริ่มต้น):

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

นี่เป็นวิธีที่ถูกต้องในการทำเช่นนี้ ไม่ควรมีใครใช้วิธี regex ที่แฮ็ก
khol

LIKEและILIKEสามารถใช้ginดัชนี positionไม่ได้.
Eugene Pakhomov

14

นอกจากนี้ในการแก้ปัญหาด้วย'aaaaaaaa' LIKE '%' || tag_name || '%'มีposition(ลำดับที่ตรงกันข้ามของ args) strposและ

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

นอกจากสิ่งที่มีประสิทธิภาพมากกว่า (LIKE ดูมีประสิทธิภาพน้อยกว่า แต่ดัชนีอาจเปลี่ยนแปลงสิ่งต่าง ๆ ) ยังมีปัญหาเล็กน้อยเกี่ยวกับ LIKE: tag_name ไม่ควรมี%และโดยเฉพาะอย่างยิ่ง_(อักขระตัวแทนตัวเดียว) เพื่อให้ไม่มีผลบวกที่ผิดพลาด


2
ฉันต้องแทนที่ strpos ด้วยตำแหน่งเนื่องจาก strpos ส่งคืน 0 ให้ฉันเสมอ
jcf

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

tag_name ควรอยู่ในใบเสนอราคามิฉะนั้นจะให้ข้อผิดพลาดเนื่องจาก tag_name doest ไม่มีอยู่


2
ตรงนี้เป็นตรงข้ามของได้รับการยอมรับคำตอบ คุณกำลังต่อกันเป็นสตริงในขณะที่มันต้องเป็นคอลัมน์ ...
Suraj Rao
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.