Operador IN vs ANY no PostgreSQL

Respostas:

158

(Nem INnem ANYé um "operador". Uma "construção" ou "elemento de sintaxe".)

Logicamente , citando o manual :

INé equivalente a = ANY.

Mas existem duas variantes de sintaxe de INe duas variantes de ANY. Detalhes:

IN pegar um conjunto é equivalente a = ANYpegar um conjunto , conforme demonstrado aqui:

Mas a segunda variante de cada uma não é equivalente à outra. A segunda variante da ANYconstrução leva um array (deve ser um tipo de array real), enquanto a segunda variante de INleva uma lista de valores separados por vírgulas . Isso leva a diferentes restrições na passagem de valores e também pode levar a diferentes planos de consulta em casos especiais:

ANY é mais versátil

A ANYconstrução é muito mais versátil, pois pode ser combinada com vários operadores, não apenas =. Exemplo:

SELECT 'foo' LIKE ANY('{FOO,bar,%oo%}');

Para um grande número de valores, fornecer um conjunto de escalas melhor para cada um:

Relacionado:

Inversão / oposto / exclusão

"Encontrar linhas onde idestá na matriz fornecida":

SELECT * FROM tbl WHERE id = ANY (ARRAY[1, 2]);

Inversão: "Encontrar linhas onde nãoid está na matriz":

SELECT * FROM tbl WHERE id <> ALL (ARRAY[1, 2]);
SELECT * FROM tbl WHERE id <> ALL ('{1, 2}');  -- equivalent array literal
SELECT * FROM tbl WHERE NOT (id = ANY ('{1, 2}'));

Todos os três equivalentes. O primeiro com construtor de array , os outros dois com literal de array . O tipo de dados pode ser derivado do contexto de forma inequívoca. Caso contrário, um elenco explícito pode ser necessário, como '{1,2}'::int[].

As linhas com id IS NULLnão passam em nenhuma dessas expressões. Para incluir NULLvalores adicionais:

SELECT * FROM tbl WHERE (id = ANY ('{1, 2}')) IS NOT TRUE;
Erwin Brandstetter
fonte
4
Seria bom esclarecer explicitamente que os resultados das segundas variantes serão sempre os mesmos. Tenho 99% de certeza de que esse é o caso, mas a resposta não parece afirmar isso. O que significa que SELECT * from mytable where id in (1, 2, 3)sempre resultará nas mesmas linhas que SELECT * from mytable where id = ANY('{1, 2, 3}'), mesmo que possam ter planos de consulta diferentes.
KPD
1
ANY não pode ser combinado com o !=operador. Não acho que esteja documentado, mas select * from foo where id != ANY (ARRAY[1, 2])não é o mesmo que select * from foo where id NOT IN (1, 2). Por outro lado, select * from foo where NOT (id = ANY (ARRAY[1, 2]))funciona como esperado.
qris
1
@qris: ANYpode ser combinado com o !=operador. Mas há mais do que isso. Eu adicionei um capítulo acima. (Observe que <>é o operador no SQL padrão - embora também !=seja aceito no Postgres.)
Erwin Brandstetter
Como funciona a última versão que inclui NULLvalores? Funcionaria WHERE id = ANY (ARRAY[1, 2]) OR id IS NULL;tão bem?
dvtan
1
@dvtan: (id = ...) IS NOT TRUEfunciona porque id = ...só avalia TRUEse há uma correspondência real. Resultados FALSEou NULLpassar no nosso teste. Consulte: stackoverflow.com/a/23767625/939860 . Sua expressão adicionada testa para outra coisa. Isso seria equivalenteWHERE id <> ALL (ARRAY[1, 2]) OR id IS NULL;
Erwin Brandstetter
3

Existem dois pontos óbvios, bem como os pontos na outra resposta:

  • Eles são exatamente equivalentes ao usar subconsultas:

    SELECT * FROM table
    WHERE column IN(subquery);
    
    SELECT * FROM table
    WHERE column = ANY(subquery);

Por outro lado:

  • Apenas o INoperador permite uma lista simples:

    SELECT * FROM table
    WHERE column IN(… ,  , …);

Presumir que eles são exatamente os mesmos me surpreendeu várias vezes quando esqueci que ANYnão funciona com listas.

Manngo
fonte