Postgresql SELECT si la cadena contiene


105

Entonces tengo un en mi Postgresql:

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

Para simplificar mi problema, lo que quiero hacer es SELECCIONAR 'id' de TAG_TABLE cuando una cadena "aaaaaaaa" contiene el 'tag_name'. Entonces, idealmente, solo debería devolver "1", que es el ID para el nombre de etiqueta "aaa"

Esto es lo que estoy haciendo hasta ahora:

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

Pero obviamente, esto no funciona, ya que postgres piensa que '% tag_name%' significa un patrón que contiene la subcadena 'tag_name' en lugar del valor de datos real en esa columna.

¿Cómo paso el tag_name al patrón?

Respuestas:


131

Debe usar 'tag_name' fuera de las comillas; luego se interpreta como un campo del registro. Concatenar usando '||' con los signos de porcentaje literal:

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

5
¿Qué pasa cuando tag_name es "; drop table TAG_TABLE; --"?
Denis de Bernardy

24
@Denis: No pasa nada. No obtiene ninguna fila, porque la WHEREcláusula se evalúa como FALSE. La declaración no es dinámica, solo los valores están concatenados, no hay posibilidad de inyección SQL.
Erwin Brandstetter

1
¿No debería invertirse el orden de aaaa y tag_name?
Quiero

@ user151496 No porque el patrón debe ir en el lado derecho de la LIKEpalabra clave.
jpmc26

4
Tenga en cuenta que el uso de variables en un LIKEpatrón puede tener consecuencias no deseadas cuando esas variables contienen guiones bajos (_) o caracteres de porcentaje (%). Puede ser necesario escapar de estos caracteres, por ejemplo con esta función: CREATE OR REPLACE FUNCTION quote_for_like(text) RETURNS text LANGUAGE SQL IMMUTABLE AS $$ SELECT regexp_replace($1, '([\%_])', '\\\1', 'g'); $$;(del usuario MatheusOl del canal de IRC #postgresql en Freenode).
Martin von Wittich

46

Personalmente prefiero la sintaxis más simple del operador ~.

SELECT id FROM TAG_TABLE WHERE 'aaaaaaaa' ~ tag_name;

Vale la pena leer Diferencia entre LIKE y ~ en Postgres para comprender la diferencia. '


2
Esto funciona solo cuando tag_namees un REGEX adecuado. Bastante arriesgado.
Jakub Fedyczak

@JakubFedyczak para que coincida con el tag_name literal que puede usar y ***=que se menciona en postgresql.org/docs/current/static/functions-matching.html . Sin embargo, he descubierto que es mucho más lento en comparación con strpos/ positionsolutions.
phunehehe

27

Una forma adecuada de buscar una subcadena es usar la positionfunción en lugar de la likeexpresión, lo que requiere escapar %, _y un carácter de escape ( \por defecto):

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

Esta es la forma correcta de hacer esto. Nadie debería usar los enfoques hacky regex.
khol

LIKEy ILIKEpuede utilizar giníndices. positionno puedo.
Eugene Pakhomov

14

Además de la solución con 'aaaaaaaa' LIKE '%' || tag_name || '%'hay position(orden inverso de argumentos) y strpos.

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

Además de lo que es más eficiente (LIKE parece menos eficiente, pero un índice puede cambiar las cosas), hay un problema menor con LIKE: tag_name por supuesto no debería contener %y especialmente _(comodín de carácter único), para no dar falsos positivos.


2
Tuve que reemplazar strpos con position, ya que strpos siempre devolvía 0 para mí
jcf

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

tag_name debe estar entre comillas, de lo contrario, dará un error ya que el nombre de la etiqueta no existe


2
Esto es exactamente lo contrario de la respuesta aceptada . Estás concatenando como una cadena mientras que necesita ser una columna ...
Suraj Rao
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.