Postgresql SELECT wenn String enthält


105

Also habe ich eine in meinem Postgresql:

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

Um mein Problem zu vereinfachen, möchte ich 'id' aus TAG_TABLE AUSWÄHLEN, wenn eine Zeichenfolge "aaaaaaaa" den 'tag_name' enthält. Im Idealfall sollte nur "1" zurückgegeben werden. Dies ist die ID für den Tag-Namen "aaa".

Das mache ich bisher:

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

Dies funktioniert jedoch offensichtlich nicht, da die Postgres der Ansicht sind, dass '% tag_name%' ein Muster bedeutet, das den Teilstring 'tag_name' anstelle des tatsächlichen Datenwerts unter dieser Spalte enthält.

Wie übergebe ich den Tag-Namen an das Muster?

Antworten:


131

Sie sollten 'tag_name' außerhalb von Anführungszeichen verwenden. dann wird es als ein Feld des Datensatzes interpretiert. Verketten Sie mit '||' mit den wörtlichen Prozentzeichen:

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

5
Was passiert, wenn tag_name ist "; drop table TAG_TABLE; --"?
Denis de Bernardy

24
@Denis: Nichts passiert. Sie erhalten keine Zeile, da die WHEREKlausel als ausgewertet wird FALSE. Die Anweisung ist nicht dynamisch, nur Werte werden verkettet, keine Chance für SQL-Injection.
Erwin Brandstetter

1
sollte die Reihenfolge von aaaa und tag_name nicht umgekehrt werden? Ich meine, dass Sie einen Spaltennamen nach wo setzen sollten
user151496

@ user151496 Nein, da das Muster auf der rechten Seite des LIKESchlüsselworts stehen muss.
jpmc26

4
Beachten Sie, dass die Verwendung von Variablen in einem LIKEMuster unbeabsichtigte Folgen haben kann, wenn diese Variablen Unterstriche (_) oder Prozentzeichen (%) enthalten. Es kann erforderlich sein, diese Zeichen zu CREATE OR REPLACE FUNCTION quote_for_like(text) RETURNS text LANGUAGE SQL IMMUTABLE AS $$ SELECT regexp_replace($1, '([\%_])', '\\\1', 'g'); $$;maskieren , beispielsweise mit folgender Funktion: (vom Benutzer MatheusOl aus dem IRC-Kanal #postgresql auf Freenode).
Martin von Wittich

46

Ich persönlich bevorzuge die einfachere Syntax des Operators ~.

SELECT id FROM TAG_TABLE WHERE 'aaaaaaaa' ~ tag_name;

Es lohnt sich, den Unterschied zwischen LIKE und ~ in Postgres durchzulesen , um den Unterschied zu verstehen. `


2
Dies funktioniert nur, wenn tag_namees sich um einen richtigen REGEX handelt. Ziemlich riskant.
Jakub Fedyczak

@JakubFedyczak entspricht dem wörtlichen Tag-Namen, den Sie verwenden können . Dies***= wird in postgresql.org/docs/current/static/functions-matching.html erwähnt . Ich habe jedoch festgestellt, dass dies im Vergleich zu den strpos/ position-Lösungen zu viel langsamer ist .
Phunehehe

27

Ein richtiger Weg für eine Teilkette zu suchen , ist die Verwendung positionFunktion anstelle von likeAusdruck, die Flucht erfordert %, _und ein Escape - Zeichen ( \Standardeinstellung):

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

Dies ist der richtige Weg, dies zu tun. Niemand sollte die hackigen Regex-Ansätze verwenden.
khol

LIKEund ILIKEkann ginIndizes verwenden. positionkann nicht.
Eugene Pakhomov

13

Neben der Lösung mit 'aaaaaaaa' LIKE '%' || tag_name || '%'gibt es position(umgekehrte Reihenfolge der Argumente) und strpos.

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

Abgesehen davon, was effizienter ist (LIKE sieht weniger effizient aus, aber ein Index kann die Dinge ändern), gibt es ein sehr kleines Problem mit LIKE: tag_name sollte natürlich nicht enthalten %und insbesondere _(Platzhalter mit einem Zeichen ), um keine falsch positiven Ergebnisse zu liefern.


2
Ich musste strpos durch position ersetzen, da strpos für mich immer 0
zurückgab

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

tag_name sollte in Anführungszeichen stehen, sonst wird ein Fehler ausgegeben, da tag_name nicht vorhanden ist


2
Dies ist genau das Gegenteil der akzeptierten Antwort . Sie verketten als Zeichenfolge, während es eine Spalte sein muss ...
Suraj Rao
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.