Postgresql SELEZIONA se la stringa contiene


105

Quindi ho un nel mio Postgresql:

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

Per semplificare il mio problema, quello che voglio fare è SELEZIONARE "id" da TAG_TABLE quando una stringa "aaaaaaaa" contiene "tag_name". Quindi, idealmente, dovrebbe restituire solo "1", che è l'ID del nome del tag "aaa"

Questo è quello che sto facendo finora:

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

Ma ovviamente, questo non funziona, poiché postgres pensa che '% tag_name%' significhi un pattern contenente la sottostringa 'tag_name' invece del valore effettivo dei dati sotto quella colonna.

Come faccio a passare il tag_name al pattern ??

Risposte:


131

Dovresti usare 'tag_name' fuori dalle virgolette; quindi viene interpretato come un campo del record. Concatena usando "||" con i segni di percentuale letterali:

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

5
cosa succede quando tag_name è "; drop table TAG_TABLE; --"?
Denis de Bernardy

24
@ Denis: non succede niente. Non si ottiene alcuna riga, perché la WHEREclausola restituisce FALSE. L'istruzione non è dinamica, vengono concatenati solo i valori, nessuna possibilità di iniezione SQL.
Erwin Brandstetter

1
l'ordine di aaaa e tag_name non dovrebbe essere invertito? voglio dire che dovresti mettere un nome di colonna dopo dove
user151496

@ user151496 No perché il pattern deve essere posizionato sul lato destro della LIKEparola chiave.
jpmc26

4
Fai attenzione che l'utilizzo di variabili in un LIKEmodello potrebbe avere conseguenze indesiderate quando tali variabili contengono trattini bassi (_) o caratteri percentuali (%). Potrebbe essere necessario sfuggire questi caratteri, ad esempio con questa funzione: CREATE OR REPLACE FUNCTION quote_for_like(text) RETURNS text LANGUAGE SQL IMMUTABLE AS $$ SELECT regexp_replace($1, '([\%_])', '\\\1', 'g'); $$;(dall'utente MatheusOl dal canale #postgresql IRC su Freenode).
Martin von Wittich

46

Personalmente preferisco la sintassi più semplice dell'operatore ~.

SELECT id FROM TAG_TABLE WHERE 'aaaaaaaa' ~ tag_name;

Vale la pena leggere Differenza tra LIKE e ~ in Postgres per capire la differenza. "


2
Funziona solo quando tag_nameè un REGEX corretto. Piuttosto rischioso.
Jakub Fedyczak

@JakubFedyczak per abbinare il nome tag letterale che puoi usare ***=che è menzionato in postgresql.org/docs/current/static/functions-matching.html . Tuttavia ho riscontrato che è troppo più lento rispetto alle soluzioni strpos/ position.
phunehehe

27

Un modo corretto di cercare una stringa è quello di utilizzare positionla funzione al posto di likeespressione, che richiede la fuga %, _e un carattere di escape ( \per impostazione predefinita):

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

Questo è il modo giusto per farlo. Nessuno dovrebbe usare gli approcci regex hacky.
khol

LIKEe ILIKEpuò utilizzare ginindici. positionnon può.
Eugene Pakhomov il

14

Oltre alla soluzione con 'aaaaaaaa' LIKE '%' || tag_name || '%'ci sono position(ordine inverso degli argomenti) e strpos.

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

Oltre a ciò che è più efficiente (LIKE sembra meno efficiente, ma un indice potrebbe cambiare le cose), c'è un problema molto minore con LIKE: tag_name ovviamente non dovrebbe contenere %e soprattutto _(carattere jolly singolo), per non fornire falsi positivi.


2
Ho dovuto sostituire strpos con position, poiché strpos restituiva sempre 0 per me
jcf

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

tag_name dovrebbe essere tra virgolette altrimenti darà un errore in quanto tag_name non esiste


2
Questo è esattamente l'opposto della risposta accettata . Stai concatenando come stringa mentre deve essere una colonna ...
Suraj Rao
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.