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 ??

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 || '%';

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. »


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;

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.


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


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
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.