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

user2436815
fonte

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 || '%';
Frans van Buul
fonte
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. `

Keithhackbarth
fonte
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;
Tometzky
fonte
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 || '%'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.

Joop Eggen
fonte
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

Shweta Verma
fonte
2
Isso é exatamente o oposto da resposta aceita . Você está concatenando como string, mas precisa ser uma coluna ...
Suraj Rao