PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Come utilizzare ANY invece di IN in una clausola WHERE con Rails?

Esistono due varianti di IN espressioni:

  • expression IN (subquery)
  • expression IN (value [, ...])

Allo stesso modo, due varianti con ANY costruire:

  • expression operator ANY (subquery)
  • expression operator ANY (array expression)

Una sottoquery funziona per entrambe le tecniche, ma per la seconda forma di ciascuno, IN si aspetta un elenco di valori (come definito nell'SQL standard) mentre = ANY si aspetta un array .

Quale usare?

ANY è un'aggiunta successiva e più versatile, può essere combinata con qualsiasi operatore binario che restituisca un valore booleano. IN si riduce a un caso speciale di ANY . Infatti, la sua seconda forma viene riscritta internamente:

IN viene riscritto con = ANY
NOT IN viene riscritto con <> ALL

Controlla il EXPLAIN output per qualsiasi query da visualizzare di persona. Questo dimostra due cose:

  • IN non può mai essere più veloce di = ANY .
  • = ANY non sarà sostanzialmente più veloce.

La scelta dovrebbe essere decisa da cosa è più facile fornire :un elenco di valori o un array (possibilmente come array letterale - un singolo valore).

Se gli ID che intendi trasmettere provengono dall'interno del DB in ogni caso, è molto più efficiente selezionarli direttamente (subquery) o integrare la tabella sorgente nella query con un JOIN (come ha commentato @mu).

Per superare un elenco lungo di valori dal tuo cliente e ottieni le migliori performance , usa un array, unnest() e unisciti o forniscilo come espressione di tabella utilizzando VALUES (come ha commentato @PinnyM). Ma nota che un JOIN conserva possibili duplicati nell'array/set fornito mentre IN o = ANY non. Altro:

  • Ottimizzazione di una query Postgres con un IN grande

In presenza di valori NULL, NOT IN è spesso la scelta sbagliata e NOT EXISTS sarebbe giusto (e anche più veloce):

  • Seleziona le righe che non sono presenti in un'altra tabella

Sintassi per = ANY

Per l'espressione di matrice Postgres accetta:

  • un costruttore di array (l'array è costruito da un elenco di valori sul lato Postgres) del modulo:ARRAY[1,2,3]
  • o un letterale array del modulo '{1,2,3}' .

Per evitare cast di tipi non validi, puoi trasmettere in modo esplicito:

ARRAY[1,2,3]::numeric[]
'{1,2,3}'::bigint[]

Correlati:

  • PostgreSQL:problema con il passaggio dell'array alla procedura
  • Come passare un array di tipi personalizzati alla funzione Postgres

Oppure potresti crea una funzione Postgres prendendo un VARIADIC parametro, che prende i singoli argomenti e ne forma una matrice:

  • Passaggio di più valori in un singolo parametro

Come passare l'array da Ruby?

Assumendo id essere integer :

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

Ma mi sto solo dilettando con Ruby. @mu fornisce istruzioni dettagliate in questa risposta correlata:

  • Invio di una matrice di valori a una query sql in ruby?