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?

user2436815
quelle

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 || '%';
Frans van Buul
quelle
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. `

keithhackbarth
quelle
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;
Tometzky
quelle
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.

Joop Eggen
quelle
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

Shweta Verma
quelle
2
Dies ist genau das Gegenteil der akzeptierten Antwort . Sie verketten als Zeichenfolge, während es eine Spalte sein muss ...
Suraj Rao