Jenis data kolom people
adalah json
, seperti hasil json_array_elements(people)
. Dan tidak ada operator kesetaraan ( =
) untuk tipe data json
. Jadi Anda juga tidak bisa menjalankannya GROUP BY
. Lebih:
jsonb
memiliki operator kesetaraan, jadi "solusi" dalam jawaban Anda adalah untuk jsonb
menggunakan dan menggunakan yang setara jsonb_array_elements()
. Para pemain menambah biaya:
jsonb_array_elements(people::jsonb)
Sejak Postgres 9.4 kami juga telah json_array_elements_text(json)
mengembalikan elemen array sebagai text
. Terkait:
Begitu:
SELECT p.name, count(*) AS c
FROM band b, json_array_elements_text(b.people) p(name)
GROUP BY p.name;
Tampaknya lebih mudah untuk mendapatkan nama text
daripada jsonb
objek (dikutip ganda dalam representasi teks) dan "output yang Anda inginkan" menunjukkan Anda ingin / perlu text
dalam hasil untuk memulai.
GROUP BY
pada text
data juga lebih murah daripada pada jsonb
, jadi "solusi" alternatif ini harus lebih cepat karena dua alasan. (Uji dengan EXPLAIN (ANALYZE, TIMING OFF)
.)
Sebagai catatan, tidak ada yang salah dengan jawaban asli Anda . Koma ( ,
) sama "benar" dengan CROSS JOIN LATERAL
. Telah didefinisikan sebelumnya dalam standar SQL tidak membuatnya lebih rendah. Lihat:
Juga tidak lebih portabel untuk RDBMS lain, dan karena jsonb_array_elements()
atau json_array_elements_text()
tidak portabel untuk RDBMS lain untuk memulai, itu juga tidak relevan. Permintaan singkat tidak menjadi lebih jelas dengan CROSS JOIN LATERAL
IMO, tetapi bit terakhir hanya pendapat pribadi saya.
Saya menggunakan tabel dan kolom yang lebih eksplisit alias p(name)
dan referensi yang memenuhi syarat tabel p.name
untuk mempertahankan terhadap kemungkinan nama duplikat. name
adalah kata yang umum, mungkin juga muncul sebagai nama kolom pada tabel di bawahnya band
, yang dalam hal ini akan diselesaikan secara diam-diam band.name
. Bentuk sederhana json_array_elements_text(people) name
hanya melampirkan alias tabel , nama kolom masih value
, seperti yang dikembalikan dari fungsi. Tetapi name
memutuskan untuk menggunakan satu kolom value
saat digunakan dalam SELECT
daftar. Itu terjadi untuk bekerja seperti yang diharapkan . Tetapi nama kolom yang benar name
(jika band.name
ada) akan mengikat terlebih dahulu. Meskipun itu tidak akan menggigit pada contoh yang diberikan, itu bisa menjadi senjata kaki yang dimuat dalam kasus lain.
Jangan gunakan "nama" generik sebagai pengidentifikasi untuk memulai. Mungkin itu hanya untuk test case sederhana.
Jika kolom people
bisa menampung apa pun selain array JSON biasa , kueri akan memicu pengecualian. Jika Anda tidak dapat menjamin integritas data, Anda mungkin ingin bertahan dengan 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
Tidak termasuk melanggar baris dari kueri.
Terkait: