簡體   English   中英

如何使用 Microsoft SQL Server 2016 生成分層 JSON 數據?

[英]How to generate hierarchical JSON data with Microsoft SQL Server 2016?

我正在使用Microsoft SQL Server 2016 此版本支持 JSON。

我有一個包含以下數據的Person表:

人名 父親身份 姓名
1 4 祖父
2 1 第三位祖父
3 2 2 祖父
4 3 祖父
5 4 父親
6 4 叔叔
7 6 表哥
8 5 兄弟
9 5

我運行以下查詢:

WITH Persons_CTE AS(
    SELECT PersonId, FatherId, Name FROM Persons WHERE FatherId IS NULL
    UNION ALL
    SELECT P.PersonId, P.FatherId, P.Name FROM Persons P JOIN Persons_CTE PCTE
    ON PCTE.PersonId = P.FatherId)

    SELECT P.Name as Name, PCTE.Name as Children FROM Persons_CTE PCTE LEFT JOIN Persons P
    ON P.PersonId = PCTE.FatherId 
    FOR JSON PATH

查詢生成以下結果:

[
   {
      "Children":"4th Grand Father"
   },
   {
      "Name":"4th Grand Father",
      "Children":"3rd Grand Father"
   },
   {
      "Name":"3rd Grand Father",
      "Children":"2nd Grand Father"
   },
   {
      "Name":"2nd Grand Father",
      "Children":"Grand Father"
   },
   {
      "Name":"Grand Father",
      "Children":"Father"
   },
   {
      "Name":"Grand Father",
      "Children":"Uncle"
   },
   {
      "Name":"Uncle",
      "Children":"Cousin"
   },
   {
      "Name":"Father",
      "Children":"Brother"
   },
   {
      "Name":"Father",
      "Children":"Me"
   }
]

我希望查詢結果為以下分層格式。 我該怎么做?

[
   {
      "Name":"4th Grand Father",
      "Children":[
         {
            "Name":"3rd Grand Father",
            "Children":[
               {
                  "Name":"2nd Grand Father",
                  "Children":[
                     {
                        "Name":"Grand Father",
                        "Children":[
                           {
                              "Name":"Father",
                              "children":[
                                 {
                                    "Name":"Brother"
                                 },
                                 {
                                    "Name":"Me"
                                 }
                              ]
                           },
                           {
                              "Name":"Uncle",
                              "children":[
                                 {
                                    "Name":"Cousin"
                                 }
                              ]
                           }
                        ]
                     }
                  ]
               }
            ]
         }
      ]
   }
]

當然 使用遞歸 CTE 實現 Json 樹將非常困難(如果不是不可能的話)。

但是,使用遞歸函數確實很有幫助並解決了問題:

ALTER  FUNCTION fn_Json(@PersonId INT, @IsRoot INT ) 
RETURNS VARCHAR(MAX)
BEGIN 
    DECLARE @Json NVARCHAR(MAX) = '{}', @Name NVARCHAR(MAX) , @Children                 NVARCHAR(MAX)

    SET @Json =  
    (SELECT P.Name ,JSON_QUERY(dbo.fn_Json(P.PersonId, 2) ) AS Children 
    FROM dbo.Persons AS P  
    WHERE P.FatherId = @PersonId 
    FOR JSON AUTO);

    IF(@IsRoot = 1) 
    BEGIN
       SELECT @Name = P.Name FROM dbo.Persons AS P WHERE P.PersonId = @PersonId
       SET @Json =   '{"Name":"' + @Name + '","Children":' + CAST(@Json AS NVARCHAR(MAX)) + '}'
       SET @IsRoot = 2
    END

    RETURN @Json 
END 

值得一提的是,如果其內部對象無效,則無法構建函數。 因此,有必要將函數構建為:

CREATE FUNCTION fn_Json(@PersonId INT, @IsRoot INT) 
RETURNS VARCHAR(MAX)
BEGIN 
   RETURN 1
END 

然后使用拳頭代碼。 如果您希望根節點包含在集合中

@IsRoot = 1

如果不是@IsRoot = 2或其他一些值

不幸的是,遞歸 CTe 不能用於生成分層 json 。 遞歸 CTE 的輸出仍然是平坦的結果。

創建分層輸出的唯一方法是為每個級別創建單獨的 CTE,然后加入 using FOR JSON AUTO

准備表:

declare @t table (PersonId int, FatherId int, Name nvarchar(20));

insert into @t(PersonId, FatherId, Name)
values
(1, NULL, '4th Grand Father'),
(2, 1, '3rd Grand Father'),
(3, 2, '2nd Grand Father'),
(4, 3, 'Grand Father'),
(5, 4, 'Father'),
(6, 4, 'Uncle'),
(7, 6, 'Cousin'),
(8, 5, 'Brother'),
(9, 5, 'Me');

-- 分層查詢:

WITH
Persons_CTE1 AS(
    SELECT PersonId, FatherId, Name FROM @t WHERE FatherId IS NULL
),
Persons_CTE2 AS(
    SELECT P.PersonId, P.FatherId, P.Name
    from @t P
    WHERE P.FatherId IN (SELECT PersonId FROM Persons_CTE1)
),
Persons_CTE3 AS(
    SELECT P.PersonId, P.FatherId, P.Name
    from @t P
    WHERE P.FatherId IN (SELECT PersonId FROM Persons_CTE2)
),
Persons_CTE4 AS(
    SELECT P.PersonId, P.FatherId, P.Name
    from @t P
    WHERE P.FatherId IN (SELECT PersonId FROM Persons_CTE3)
),
Persons_CTE5 AS(
    SELECT P.PersonId, P.FatherId, P.Name
    from @t P
    WHERE P.FatherId IN (SELECT PersonId FROM Persons_CTE4)
),
Persons_CTE6 AS(
    SELECT P.PersonId, P.FatherId, P.Name
    from @t P
    WHERE P.FatherId IN (SELECT PersonId FROM Persons_CTE5)
)
select Persons_CTE1.Name, Persons_CTE2.Name, Persons_CTE3.Name,
       Persons_CTE4.Name, Persons_CTE5.Name, Persons_CTE6.Name
from Persons_CTE1
    LEFT JOIN Persons_CTE2
        ON Persons_CTE2.FatherId = Persons_CTE1.PersonId
    LEFT JOIN Persons_CTE3
        ON Persons_CTE3.FatherId = Persons_CTE2.PersonId
    LEFT JOIN Persons_CTE4
        ON Persons_CTE4.FatherId = Persons_CTE3.PersonId
    LEFT JOIN Persons_CTE5
        ON Persons_CTE5.FatherId = Persons_CTE4.PersonId
    LEFT JOIN Persons_CTE6
        ON Persons_CTE6.FatherId = Persons_CTE5.PersonId
FOR JSON AUTO

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM