Postgresql SELECT si la chaîne contient

105

J'ai donc un dans mon Postgresql:

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

Pour simplifier mon problème, ce que je veux faire est de SELECT 'id' dans TAG_TABLE lorsqu'une chaîne "aaaaaaaa" contient le "tag_name". Donc, idéalement, il ne devrait renvoyer que "1", qui est l'ID du nom de balise 'aaa'

C'est ce que je fais jusqu'à présent:

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

Mais évidemment, cela ne fonctionne pas, puisque le postgres pense que «% tag_name%» signifie un modèle contenant la sous-chaîne «tag_name» au lieu de la valeur réelle des données sous cette colonne.

Comment passer le tag_name au motif ??

user2436815
la source

Réponses:

131

Vous devez utiliser «nom_tiquette» en dehors des guillemets; puis il est interprété comme un champ de l'enregistrement. Concaténer en utilisant "||" avec les signes de pourcentage littéraux:

SELECT id FROM TAG_TABLE WHERE 'aaaaaaaa' LIKE '%' || tag_name || '%';
Frans van Buul
la source
5
que se passe-t-il quand tag_name est "; drop table TAG_TABLE; --"?
Denis de Bernardy
24
@Denis: Rien ne se passe. Vous n'obtenez aucune ligne, car la WHEREclause est évaluée à FALSE. L'instruction n'est pas dynamique, seules les valeurs sont concaténées, aucune chance d'injection SQL.
Erwin Brandstetter
1
ne devrait pas être l'ordre aaaa et tag_name inversé? je veux dire que vous devriez mettre un nom de colonne après où
user151496
@ user151496 Non car le modèle doit se trouver sur le côté droit du LIKEmot - clé.
jpmc26
4
Attention, l'utilisation de variables dans un LIKEmodèle peut avoir des conséquences inattendues lorsque ces variables contiennent des traits de soulignement (_) ou des pourcentages (%). Il peut être nécessaire d'échapper à ces caractères, par exemple avec cette fonction: CREATE OR REPLACE FUNCTION quote_for_like(text) RETURNS text LANGUAGE SQL IMMUTABLE AS $$ SELECT regexp_replace($1, '([\%_])', '\\\1', 'g'); $$;(de l'utilisateur MatheusOl du canal IRC #postgresql sur Freenode).
Martin von Wittich
46

Personnellement, je préfère la syntaxe plus simple de l'opérateur ~.

SELECT id FROM TAG_TABLE WHERE 'aaaaaaaa' ~ tag_name;

Il vaut la peine de lire Différence entre LIKE et ~ dans Postgres pour comprendre la différence. »

keithhackbarth
la source
2
Cela ne fonctionne que s'il tag_names'agit d'un REGEX approprié. Assez risqué.
Jakub Fedyczak
@JakubFedyczak pour correspondre à nom_tiquette littérale que vous pouvez utiliser et ***=qui est mentionné dans postgresql.org/docs/current/static/functions-matching.html . Cependant, j'ai trouvé que c'était beaucoup plus lent que les strpos/ positionsolutions.
phunehehe
27

Une bonne façon de rechercher une sous-chaîne est d'utiliser une positionfonction au lieu d'une likeexpression, qui nécessite un échappement %, _et un caractère d'échappement ( \par défaut):

SELECT id FROM TAG_TABLE WHERE position(tag_name in 'aaaaaaaaaaa')>0;
Tometzky
la source
C'est la bonne manière de procéder. Personne ne devrait utiliser les approches hacky regex.
khol le
LIKEet ILIKEpeut utiliser des ginindices. positionne peux pas.
Eugene Pakhomov
14

En plus de la solution avec, 'aaaaaaaa' LIKE '%' || tag_name || '%'il y a position(ordre inverse des args) et strpos.

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

Outre ce qui est plus efficace (LIKE semble moins efficace, mais un index peut changer les choses), il y a un problème très mineur avec LIKE: tag_name bien sûr ne doit pas contenir %et surtout _(caractère générique unique), pour ne pas donner de faux positifs.

Joop Eggen
la source
2
J'ai dû remplacer les strpos par la position, car les strpos renvoyaient toujours 0 pour moi
jcf
-2
SELECT id FROM TAG_TABLE WHERE 'aaaaaaaa' LIKE '%' || "tag_name" || '%';

tag_name devrait être entre guillemets sinon cela donnera une erreur car tag_name n'existe pas

Shweta Verma
la source
2
C'est exactement le contraire de la réponse acceptée . Vous concaténez en tant que chaîne alors qu'il doit s'agir d'une colonne ...
Suraj Rao