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.