Saya memiliki kolom data
yang menyimpan json
dokumen kira-kira seperti ini:
{
"name": "foo",
"tags": ["foo", "bar"]
}
Saya ingin mengubah tags
array bersarang menjadi string bersambung ( foo, bar
). Itu akan dengan mudah dimungkinkan dengan array_to_string()
fungsi dalam teori. Namun, fungsi ini tidak bekerja pada json
array. Jadi saya bertanya-tanya bagaimana cara mengubah json
array ini menjadi Postgres array
?
postgresql
postgresql-9.3
array
json
Christoph
sumber
sumber
json_extract_path_text(your_column, 'tags')
yang Anda cari?Jawaban:
Postgres 9.4 atau lebih baru
Jelas terinspirasi oleh posting ini , Postgres 9.4 menambahkan fungsi yang hilang:
Terima kasih kepada Laurence Rowe untuk patch dan Andrew Dunstan untuk melakukan!
json_array_elements_text(json)
jsonb_array_elements_text(jsonb)
Untuk membatalkan array JSON. Kemudian gunakan
array_agg()
atau konstruktor ARRAY untuk membangun array Postgres darinya. Ataustring_agg()
untuk membanguntext
string .Agregasikan elemen yang tidak diuji per baris dalam
LATERAL
subquery yang berkorelasi. Kemudian pesanan asli dipertahankan dan kami tidak perluORDER BY
,GROUP BY
atau bahkan kunci unik di kueri luar. Lihat:Ganti 'json' dengan 'jsonb' untuk
jsonb
semua kode SQL berikut.Sintaks pendek:
Terkait:
Konstruktor ARRAY dalam subquery berkorelasi:
Terkait:
Perbedaan halus :
null
elemen dipertahankan dalam array yang sebenarnya . Ini tidak mungkin dalam kueri di atas yang menghasilkantext
string, yang tidak bisa berisinull
nilai. The representasi sejati adalah array.Fungsi pembungkus
Untuk penggunaan berulang, untuk membuatnya lebih sederhana, merangkum logika dalam suatu fungsi:
Jadikan sebagai fungsi SQL , sehingga bisa diuraikan dalam kueri yang lebih besar.
Buatlah
IMMUTABLE
(karena memang demikian) untuk menghindari evaluasi berulang dalam permintaan yang lebih besar dan memungkinkannya dalam ekspresi indeks.Panggilan:
db <> biola di sini
Postgres 9.3 atau lebih tua
Gunakan fungsinya
json_array_elements()
. Tapi kami mendapatkan string yang dikutip ganda .Kueri alternatif dengan agregasi dalam kueri luar.
CROSS JOIN
menghapus baris dengan array yang hilang atau kosong. Semoga bermanfaat untuk memproses elemen. Kami membutuhkan kunci unik untuk agregat:Konstruktor ARRAY, masih dengan string yang dikutip:
Catatan yang
null
dikonversi ke nilai teks "null", tidak seperti di atas. Tidak benar, benar-benar berbicara, dan berpotensi ambigu.Orang miskin tidak mengutip dengan
trim()
:Ambil satu baris dari tbl:
String membentuk subquery yang dikorelasikan:
Konstruktor ARRAY:
Biola SQL Asli (kedaluwarsa) .
db <> biola di sini.
Terkait:
Catatan (kedaluwarsa sejak pg 9.4)
Kita akan membutuhkan
json_array_elements_text(json)
, kembaranjson_array_elements(json)
untuk mengembalikantext
nilai yang tepat dari array JSON. Tapi itu tampaknya hilang dari gudang fungsi JSON yang disediakan . Atau fungsi lain untuk mengekstraksitext
nilai dariJSON
nilai skalar . Sepertinya aku juga kehilangan yang itu.Jadi saya berimprovisasi dengan
trim()
, tetapi itu akan gagal untuk kasus-kasus non-sepele ...sumber
to_jsonb()
untuk array-> konversi jsonb.SELECT ARRAY(SELECT json_array_elements_text(_js))
benar-benar menjamin bahwa pemesanan array dipertahankan? Tidakkah optimizer diizinkan mengubah urutan baris yang keluar dari json_array_elements_text secara teoritis?PG 9.4+
Jawaban yang diterima pasti apa yang Anda butuhkan, tetapi demi kesederhanaan di sini adalah penolong yang saya gunakan untuk ini:
Maka lakukan saja:
sumber
Pertanyaan ini ditanyakan pada milis PostgreSQL dan saya menemukan cara ini untuk mengkonversi teks JSON menjadi tipe teks PostgreSQL melalui operator ekstraksi bidang JSON:
Pada dasarnya itu mengubah nilai menjadi array elemen tunggal dan kemudian meminta elemen pertama.
Pendekatan lain adalah menggunakan operator ini untuk mengekstraksi semua bidang satu per satu. Tetapi untuk array besar ini kemungkinan lebih lambat, karena perlu mengurai seluruh string JSON untuk setiap elemen array, yang mengarah ke kompleksitas O (n ^ 2).
sumber
Saya sudah menguji beberapa opsi. Ini permintaan favorit saya. Misalkan kita memiliki tabel yang berisi bidang id dan json. Bidang json berisi array, yang ingin kita ubah menjadi array pg.
Ini bekerja di mana saja dan lebih cepat daripada yang lain, tetapi terlihat kasar)
Pertama array json dilemparkan sebagai teks, dan kemudian kita hanya mengubah tanda kurung siku ke tanda kurung. Akhirnya teks tersebut dicasting sebagai larik tipe yang diperlukan.
dan jika Anda lebih suka array teks []
sumber
SELECT TRANSLATE('{"name": "foo", "tags": ["foo", "bar"]}'::jsonb::text, '[]','{}')::INT[]; ERROR: malformed array literal: "{"name": "foo", "tags": {"foo", "bar"}}"
Saya pikir Anda harus menambahkan beberapa penjelasan tentang bagaimana ini seharusnya bekerja.SELECT translate('["foo", "bar"]'::jsonb::text, '[]','{}')::INT[]; ERROR: invalid input syntax for integer: "foo"
Ini tidak begitu tahan bom ...Beberapa fungsi ini, diambil dari jawaban untuk pertanyaan ini , adalah apa yang saya gunakan dan mereka bekerja dengan baik
Di masing-masing dari mereka, dengan menggabungkan dengan array kosong, mereka menangani kasus yang membuat saya memeras otak saya sedikit, dalam bahwa jika Anda mencoba dan melemparkan array kosong dari
json
/jsonb
tanpa itu Anda tidak akan mendapatkan apa-apa kembali, bukan sebuah kosongkan array ({}
) seperti yang Anda harapkan. Saya yakin ada beberapa optimasi untuk mereka, tetapi mereka dibiarkan apa adanya untuk kesederhanaan dalam menjelaskan konsep.sumber