Controlla se esiste un valore nell'array Postgres


196

Usando Postgres 9.0, ho bisogno di un modo per verificare se esiste un valore in un determinato array. Finora mi è venuto in mente qualcosa del genere:

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

Ma continuo a pensare che dovrebbe esserci un modo più semplice per farlo, non riesco proprio a vederlo. Questo sembra meglio:

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

Credo che basterà. Ma se hai altri modi per farlo, ti preghiamo di condividere!

Risposte:


323

Più semplice con il ANYcostrutto:

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

L'operando di destra ANY(tra parentesi) può essere un set (risultato di una sottoquery, per esempio) o un array . Esistono diversi modi per usarlo:

Importante differenza: (Array operators <@, @>, &&et al.) Durante matrice tipi come operandi e supporto GIN o indici GiST nella distribuzione standard di PostgreSQL, mentre il ANYcostrutto prevede un elemento di tipo sinistro operando e non supporta questi indici. Esempio:

Niente di tutto ciò funziona per gli NULLelementi. Per verificare NULL:


Grazie. Deve aver saltato quella parte del manuale. Funziona benissimo. Ha un effetto collaterale del lancio automatico. Es .: SELECT 1 :: smallint = ANY ('{1,2,3}' :: int []) funziona. Assicurati di mettere ANY () sul lato destro dell'espressione.
Mike Starov,

Grazie per la risposta. Ho avuto un problema a causa del quale la mia query funzionava su local, ma in heroku stava lanciando questo messaggio ANY/ALL (array) requires array on right side, l'aggiunta di ha ::int[]fatto il fascino.
kinduff

dove S.employee_id <@ ANY ('"+ employeeIDsArray +"' :: int []) Questo restituisce PSQLException: ERRORE: valore dimensione mancante
Ramprasad

3
Sebbene questa sia una domanda sui dinosauri negli anni di Internet, le persone lente come me dovrebbero essere consapevoli che 'something' = ANY(some_array)possono essere utilizzate anche in una WHEREclausola. Per motivi noti solo a Crom, ho trascorso gli ultimi quattro anni a pensare di non poter usare i comparatori di array nelle WHEREclausole. Quei giorni sono passati adesso. (Sono stato lasciato cadere in testa da bambino, quindi forse sono solo io).
GT.

1
@GT .: Il senso dell'essenziale: qualsiasi boolean espressione funziona nella WHEREclausola - Crom disposto.
Erwin Brandstetter,

90

Fai attenzione alla trappola in cui mi sono imbattuto: quando controlli se un certo valore non è presente in un array, non dovresti fare:

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

ma usa

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

anziché.


2
Tipo di doppio negativo; notate il suo uso di ALLvsANY
vol7ron il

43
SELECT NOT value_variable = ANY('{1,2,3}'::int[])potrebbe essere più leggibile
Ondřej Bouda

28

ma se hai altri modi per farlo, ti preghiamo di condividere.

È possibile confrontare due matrici. Se uno qualsiasi dei valori nella matrice sinistra si sovrappone ai valori nella matrice destra, allora restituisce true. È un po 'hacker, ma funziona.

SELECT '{1}'   && '{1,2,3}'::int[];  -- true
SELECT '{1,4}' && '{1,2,3}'::int[];  -- true
SELECT '{4}'   && '{1,2,3}'::int[];  -- false
  • Nella prima e nella seconda query, il valore 1è nella matrice corretta
  • Si noti che la seconda query è true, anche se il valore 4non è contenuto nell'array giusto
  • Per la terza query, nessun valore nell'array di sinistra (ovvero, 4) è nell'array di destra, quindi restituiscefalse

come posso cercare una colonna da un'altra tabella per avere un valore nella matrice? ad es. selezionare * dalle birre in cui style_id (seleziona le preferenze degli utenti dove id = 1) limita 1; style_id è un tipo di dati intero; le preferenze sono numeri interi [] Ottengo questo errore ERRORE: l'operatore non esiste: numero intero = numero intero [] LINEA 1: seleziona * da birre in cui style_id (seleziona preferenze f ... ^ SUGGERIMENTO: nessun operatore corrisponde al nome e al tipo di argomento indicati (s). Potrebbe essere necessario aggiungere cast di tipo esplicito
HP,

@HP Ci sono diversi modi per risolvere quella domanda, dovresti fare una nuova domanda
vol7ron,

sei sicuro che non ci siano domande esistenti? @ vol7ron
HP,

@HP Niente affatto, ma i commenti sono per commenti riguardanti una domanda o una risposta; in genere per aggiungere più informazioni o sollecitare ulteriori informazioni che non sono state indirizzate. Stai ponendo una domanda non correlata a questa risposta. Penso che avrai più fortuna ponendo la tua domanda come nuovo post, non nel commento;)
vol7ron

@HP se non hai pubblicato la tua domanda, puoi vedere qui: sqlfiddle.com/#!15/144cd/3 per un esempio di ciò che devi fare: il tuo problema è diverso perché devi annullare l'assestamento dell'array.
vol7ron,

4

unnestpuò anche essere usato. Espande l'array in un set di righe e quindi semplicemente controllare che un valore esista o meno è semplice come usare INo NOT IN.

per esempio

  1. id => uuid

  2. exception_list_ids => uuid []

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


Sì. Nota che nei miei piani di query SELECT UNNEST non è buono come = ANY. Consiglio di controllare i piani di query per vedere se ottieni quello che vuoi / ti aspetti.
Rob Bygrave,

3

Quando si cerca l'esistenza di un elemento in un array, è richiesto il casting corretto per passare il parser SQL di postgres. Ecco una query di esempio che utilizza array contiene l'operatore nella clausola join:

Per semplicità elenco solo la parte pertinente:

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

Viene visualizzata la parte di join di SQL

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

Di seguito funziona anche

on t2.panel = ANY(t1.other_name)

Sto solo supponendo che il casting extra sia necessario perché l'analisi non deve recuperare la definizione della tabella per capire il tipo esatto della colonna. Altri, per favore, commentate questo.


1

Ciao, quello funziona bene per me, forse utile per qualcuno

seleziona * da your_table dove array_column :: text ilike ANY (ARRAY ['% text_to_search%' :: text]);

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.