PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Como usar ANY em vez de IN em uma cláusula WHERE com Rails?


Existem duas variantes de IN expressões:
  • expression IN (subquery)
  • expression IN (value [, ...])

Da mesma forma, duas variantes com o ANY construir:
  • expression operator ANY (subquery)
  • expression operator ANY (array expression)

Uma subconsulta funciona para qualquer técnica, mas para o segundo forma de cada um, IN espera uma lista de valores (conforme definido no SQL padrão) enquanto = ANY espera uma matriz .

Qual ​​usar?


ANY é uma adição posterior e mais versátil, pode ser combinada com qualquer operador binário retornando um valor booleano. IN reduz a um caso especial de ANY . De fato, sua segunda forma é reescrita internamente:

IN é reescrito com = ANY
NOT IN é reescrito com <> ALL

Verifique o EXPLAIN saída para qualquer consulta para ver por si mesmo. Isso prova duas coisas:
  • IN nunca pode ser mais rápido que = ANY .
  • = ANY não será substancialmente mais rápido.

A escolha deve ser decidida por o que é mais fácil de fornecer :uma lista de valores ou um array (possivelmente como array literal - um único valor).

Se os IDs que você vai passar vierem de dentro do banco de dados de qualquer forma, é muito mais eficiente selecioná-los diretamente (subconsulta) ou integrar a tabela de origem na consulta com um JOIN (como @mu comentou).

Para passar uma lista longa de valores do seu cliente e obtenha o melhor desempenho , use uma matriz, unnest() e juntar, ou fornecê-lo como expressão de tabela usando VALUES (como @PinnyM comentou). Mas observe que um JOIN preserva possíveis duplicações no array fornecido / set enquanto IN ou = ANY não faça. Mais:
  • Otimizando uma consulta Postgres com um grande IN

Na presença de valores NULL, NOT IN geralmente é a escolha errada e NOT EXISTS estaria certo (e mais rápido também):
  • Selecione as linhas que não estão presentes em outra tabela

Sintaxe para = ANY


Para a expressão de array, o Postgres aceita:
  • um construtor de matriz (array é construído a partir de uma lista de valores no lado do Postgres) da forma:ARRAY[1,2,3]
  • ou um literal de matriz da forma '{1,2,3}' .

Para evitar conversões de tipo inválido, você pode converter explicitamente:
ARRAY[1,2,3]::numeric[]
'{1,2,3}'::bigint[]

Relacionado:
  • PostgreSQL:problema ao passar array para procedimento
  • Como passar array de tipo personalizado para a função Postgres

Ou você poderia crie uma função Postgres pegando um VARIADIC parâmetro, que recebe argumentos individuais e forma um array a partir deles:
  • Passando vários valores em um único parâmetro

Como passar o array do Ruby?


Assumindo id para ser integer :
MyModel.where('id = ANY(ARRAY[?]::int[])', ids.map { |i| i})

Mas estou apenas brincando com Ruby. @mu fornece instruções detalhadas nesta resposta relacionada:
  • Enviando array de valores para uma consulta sql em ruby?