从 Table 值输出 JSON 类型数组而不重复的最佳做法是什么?

What is the best practise for outputting JSON Type arrays from Table values without repetition?

我有以下 SQL 数据,我正尝试将其输出为结构化 JSON 字符串,如下所示:

Table数据

TableId ContainerId MaterialId  SizeId
848     1           1           1
849     1           1           2
850     1           2           1
851     1           2           2
852     1           3           1
853     1           4           1
854     2           2           1
855     2           2           2
856     2           2           3

JSON输出

{
  "container": [
    {
      "id": 1,
      "material": [
        {
          "id": 1,
          "size": [
            {
              "id": 1
            },
            {
              "id": 2
            }
          ]
        },
        {
          "id": 2,
          "size": [
            {
              "id": 1
            },
            {
              "id": 2
            }
          ]
        },
        {
          "id": 3,
          "size": [
            {
              "id": 1
            }
          ]
        },
        {
          "id": 4,
          "size": [
            {
              "id": 1
            }
          ]
        }
      ]
    },
    {
      "id": 2,
      "material": [
        {
          "id": 2,
          "size": [
            {
              "id": 1
            },
            {
              "id": 2
            },
            {
              "id": 3
            }
          ]
        }
      ]
    }
  ]
}

我已经尝试了几种输出它的方法,但我很难停止重复的 Container 和 Material Id 记录。有没有人能够展示从这样的 table 中提取 JSON 的最佳工作实践?

您可以使用以下查询

SELECT CONCAT('{"container": [',string_agg(json,','),']}') as json
FROM 


  (SELECT CONCAT('{"id:"',CAST(ContainerId as nvarchar(100)),
       ',"material":[{',string_agg(json,','),'}]}') as json,
       dense_rank() over(partition by ContainerId order by ContainerId) rnk
  FROM
     (SELECT ContainerId ,MaterialId,CONCAT('"id":',CAST(MaterialId as nvarchar(100))
           ,',"size":[',string_agg('{"id":' + CAST(SizeId as nvarchar(100)) + '}',','),']') as json
         
     FROM tb  
     GROUP BY ContainerId,MaterialId) T
  GROUP BY ContainerId) T

GROUP BY rnk

演示 db<>fiddle

嗯,它并不漂亮,但这似乎有效:

WITH
   container As (SELECT distinct containerid As id FROM jsonArray1 As container)
 , material As (SELECT distinct materialid As id, containerid As cid FROM jsonArray1 As material) 
 , size As (SELECT sizeid As id, materialid As tid, containerid As cid FROM jsonArray1 As size) 
SELECT container.id id, material.id id, size.id id
FROM container
JOIN material ON material.cid = container.id 
JOIN size     ON size.tid = material.id AND size.cid = material.cid
FOR JSON AUTO, ROOT

sqlfiddle example

AUTO 将为您构造 JSON,但仅遵循查询中使用的数据 table 的结构。由于数据以单个 table 开始“平坦”,因此 AUTO 不会创建任何结构。所以我在这里应用的技巧是使用 WITH CTE 将这个平面数据重组为三个虚拟 tables,它们的关系具有必要的结构。

这里的一切都非常敏感,正常关系 SQL 不会如此。例如,仅更改 JOIN 的顺序将重构 JSON 层次结构,即使这对正常的 SQL 查询没有影响。

我还不得不尝试使用 table 和列别名(lot)来让它在 [=24] 中的所有内容上加上正确的名称=].