Pembaruan:Di PostgreSQL 9.4 ini meningkat pesat dengan pengenalan to_json
, json_build_object
, json_object
dan json_build_array
, meskipun bertele-tele karena kebutuhan untuk menamai semua bidang secara eksplisit:
select
json_build_object(
'id', u.id,
'name', u.name,
'email', u.email,
'user_role_id', u.user_role_id,
'user_role', json_build_object(
'id', ur.id,
'name', ur.name,
'description', ur.description,
'duty_id', ur.duty_id,
'duty', json_build_object(
'id', d.id,
'name', d.name
)
)
)
from users u
inner join user_roles ur on ur.id = u.user_role_id
inner join role_duties d on d.id = ur.duty_id;
Untuk versi yang lebih lama, baca terus.
Itu tidak terbatas pada satu baris, itu hanya sedikit menyakitkan. Anda tidak dapat membuat alias tipe baris komposit menggunakan AS
, jadi Anda perlu menggunakan ekspresi subquery alias atau CTE untuk mendapatkan efeknya:
select row_to_json(row)
from (
select u.*, urd AS user_role
from users u
inner join (
select ur.*, d
from user_roles ur
inner join role_duties d on d.id = ur.duty_id
) urd(id,name,description,duty_id,duty) on urd.id = u.user_role_id
) row;
menghasilkan, melalui http://jsonprettyprint.com/:
{
"id": 1,
"name": "Dan",
"email": "[email protected]",
"user_role_id": 1,
"user_role": {
"id": 1,
"name": "admin",
"description": "Administrative duties in the system",
"duty_id": 1,
"duty": {
"id": 1,
"name": "Script Execution"
}
}
}
Anda akan ingin menggunakan array_to_json(array_agg(...))
ketika Anda memiliki hubungan 1:banyak, btw.
Kueri di atas idealnya dapat ditulis sebagai:
select row_to_json(
ROW(u.*, ROW(ur.*, d AS duty) AS user_role)
)
from users u
inner join user_roles ur on ur.id = u.user_role_id
inner join role_duties d on d.id = ur.duty_id;
... tetapi ROW
PostgreSQL konstruktor tidak menerima AS
alias kolom. Sayangnya.
Untungnya, mereka mengoptimalkan hal yang sama. Bandingkan paketnya:
- Versi subkueri bersarang; vs
- Yang terakhir bersarang
ROW
versi konstruktor dengan alias dihapus sehingga dijalankan
Karena CTE adalah pagar pengoptimalan, frasa ulang versi subkueri bersarang untuk menggunakan CTE berantai (WITH
ekspresi) mungkin tidak berfungsi dengan baik, dan tidak akan menghasilkan rencana yang sama. Dalam hal ini Anda agak terjebak dengan subkueri bersarang jelek sampai kami mendapatkan beberapa peningkatan pada row_to_json
atau cara untuk mengganti nama kolom dalam ROW
konstruktor secara lebih langsung.
Bagaimanapun, secara umum, prinsipnya adalah di mana Anda ingin membuat objek json dengan kolom a, b, c
, dan Anda ingin menulis sintaks ilegal:
ROW(a, b, c) AS outername(name1, name2, name3)
Anda dapat menggunakan subkueri skalar yang mengembalikan nilai yang diketik baris:
(SELECT x FROM (SELECT a AS name1, b AS name2, c AS name3) x) AS outername
Atau:
(SELECT x FROM (SELECT a, b, c) AS x(name1, name2, name3)) AS outername
Selain itu, perlu diingat bahwa Anda dapat membuat json
nilai tanpa kutipan tambahan, mis. jika Anda memasukkan output dari json_agg
dalam row_to_json
, json_agg
bagian dalam hasilnya tidak akan dikutip sebagai string, itu akan dimasukkan langsung sebagai json.
misalnya dalam contoh arbitrer:
SELECT row_to_json(
(SELECT x FROM (SELECT
1 AS k1,
2 AS k2,
(SELECT json_agg( (SELECT x FROM (SELECT 1 AS a, 2 AS b) x) )
FROM generate_series(1,2) ) AS k3
) x),
true
);
outputnya adalah:
{"k1":1,
"k2":2,
"k3":[{"a":1,"b":2},
{"a":1,"b":2}]}
Perhatikan bahwa json_agg
produk, [{"a":1,"b":2}, {"a":1,"b":2}]
, belum di-escape lagi, sebagai text
akan.
Ini berarti Anda dapat menciptakan json untuk membuat baris, Anda tidak selalu harus membuat tipe komposit PostgreSQL yang sangat kompleks, lalu panggil row_to_json
pada keluaran.