Il tipo di dati della colonna people
è json
, come è il risultato di json_array_elements(people)
. E non esiste un operatore di uguaglianza ( =
) per il tipo di dati json
. Quindi non puoi nemmeno eseguirlo GROUP BY
. Di Più:
jsonb
ha un operatore di uguaglianza, quindi la "soluzione alternativa" nella tua risposta è lanciare jsonb
e usare l'equivalente jsonb_array_elements()
. Il cast aggiunge un costo:
jsonb_array_elements(people::jsonb)
Da Postgres 9.4 abbiamo anche json_array_elements_text(json)
restituito elementi array come text
. Relazionato:
Così:
SELECT p.name, count(*) AS c
FROM band b, json_array_elements_text(b.people) p(name)
GROUP BY p.name;
Sembra più conveniente ottenere nomi come text
invece di jsonb
oggetti (tra virgolette doppie nella rappresentazione del testo) e il tuo "output desiderato" indica che vuoi / necessiti text
nel risultato per cominciare.
GROUP BY
sui text
dati è anche più economico che su jsonb
, quindi questa "soluzione alternativa" dovrebbe essere più veloce per due motivi. (Prova con EXPLAIN (ANALYZE, TIMING OFF)
.)
Per la cronaca, non c'era niente di sbagliato nella risposta originale . La virgola ( ,
) è "corretta" come CROSS JOIN LATERAL
. Essere stato definito in precedenza in SQL standard non lo rende inferiore. Vedere:
Né è più portabile su altri RDBMS, e dato che jsonb_array_elements()
o json_array_elements_text()
non sono portabili su altri RDBMS per cominciare, anche questo è irrilevante. La breve query non è più chiara con CROSS JOIN LATERAL
IMO, ma l'ultimo bit è solo la mia opinione personale.
Ho usato l'alias di tabella e colonna più esplicito p(name)
e il riferimento qualificato p.name
per la tabella per difendermi da possibili nomi duplicati. name
è una parola così comune, potrebbe anche apparire come nome di colonna nella tabella sottostante band
, nel qual caso si risolverebbe silenziosamente band.name
. Il modulo semplice json_array_elements_text(people) name
allega solo un alias di tabella , il nome della colonna è fermo value
, come restituito dalla funzione. Ma si name
risolve nella sua singola colonna value
quando viene utilizzato SELECT
nell'elenco. E capita a funzionare come previsto . Ma un vero nome di colonna name
(se band.name
dovesse esistere) si legherà per primo. Anche se questo non morde nell'esempio dato, in altri casi può essere una pistola a pedale carica .
Non utilizzare il "nome" generico come identificatore per cominciare. Forse era solo per il semplice test case.
Se la colonna people
può contenere qualsiasi cosa tranne un semplice array JSON , entrambe le query genererebbero un'eccezione. Se non puoi garantire l'integrità dei dati, potresti voler difendere con json_typeof()
:
SELECT p.name, count(*) AS c
FROM band b, json_array_elements_text(b.people) p(name)
WHERE json_typeof(b.people) = 'array'
GROUP BY 1; -- optional short syntax since you seem to prefer short syntax
Esclude le righe di violazione dalla query.
Relazionato: