Verifique se o valor existe na matriz do Postgres

196

Usando o Postgres 9.0, preciso de uma maneira de testar se existe um valor em uma determinada matriz. Até agora, eu vim com algo assim:

select '{1,2,3}'::int[] @> (ARRAY[]::int[] || value_variable::int)

Mas continuo pensando que deveria haver uma maneira mais simples de fazer isso, simplesmente não consigo ver. Isso parece melhor:

select '{1,2,3}'::int[] @> ARRAY[value_variable::int]

Eu acredito que será suficiente. Mas se você tiver outras maneiras de fazê-lo, compartilhe!

Mike Starov
fonte

Respostas:

323

Mais simples com a ANYconstrução:

SELECT value_variable = ANY ('{1,2,3}'::int[])

O operando à direita de ANY(entre parênteses) pode ser um conjunto (resultado de uma subconsulta, por exemplo) ou uma matriz . Existem várias maneiras de usá-lo:

Importante diferença: (operadores de array <@, @>, &&. Et ai) esperar matriz tipos como operandos e GIN apoio ou os índices de GIST na distribuição padrão do PostgreSQL, enquanto a ANYconstrução de espera um elemento tipo como operando à esquerda e não suporta estes índices. Exemplo:

Nada disso funciona para NULLelementos. Para testar NULL:

Erwin Brandstetter
fonte
Obrigado. Deve ter pulado essa parte do manual. Isso funciona muito bem. Tem um efeito colateral da fundição automática. Ex: SELECT 1 :: smallint = QUALQUER ('{1,2,3}' :: int []) funciona. Apenas certifique-se de colocar ANY () no lado direito da expressão.
Mike Starov
Obrigado pela resposta. Ocorreu um problema em que minha consulta funcionava no local, mas no heroku estava lançando essa mensagem ANY/ALL (array) requires array on right side, o add de ::int[]fez o encanto.
kinduff
where S.employee_id <@ ANY ('"+ employeeIDsArray +"' :: int []) Isso retorna PSQLException: ERROR: valor de dimensão ausente
Ramprasad
3
Embora essa seja uma questão de dinossauro nos anos da Internet, pessoas lentas como eu devem ser informadas de que 'something' = ANY(some_array)também podem ser usadas em uma WHEREcláusula. Por razões conhecidas apenas pela Crom, passei os últimos quatro anos pensando que não poderia usar comparadores de matriz em WHEREcláusulas. Esses dias se foram agora. (Eu caí na minha cabeça quando criança, então talvez seja só eu).
GT.
1
@GT .: A essência: qualquer boolean expressão funciona na WHEREcláusula - Crom disposto.
Erwin Brandstetter
90

Cuidado com a armadilha em que entrei: Ao verificar se determinado valor não está presente em uma matriz, você não deve fazer:

SELECT value_variable != ANY('{1,2,3}'::int[])

mas use

SELECT value_variable != ALL('{1,2,3}'::int[])

em vez de.

Murison
fonte
2
Tipo de duplo negativo; observe o uso de ALLvsANY
vol7ron 13/11/2013
43
SELECT NOT value_variable = ANY('{1,2,3}'::int[])pode ser mais legível
Ondřej Bouda
28

mas se você tiver outras maneiras de fazer isso, compartilhe.

Você pode comparar duas matrizes. Se algum dos valores na matriz esquerda se sobrepuser aos valores da matriz direita, ele retorna true. É meio bobo, mas funciona.

SELECT '{1}'   && '{1,2,3}'::int[];  -- true
SELECT '{1,4}' && '{1,2,3}'::int[];  -- true
SELECT '{4}'   && '{1,2,3}'::int[];  -- false
  • Na primeira e na segunda consulta, o valor 1está na matriz correta
  • Observe que a segunda consulta é true, mesmo que o valor 4não esteja contido na matriz correta
  • Para a terceira consulta, nenhum valor na matriz esquerda (ou seja 4) está na matriz direita, portanto, ele retornafalse
vol7ron
fonte
como posso procurar uma coluna de outra tabela para ter um valor na matriz? por exemplo, selecione * das cervejas em que style_id (selecione preferências dos usuários em que id = 1) limita 1; style_id é um tipo de dados inteiro; preferências é inteiro [] Eu recebo este erro ERRO: operador não existe: número inteiro = número inteiro [] LINHA 1: selecione * das cervejas em que style_id está (selecione preferências f ... ^ DICA: Nenhum operador corresponde ao nome e tipo de argumento Talvez você precise adicionar conversões explícitas de tipo.
HP
@HP Existem diferentes maneiras de resolver essa pergunta, você deve fazer uma nova pergunta
vol7ron
tem certeza de que não há perguntas? @ vol7ron
HP
@ HP De forma alguma, mas os comentários são para comentários sobre uma pergunta ou resposta; normalmente, para adicionar mais informações ou solicitar mais informações que não foram abordadas. Você está fazendo uma pergunta que não está relacionada a esta resposta. Eu acho que você vai ter mais sorte, pedindo a sua pergunta como um novo post, não no comentário;)
vol7ron
@ HP, se você não publicou sua pergunta, pode ver aqui: sqlfiddle.com/#!15/144cd/3 para obter um exemplo do que você precisa fazer - seu problema é diferente porque você precisa desnaturar sua matriz.
vol7ron
4

unnesttambém pode ser usado. Ele expande a matriz para um conjunto de linhas e, em seguida, simplesmente verificar se um valor existe ou não é tão simples quanto usar INor NOT IN.

por exemplo

  1. id => uuid

  2. exception_list_ids => uuid []

select * from table where id NOT IN (select unnest(exception_list_ids) from table2)

pg2286
fonte
Sim. Observe que, nos meus planos de consulta, SELECT UNNEST não é tão bom quanto = ANY. Eu recomendo verificar os planos de consulta para ver se você consegue o que deseja / espera.
precisa
3

Ao procurar a existência de um elemento em uma matriz, é necessária a conversão adequada para passar o analisador SQL do postgres. Aqui está um exemplo de consulta usando array contém o operador na cláusula join:

Para simplificar, listo apenas a parte relevante:

table1 other_name text[]; -- is an array of text

A parte de junção do SQL mostrada

from table1 t1 join table2 t2 on t1.other_name::text[] @> ARRAY[t2.panel::text]

O seguinte também funciona

on t2.panel = ANY(t1.other_name)

Estou apenas supondo que a conversão extra seja necessária porque a análise não precisa buscar a definição da tabela para descobrir o tipo exato da coluna. Outros, por favor, comente sobre isso.

Kemin Zhou
fonte
0

Oi, isso funciona bem para mim, talvez útil para alguém

selecione * da sua tabela onde array_column :: text é semelhante a ANY (ARRAY ['% text_to_search%' :: text]);

Dave Kraczo
fonte