我刚开始使用postgreSQL,现在我正在尝试获取相关表条目的树结构。
假设我有以下表格:
街道,房产,建筑物,楼层,房间
streets (columns: id, name)
properties (columns: id, name, street_id)
buildings (columns: id, name, property_id)
floors (columns: id, name, building_id)
rooms (columns: id, name, floor_id)
现在我尝试获得如下输出:
[{
"id":1,
"name":"Main Street",
"properties": [{
"id":"1",
"name":"First Property",
"buildings": [{
"id":"1",
"name":"Main Building",
"floors": [{...},{...}]
},{
"id":"2",
"name":"Shed",
"floors": [{...},{...}]
}]
},{
"id":"2",
"name":"Another Property",
"buildings": [{...},{...}]
}]
}]
现在查询是这样的:
SELECT s.*, json_agg(p.*) as properties
FROM streets AS s
INNER JOIN properties AS p ON s.id = p.street_id
GROUP BY s.id;
它为我提供了上面两层街道的输出和街道内的属性结果。但我无法理解如何将建筑物嵌入房屋,然后将建筑物嵌入建筑物......,
我可以为它们添加另一个INNER JOIN和json_agg(),但是它们不会在属性中。
我应该如何处理这个问题?
编辑:
感谢德米特里,你的回答非常好。但现在让我说我想将所有数据存储在名为“locations”的同一个表中,并通过“parent_id”链接条目
所以我有专栏:
id,name,type,parent_id
使用以下代码我得到了错误的层次结构。
WITH RECURSIVE locationtree AS (
SELECT
e.*,
null::json as parent
FROM location e
WHERE parent_id IS NULL
UNION ALL
SELECT
e.*,
row_to_json(et.*) as parent
FROM location e
INNER JOIN locationtree et
ON et.id = e.parent_id
)
SELECT *
FROM locationtree;
这导致了 房间 地板 建造 属性 街
但我想在最初的问题和德米特里的答案中遵循以下结构 街道 属性 房屋 地板 室
有关于此的任何建议吗?
答案 0 :(得分:0)
使用 CTE 表达式查询可能如下:
WITH floors_agg AS (
-- get floors with nested rooms
SELECT
f.*,
json_agg(r.*) nested_rooms
FROM floors f
LEFT JOIN rooms r ON r.floor_id = f.id
GROUP BY 1
), buildings_agg AS (
-- get buildings with nested floors
SELECT
b.*,
json_agg(fa.*) nested_floors
FROM buildings b
LEFT JOIN floors_agg fa ON fa.building_id = b.id
GROUP BY 1
), properties_agg AS (
-- get properties with nested buildings
SELECT
p.*,
json_agg(ba.*)
FROM properties p
LEFT JOIN buildings_agg ba ON ba.property_id = p.id
GROUP BY 1
), streets_agg AS (
-- get streets with nested properties
SELECT
s.*,
json_agg(pa.*) nested_properties
FROM streets s
LEFT JOIN properties_agg pa ON pa.street_id = s.id
ORDER BY 1
)
SELECT json_agg(sa.*)
FROM streets_agg sa;