如何将多个postgreSQL表嵌套到一个json中?

时间:2015-12-13 18:58:07

标签: json postgresql

我刚开始使用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;

这导致了      房间         地板            建造               属性                  街

但我想在最初的问题和德米特里的答案中遵循以下结构      街道         属性            房屋               地板                  室

有关于此的任何建议吗?

1 个答案:

答案 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;