通过将父母和孩子分组来显示Postgres LTREE

时间:2019-07-18 06:53:23

标签: sql postgresql psql ltree

我有一个示例Ltree结构,而不想将其作为JSON结构返回。 我尝试过搜索堆栈溢出,但是结果给出了错误的响应。

create table node
(
    id   integer not null,
    name varchar(255),
    path ltree   not null
);

我有这些数据

INSERT INTO node (id,name,path) VALUES (1,'Residential','1');
INSERT INTO node (id,name,path) VALUES (2,'Commercial','2');
INSERT INTO node (id,name,path) VALUES (3,'Industrial','3');
INSERT INTO node (id,name,path) VALUES (4,'Res type 1','1.4');
INSERT INTO node (id,name,path) VALUES (5,'Comm type 1','2.5');
INSERT INTO node (id,name,path) VALUES (6,'Industrial 1','3.6');
INSERT INTO node (id,name,path) VALUES (7,'Residential 2','1.4.7');
INSERT INTO node (id,name,path) VALUES (8,'Commercial 2','2.5.8');
INSERT INTO node (id,name,path) VALUES (9,'Industrial 2','3.6.9');

这就是我要通过查询收集的信息

[
  {
    "name": "Residentioal",
    "children": [
      {
        "name": "Res type 1",
        "children": [
          {
            "name": "Residential 2",
            "children": []
          }
        ]
      }
    ]
  },
  {
    "name": "Commercial",
    "children": [
      {
        "name": "Comm type 1",
        "children": [
          {
            "name": "Commercial 2",
            "children": []
          }
        ]
      }
    ]
  },
  {
    "name": "Industrial",
    "children": [
      {
        "name": "Industrial 1",
        "children": [
          {
            "name": "Industrial 2",
            "children": []
          }
        ]
      }
    ]
  }
]

我尝试了recursive with ..,但是它一直循环执行而没有返回正确的值。

1 个答案:

答案 0 :(得分:1)

您需要两个部分,一个是递归部分,另一个是函数。我已经对此hereherehere进行了解释,因此请查看那里以获取进一步的解释。

demo:db<>fiddle

递归

WITH RECURSIVE cte AS (
    SELECT 
        id,
        name,
        path,
        json_build_object('name', name, 'children', ARRAY[]::text[]) AS jsonobject,
        ARRAY[]::text[] || (row_number() OVER () - 1)::text as jsonpath,
        0 as depth        
    FROM node
    WHERE path = subpath(path, 0, 1) --parents

    UNION ALL

    SELECT
        n.id, 
        n.name, 
        n.path,
        json_build_object('name', n.name, 'children', ARRAY[]::text[]),
        jsonpath || '{children}' || (row_number() OVER (PARTITION BY subpath(n.path, depth, 1)::text ORDER BY subpath(n.path, depth + 1, 1)::text::int) - 1)::text,
        c.depth + 1
    FROM
        node n
    JOIN cte c 
    ON c.id = subpath(n.path, depth, 1)::text::int
       AND nlevel(n.path) = depth + 2 AND subpath(n.path, depth + 1, 1)::text::int = n.id
)
SELECT * FROM cte

功能

CREATE OR REPLACE FUNCTION nested_json() RETURNS jsonb AS $$
DECLARE
    _json_output jsonb;
    _temprow record;
BEGIN   
    _json_output := '[]'::jsonb;

    FOR _temprow IN
        -- <Add the CTE from above here>
    LOOP
        SELECT 
        jsonb_insert(
            _json_output, 
            _temprow.jsonpath, 
            _temprow.jsonobject
        )
        INTO _json_output;
    END LOOP;   

    RETURN _json_output;
END;
$$ LANGUAGE plpgsql;

请注意:对于这种用例,ltree结构并不是一个很好的选择,因为您需要一次又一次地计算子路径。对父母的简单引用会更有用和更快。


编辑:db <> fiddle管理员非常棒,并安装了ltree扩展名,因此有一个新的fiddle