从 sql 查询 postgres 9.4 创建嵌套的 json
Create nested json from sql query postgres 9.4
我需要从完全结构化的查询中获得结果 JSON。
我可以在 postgres 中看到有一些可能有用的内置函数。
作为示例,我创建了一个结构如下:
-- Table: person
-- DROP TABLE person;
CREATE TABLE person
(
id integer NOT NULL,
name character varying(30),
CONSTRAINT person_pk PRIMARY KEY (id)
)
WITH (
OIDS=FALSE
);
ALTER TABLE person
OWNER TO postgres;
-- Table: car
-- DROP TABLE car;
CREATE TABLE car
(
id integer NOT NULL,
type character varying(30),
personid integer,
CONSTRAINT car_pk PRIMARY KEY (id)
)
WITH (
OIDS=FALSE
);
ALTER TABLE car
OWNER TO postgres;
-- Table: wheel
-- DROP TABLE wheel;
CREATE TABLE wheel
(
id integer NOT NULL,
whichone character varying(30),
serialnumber integer,
carid integer,
CONSTRAINT "Wheel_PK" PRIMARY KEY (id)
)
WITH (
OIDS=FALSE
);
ALTER TABLE wheel
OWNER TO postgres;
还有一些数据:
INSERT INTO person(id, name)
VALUES (1, 'Johny'),
(2, 'Freddy');
INSERT INTO car(id, type, personid)
VALUES (1, 'Toyota', 1),
(2, 'Fiat', 1),
(3, 'Opel', 2);
INSERT INTO wheel(id, whichone, serialnumber, carid)
VALUES (1, 'front', '11', 1),
(2, 'back', '12', 1),
(3, 'front', '21', 2),
(4, 'back', '22', 2),
(5, 'front', '3', 3);
因此,我想要一个 JSON 对象,其中包含人员列表,每个人都有汽车列表和每辆汽车的车轮列表。
我试过类似的东西,但这不是我想要的东西:
select json_build_object(
'Persons', json_build_object(
'person_name', person.name,
'cars', json_build_object(
'carid', car.id,
'type', car.type,
'comment', 'nice car', -- this is constant
'wheels', json_build_object(
'which', wheel.whichone,
'serial number', wheel.serialnumber
)
))
)
from
person
left join car on car.personid = person.id
left join wheel on wheel.carid = car.id
我想我缺少一些分组 json_agg 但我不确定该怎么做。
我想得到这样的结果:
{ "persons": [
{
"person_name": "Johny",
"cars": [
{
"carid": 1,
"type": "Toyota",
"comment": "nice car",
"wheels": [{
"which": "Front",
"serial number": 11
},
{
"which": "Back",
"serial number": 12
}]
},
{
"carid": 2,
"type": "Fiat",
"comment": "nice car",
"wheels": [{
"which": "Front",
"serial number": 21
},{
"which": "Back",
"serial number": 22
}]
}
]
},
{
"person_name": "Freddy",
"cars": [
{
"carid": 3,
"type": "Opel",
"comment": "nice car",
"wheels": [{
"which": "Front",
"serial number": 33
}]
}]
}]
}
http://www.jsoneditoronline.org/?id=7792a0a2bf11be724c29bb86c4b14577
您应该构建分层查询以获得分层结构作为结果。
您想在一个 json 对象中包含很多人,因此请使用 json_agg()
将人聚集在一个 json 数组中。
类似地,一个人可以拥有多辆汽车,您应该将属于一个人的汽车放在 json 数组中。这同样适用于汽车和车轮。
select
json_build_object(
'persons', json_agg(
json_build_object(
'person_name', p.name,
'cars', cars
)
)
) persons
from person p
left join (
select
personid,
json_agg(
json_build_object(
'carid', c.id,
'type', c.type,
'comment', 'nice car', -- this is constant
'wheels', wheels
)
) cars
from
car c
left join (
select
carid,
json_agg(
json_build_object(
'which', w.whichone,
'serial number', w.serialnumber
)
) wheels
from wheel w
group by 1
) w on c.id = w.carid
group by personid
) c on p.id = c.personid;
(格式化的)结果:
{
"persons": [
{
"person_name": "Johny",
"cars": [
{
"carid": 1,
"type": "Toyota",
"comment": "nice car",
"wheels": [
{
"which": "front",
"serial number": 11
},
{
"which": "back",
"serial number": 12
}
]
},
{
"carid": 2,
"type": "Fiat",
"comment": "nice car",
"wheels": [
{
"which": "front",
"serial number": 21
},
{
"which": "back",
"serial number": 22
}
]
}
]
},
{
"person_name": "Freddy",
"cars": [
{
"carid": 3,
"type": "Opel",
"comment": "nice car",
"wheels": [
{
"which": "front",
"serial number": 3
}
]
}
]
}
]
}
如果您不熟悉嵌套的派生 table,您可以使用常见的 table 表达式。
此变体说明应该从最嵌套的对象开始向最高级别构建查询:
with wheels as (
select
carid,
json_agg(
json_build_object(
'which', w.whichone,
'serial number', w.serialnumber
)
) wheels
from wheel w
group by 1
),
cars as (
select
personid,
json_agg(
json_build_object(
'carid', c.id,
'type', c.type,
'comment', 'nice car', -- this is constant
'wheels', wheels
)
) cars
from car c
left join wheels w on c.id = w.carid
group by c.personid
)
select
json_build_object(
'persons', json_agg(
json_build_object(
'person_name', p.name,
'cars', cars
)
)
) persons
from person p
left join cars c on p.id = c.personid;
我想到了这个解决方案。它非常紧凑,适用于任何给定情况。
但是,与更多使用 json_build_object
的其他解决方案相比,不确定对性能有何影响。使用 row_to_json
优于 json_build_object
的优点是所有工作都在幕后完成,这使查询更具可读性。
SELECT json_build_object('persons', json_agg(p)) persons
FROM (
SELECT
person.name person_name,
(
SELECT json_agg(row_to_json(c))
FROM (
SELECT
id carid,
type,
(
SELECT json_agg(row_to_json(w))
FROM (
SELECT
whichone which,
serialnumber
FROM wheel
WHERE wheel.carid = car.id
) w
) wheels
FROM car
WHERE car.personid = person.id
) c
) AS cars
FROM person
) p
select row_to_json(t)
from (
select service_id,service_name,product_description,service_description,account,
(
select array_to_json(array_agg(row_to_json(jd)))
from (
select service_location,opening_stock,running_stock
from public.product_service_location
where s.service_id = service_location_id
) jd
) as product_service_location
from public.product_service s
where s.service_id=services_id
) as t;
我需要从完全结构化的查询中获得结果 JSON。 我可以在 postgres 中看到有一些可能有用的内置函数。
作为示例,我创建了一个结构如下:
-- Table: person
-- DROP TABLE person;
CREATE TABLE person
(
id integer NOT NULL,
name character varying(30),
CONSTRAINT person_pk PRIMARY KEY (id)
)
WITH (
OIDS=FALSE
);
ALTER TABLE person
OWNER TO postgres;
-- Table: car
-- DROP TABLE car;
CREATE TABLE car
(
id integer NOT NULL,
type character varying(30),
personid integer,
CONSTRAINT car_pk PRIMARY KEY (id)
)
WITH (
OIDS=FALSE
);
ALTER TABLE car
OWNER TO postgres;
-- Table: wheel
-- DROP TABLE wheel;
CREATE TABLE wheel
(
id integer NOT NULL,
whichone character varying(30),
serialnumber integer,
carid integer,
CONSTRAINT "Wheel_PK" PRIMARY KEY (id)
)
WITH (
OIDS=FALSE
);
ALTER TABLE wheel
OWNER TO postgres;
还有一些数据:
INSERT INTO person(id, name)
VALUES (1, 'Johny'),
(2, 'Freddy');
INSERT INTO car(id, type, personid)
VALUES (1, 'Toyota', 1),
(2, 'Fiat', 1),
(3, 'Opel', 2);
INSERT INTO wheel(id, whichone, serialnumber, carid)
VALUES (1, 'front', '11', 1),
(2, 'back', '12', 1),
(3, 'front', '21', 2),
(4, 'back', '22', 2),
(5, 'front', '3', 3);
因此,我想要一个 JSON 对象,其中包含人员列表,每个人都有汽车列表和每辆汽车的车轮列表。
我试过类似的东西,但这不是我想要的东西:
select json_build_object(
'Persons', json_build_object(
'person_name', person.name,
'cars', json_build_object(
'carid', car.id,
'type', car.type,
'comment', 'nice car', -- this is constant
'wheels', json_build_object(
'which', wheel.whichone,
'serial number', wheel.serialnumber
)
))
)
from
person
left join car on car.personid = person.id
left join wheel on wheel.carid = car.id
我想我缺少一些分组 json_agg 但我不确定该怎么做。
我想得到这样的结果:
{ "persons": [
{
"person_name": "Johny",
"cars": [
{
"carid": 1,
"type": "Toyota",
"comment": "nice car",
"wheels": [{
"which": "Front",
"serial number": 11
},
{
"which": "Back",
"serial number": 12
}]
},
{
"carid": 2,
"type": "Fiat",
"comment": "nice car",
"wheels": [{
"which": "Front",
"serial number": 21
},{
"which": "Back",
"serial number": 22
}]
}
]
},
{
"person_name": "Freddy",
"cars": [
{
"carid": 3,
"type": "Opel",
"comment": "nice car",
"wheels": [{
"which": "Front",
"serial number": 33
}]
}]
}]
}
http://www.jsoneditoronline.org/?id=7792a0a2bf11be724c29bb86c4b14577
您应该构建分层查询以获得分层结构作为结果。
您想在一个 json 对象中包含很多人,因此请使用 json_agg()
将人聚集在一个 json 数组中。
类似地,一个人可以拥有多辆汽车,您应该将属于一个人的汽车放在 json 数组中。这同样适用于汽车和车轮。
select
json_build_object(
'persons', json_agg(
json_build_object(
'person_name', p.name,
'cars', cars
)
)
) persons
from person p
left join (
select
personid,
json_agg(
json_build_object(
'carid', c.id,
'type', c.type,
'comment', 'nice car', -- this is constant
'wheels', wheels
)
) cars
from
car c
left join (
select
carid,
json_agg(
json_build_object(
'which', w.whichone,
'serial number', w.serialnumber
)
) wheels
from wheel w
group by 1
) w on c.id = w.carid
group by personid
) c on p.id = c.personid;
(格式化的)结果:
{
"persons": [
{
"person_name": "Johny",
"cars": [
{
"carid": 1,
"type": "Toyota",
"comment": "nice car",
"wheels": [
{
"which": "front",
"serial number": 11
},
{
"which": "back",
"serial number": 12
}
]
},
{
"carid": 2,
"type": "Fiat",
"comment": "nice car",
"wheels": [
{
"which": "front",
"serial number": 21
},
{
"which": "back",
"serial number": 22
}
]
}
]
},
{
"person_name": "Freddy",
"cars": [
{
"carid": 3,
"type": "Opel",
"comment": "nice car",
"wheels": [
{
"which": "front",
"serial number": 3
}
]
}
]
}
]
}
如果您不熟悉嵌套的派生 table,您可以使用常见的 table 表达式。 此变体说明应该从最嵌套的对象开始向最高级别构建查询:
with wheels as (
select
carid,
json_agg(
json_build_object(
'which', w.whichone,
'serial number', w.serialnumber
)
) wheels
from wheel w
group by 1
),
cars as (
select
personid,
json_agg(
json_build_object(
'carid', c.id,
'type', c.type,
'comment', 'nice car', -- this is constant
'wheels', wheels
)
) cars
from car c
left join wheels w on c.id = w.carid
group by c.personid
)
select
json_build_object(
'persons', json_agg(
json_build_object(
'person_name', p.name,
'cars', cars
)
)
) persons
from person p
left join cars c on p.id = c.personid;
我想到了这个解决方案。它非常紧凑,适用于任何给定情况。
但是,与更多使用 json_build_object
的其他解决方案相比,不确定对性能有何影响。使用 row_to_json
优于 json_build_object
的优点是所有工作都在幕后完成,这使查询更具可读性。
SELECT json_build_object('persons', json_agg(p)) persons
FROM (
SELECT
person.name person_name,
(
SELECT json_agg(row_to_json(c))
FROM (
SELECT
id carid,
type,
(
SELECT json_agg(row_to_json(w))
FROM (
SELECT
whichone which,
serialnumber
FROM wheel
WHERE wheel.carid = car.id
) w
) wheels
FROM car
WHERE car.personid = person.id
) c
) AS cars
FROM person
) p
select row_to_json(t)
from (
select service_id,service_name,product_description,service_description,account,
(
select array_to_json(array_agg(row_to_json(jd)))
from (
select service_location,opening_stock,running_stock
from public.product_service_location
where s.service_id = service_location_id
) jd
) as product_service_location
from public.product_service s
where s.service_id=services_id
) as t;