Postgres NON in array


96

Sto usando il tipo di array nativo di Postgres e sto cercando di trovare i record in cui l'ID non è negli ID del destinatario dell'array.

Posso trovare dove sono IN:

SELECT COUNT(*) FROM messages WHERE (3 = ANY (recipient_ids))

Ma questo non funziona:

SELECT COUNT(*) FROM messages WHERE (3 != ANY (recipient_ids))
SELECT COUNT(*) FROM messages WHERE (3  = NOT ANY (recipient_ids))

Qual è il modo giusto per testare questa condizione?


fa WHERE 3 NOT IN recipient_idsil lavoro?
Janus Troelsen

1
Nota correlata: come per text[]e int[]array:select not(array[1,2,3] @> array[3]);
Steve Peak

3
Suggerimento: se stai controllando se una nullcolonna è contenuta o meno in un array, dirà sempre no. Mi ci sono voluti circa 20 minuti di debug di diversi metodi di contenimento per giungere alla conclusione che non è possibile verificare se null è contenuto in un array
André Pena

Risposte:



39

Potresti girarlo un po 'e dire "3 non è uguale a tutti gli ID":

where 3 != all (recipient_ids)

Dal bel manuale :

9.21.4. TUTTI (array)

expression operator ALL (array expression)

Il lato destro è un'espressione tra parentesi, che deve restituire un valore di matrice. L'espressione di sinistra viene valutata e confrontata con ogni elemento dell'array utilizzando l' operatore specificato , che deve produrre un risultato booleano. Il risultato di ALLè "vero" se tutti i confronti restituiscono vero (incluso il caso in cui l'array ha zero elementi). Il risultato è "falso" se viene trovato un risultato falso.


questo non spiega davvero perché anynon funziona in questo caso
seanlinsley

Questo dovrebbe essere accettato poiché ha spiegato correttamente il motivo. PS puoi anche trovare anye allsu postgres doc, che dice: " x <> ANY (a,b,c) è equivalente a x <> a OR <> b OR x <> c". ref: postgresqltutorial.com/postgresql-any postgresqltutorial.com/postgresql-all
Tyler Temp

19

Aumentare le ALL/ANYrisposte

Preferisco tutte le soluzioni che utilizzano allo anyper ottenere il risultato, apprezzando le note aggiuntive (es. Sui NULL ). Come ulteriore aumento, ecco un modo per pensare a quegli operatori.

Puoi considerarli come operatori di cortocircuito :

  • all(array)passa attraverso tutti i valori nell'array, confrontandoli con il valore di riferimento utilizzando l'operatore fornito. Non appena si ottiene un confronto false, il processo termina con falso, altrimenti vero. (Paragonabile al cortocircuito logico and.)
  • any(array)passa attraverso tutti i valori nell'array, confrontandoli con il valore di riferimento utilizzando l'operatore fornito. Non appena si ottiene un confronto true, il processo termina con vero, altrimenti falso. (Paragonabile al cortocircuito logico or.)

Questo è il motivo per cui 3 <> any('{1,2,3}')non produce il risultato desiderato: il processo confronta 3 con 1 per la disuguaglianza, che è vero, e restituisce immediatamente vero. Un singolo valore nella matrice diverso da 3 è sufficiente per rendere vera l'intera condizione. Il 3 nell'ultima posizione dell'array è prob. mai usato.

3 <> all('{1,2,3}')d'altra parte si assicura che tutti i valori non siano uguali 3. Eseguirà tutti i confronti che restituiscono true fino a un elemento che restituisce false (l'ultimo in questo caso), per restituire false come risultato complessivo. Questo è ciò che vuole l'OP.


12

not (3 = any(recipient_ids))?


Grazie, stavo usando 3 <> ANY(ARRAY[1,2,3,4]). Avrebbe dovuto funzionare in questo modo: \
yeyo

11

un aggiornamento:

a partire da postgres 9.3,

è possibile utilizzare NOTin tandem con l ' @> (operatore contiene) per ottenere anche questo.

IE.

SELECT COUNT(*) FROM "messages" WHERE NOT recipient_ids @> ARRAY[3];


11

Attenzione ai NULL

Entrambi ALL:

(some_value != ALL(some_array))

E ANY:

NOT (some_value = ANY(some_array))

Funzionerebbe finché some_arraynon è nullo. Se l'array potrebbe essere nullo, devi tenerne conto con coalesce (), ad es

(some_value != ALL(coalesce(some_array, array[]::int[])))

O

NOT (some_value = ANY(coalesce(some_array, array[]::int[])))

Dai documenti :

Se l'espressione di matrice restituisce una matrice nulla, il risultato di ANY sarà nullo

Se l'espressione di matrice restituisce una matrice nulla, il risultato di ALL sarà nullo


3

Notare che gli operatori ANY / ALL non funzioneranno con gli indici di array. Se gli indici sono in mente:

SELECT COUNT(*) FROM "messages" WHERE 3 && recipient_ids

e il negativo:

SELECT COUNT(*) FROM "messages" WHERE NOT (3 && recipient_ids)

È quindi possibile creare un indice come:

CREATE INDEX recipient_ids_idx on tableName USING GIN(recipient_ids)

A differenza di altre risposte, questa risposta utilizza effettivamente l'operatore di sovrapposizione degli array PostgreSQL. &&
Soffitto Gecko

6
Non funzionerà come scritto. Gli operatori di array come && e @> richiedono che entrambi gli elementi siano array, il che 3 non lo è. Affinché questo al lavoro, la query avrebbe bisogno di essere scritto come: SELECT COUNT(*) FROM "messages" WHERE ARRAY[3] && recipient_ids.
Dologan
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.