Teradata如何使用递归来构建JSON层次结构

时间:2016-02-24 03:51:51

标签: sql json teradata common-table-expression recursive-query

Reverse aggregation inside of common table expression找到的常见表格表达式内回答相同问题的相同问题是什么等效的Teradata语法?

我正在尝试破解Teradata语法版本以迭代父子关系表并构建JSON,该JSON将父亲的父级父级子项放置在子级等的父级子级中,并放在一个JSON字段中。

这是上面列出的超链接问题中给出的答案,我认为这是为PostgreSQL编写的。我非常感谢协助将其翻译成TD,因为我认为这个答案应该让我完成我的预期任务。如果没有请请我直截了当。

我不确定row_to_json(c)调用的是JSON_AGG(c.children)吗?我认为双冒号(NULL :: JSON)是否将null转换为JSON数据类型?无论如何,我尝试了一些变化无济于事。请帮忙。

这是给出的PostgreSQL语法答案:

WITH RECURSIVE cte AS (
   SELECT id, parent_id, name, NULL::JSON AS children
   FROM   people p
   WHERE  NOT EXISTS (  -- only leaf nodes; see link below
      SELECT 1 FROM people
      WHERE  parent_id = p.id
      )
   UNION ALL
   SELECT p.id, p.parent_id, p.name, row_to_json(c) AS children
   FROM   cte c
   JOIN   people p ON p.id = c.parent_id
   )
SELECT id, name, json_agg(children) AS children
FROM   cte
GROUP  BY 1, 2;

1 个答案:

答案 0 :(得分:1)

将PostgreSQL翻译为Teradata时遇到限制,UNION等集合操作不支持JSON列。

来回转换JSON / VarChar是一种解决方法:

CREATE VOLATILE TABLE people (id INT, name VARCHAR(20), parent_id INT) ON COMMIT PRESERVE ROWS;

INSERT INTO people VALUES(1, 'Adam', NULL);
INSERT INTO people VALUES(2, 'Abel',  1);
INSERT INTO people VALUES(3, 'Cain',  1);
INSERT INTO people VALUES(4, 'Enoch', 3);

WITH RECURSIVE cte AS (
   SELECT id, parent_id, name,
      CAST(NULL AS VARCHAR(2000)) AS children
   FROM   people p
   WHERE  NOT EXISTS (
      SELECT * FROM people
      WHERE  parent_id = p.id
      )
   UNION ALL
   SELECT p.id, p.parent_id, p.name,
      -- VarChar -> JSON -> VarChar
      CAST(JSON_COMPOSE(c.id, 
                        c.name,
                        NEW JSON(c.children) AS children) AS VARCHAR(10000)) AS children
   FROM   cte c                                       
   JOIN   people p ON p.id = c.parent_id
   )
SELECT id, name,
   JSON_AGG(NEW JSON(children) AS children) AS children
FROM cte
GROUP  BY 1, 2;

结果类似,但不完全相同,Teradata添加"children":,例如:

{"children":{"id":4,"name":"Enoch","children":null}} -- Teradata
           [{"id":4,"name":"Enoch","children":null}] -- PostgreSQL

最后添加JSONExtract以仅获取数组:

SELECT id, name,
     JSON_AGG(NEW JSON(children) AS X).JSONExtract('$..X') AS children
FROM cte
GROUP  BY 1, 2;

            [{"id":4,"name":"Enoch","children":null}]