Postgresql SELECT se string contém


105

Portanto, tenho um em meu Postgresql:

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

Para simplificar meu problema, o que eu quero fazer é SELECT 'id' em TAG_TABLE quando uma string "aaaaaaaa" contém o 'tag_name'. Portanto, o ideal é que ele retorne apenas "1", que é o ID do nome da tag 'aaa'

Isso é o que estou fazendo até agora:

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

Mas, obviamente, isso não funciona, uma vez que o postgres pensa que '% tag_name%' significa um padrão contendo a substring 'tag_name' em vez do valor real dos dados sob essa coluna.

Como faço para passar o tag_name para o padrão ??

Respostas:


131

Você deve usar 'tag_name' fora das aspas; então é interpretado como um campo do registro. Concatene usando '||' com os sinais de porcentagem literais:

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

5
o que acontece quando tag_name é "; drop table TAG_TABLE; --"?
— Denis de Bernardy

24
@Denis: Nada acontece. Você não obtém nenhuma linha, porque a WHEREcláusula avalia para FALSE. A instrução não é dinâmica, apenas os valores são concatenados, sem chance de injeção de SQL.
— Erwin Brandstetter

1
não deveria ser a ordem de aaaa e tag_name invertida? quero dizer que você deve colocar um nome de coluna após onde
— user151496

@ user151496 Não porque o padrão deve ficar no lado direito da LIKEpalavra - chave.
— jpmc26

4
Esteja ciente de que o uso de variáveis ​​em um LIKEpadrão pode ter consequências indesejadas quando essas variáveis ​​contêm sublinhados (_) ou caracteres de porcentagem (%). Pode ser necessário escapar esses caracteres, por exemplo com esta função: CREATE OR REPLACE FUNCTION quote_for_like(text) RETURNS text LANGUAGE SQL IMMUTABLE AS $$ SELECT regexp_replace($1, '([\%_])', '\\\1', 'g'); $$;(do usuário MatheusOl do canal IRC #postgresql em Freenode).
— Martin von Wittich

46

Eu pessoalmente prefiro a sintaxe mais simples do operador ~.

SELECT id FROM TAG_TABLE WHERE 'aaaaaaaa' ~ tag_name;

Vale a pena ler Diferença entre LIKE e ~ no Postgres para entender a diferença. `


2
Isso funciona apenas quando tag_nameé um REGEX adequado. Muito arriscado.
— Jakub Fedyczak

@JakubFedyczak para corresponder ao tag_name literal que você pode usar, o ***=qual é mencionado em postgresql.org/docs/current/static/functions-matching.html . No entanto, descobri que isso é muito mais lento em comparação com as soluções strpos/ position.
— phunehehe

27

Uma maneira adequada de pesquisar uma substring é usar positionfunção em vez de likeexpressão, que requer escape %, _e um caractere de escape ( \por padrão):

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

Esta é a maneira certa de fazer isso. Ninguém deve usar as abordagens de regex do hacky.
— khol 01 de

LIKEe ILIKEpode usar giníndices. positionnão podes.
— Eugene Pakhomov

14

Além da solução com 'aaaaaaaa' LIKE '%' || tag_name || '%'há position(ordem reversa de args) e strpos.

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

Além do que é mais eficiente (LIKE parece menos eficiente, mas um índice pode mudar as coisas), há um problema muito pequeno com LIKE: o tag_name obviamente não deve conter %e, especialmente _(caractere curinga único), para não dar falsos positivos.


2
Tive que substituir strpos por position, pois strpos sempre retornou 0 para mim
— jcf

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

tag_name deve estar entre aspas, caso contrário irá dar um erro porque tag_name não existe


2
Isso é exatamente o oposto da resposta aceita . Você está concatenando como string, mas precisa ser uma coluna ...
— Suraj Rao
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.