我正在使用 Microsoft SQL Server 2016 。此版本支持JSON。
我有一个人表,其中包含以下数据:
PersonId FatherId Name
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_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"
}
]
}
]
}
]
}
]
}
]
}
]
答案 0 :(得分:3)
当然使用递归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
GO
值得一提的是,如果内部对象无效,则无法构建函数。因此,有必要将函数构建为:
CREATE FUNCTION fn_Json(@PersonId INT, @IsRoot INT)
RETURNS VARCHAR(MAX)
BEGIN
RETURN 1
END
然后使用第一个代码。如果您希望包含根节点
@IsRoot = 1
如果不是@IsRoot = 2
或其他一些值
答案 1 :(得分:1)
不幸的是,递归CTe不能用于生成分层json。递归CTE的输出仍然是平坦的结果。
创建分层输出的唯一方法是为每个级别创建单独的CTE,然后加入使用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