SQL Query 以逗号分隔获取 Json 内部的 Json 值
Posted
技术标签:
【中文标题】SQL Query 以逗号分隔获取 Json 内部的 Json 值【英文标题】:SQL Query to get the Json inside Json values by comma separated 【发布时间】:2020-05-04 16:47:09 【问题描述】:我有下面的 Json 对象。我需要用逗号(,)分隔的任务名称。
"Model": [
"ModelName": "Test Model",
"Object": [
"ID": 1,
"Name": "ABC",
"Task" : [
TaskID : 1222,
Name: "TaskA"
,
TaskID : 154,
Name: "TaskB"
]
,
"ID": 11,
"Name": "ABCD",
"Task" : [
TaskID : 222,
Name: "TaskX"
,
TaskID : 234,
Name: "TaskY"
]
,
]
]
预期的输出应在下表中。我需要任务名称应该用逗号分隔。
ModelName ObjectID ObjectName TaskName
Test Model 1 ABC TaskA, TaskB
Test Model 11 ABCD TaskX, TaskY
我尝试了以下查询。但我不知道如何对任务名称进行分组。
SELECT S1.ModelName,
S2.ID AS ObjectID,
S2.Name AS ObjectName,
S3.TaskName
FROM TableA
CROSS APPLY OPENJSON(JsonData)
WITH (Model NVARCHAR(MAX) '$.Model[0]' AS JSON) S1
CROSS APPLY OPENJSON (S1.Model)
WITH (Object NVARCHAR(MAX) '$.Object' AS JSON,
ID INT '$.ID',
Name NVARCHAR(250) '$.Name') S2
CROSS APPLY OPENJSON (S2.Object)
WITH (Task NVARCHAR(MAX) '$.Task' AS JSON ,
TaskName NVARCHAR(MAX) '$.TaskName') S3
【问题讨论】:
【参考方案1】:您需要使用STRING_AGG()
来聚合文本值,一种可能的方法(基于问题中的尝试)是以下语句。任务名称的聚合是针对Object
JSON 数组中的每个项目:
表:
CREATE TABLE TableA (JsonData varchar(max))
INSERT INTO TableA (JsonData) VALUES ('
"Model": [
"ModelName": "Test Model",
"Object": [
"ID": 1,
"Name": "ABC",
"Task" : [
"TaskID" : 1222,
"Name": "TaskA"
,
"TaskID" : 154,
"Name": "TaskB"
]
,
"ID": 11,
"Name": "ABCD",
"Task" : [
"TaskID" : 222,
"Name": "TaskX"
,
"TaskID" : 234,
"Name": "TaskY"
]
]
]')
声明:
SELECT
j1.ModelName,
j2.ObjectID, j2.ObjectName,
c.TaskName
FROM TableA t
CROSS APPLY OPENJSON(t.JsonData, '$.Model[0]') WITH (
ModelName varchar(50) '$.ModelName',
Object nvarchar(max) '$.Object' AS JSON
) j1
CROSS APPLY OPENJSON(j1.Object, '$') WITH (
ObjectID int '$.ID',
ObjectName varchar(50) '$.Name',
Task nvarchar(max) '$.Task' AS JSON
) j2
CROSS APPLY (
SELECT STRING_AGG([Name], ',') AS TaskName
FROM OPENJSON (j2.Task, '$') WITH (Name varchar(50) '$.Name')
) c
【讨论】:
【参考方案2】:您需要使用STRING_AGG()
函数,适用于DB版本SQL Server 2017及更高版本,连同下面的GROUP BY
表达式为
SELECT S1.ModelName, S2.ID AS ObjectID, S2.Name AS ObjectName,
STRING_AGG(S3.TaskName, ',') WITHIN GROUP (ORDER BY TaskName) AS TaskName
FROM <rest of your query>
GROUP BY S1.ModelName, S2.ID, S2.Name
作为一个完整的查询:
SELECT S1.ModelName, S3.ObjectID, S3.ObjectName,
STRING_AGG(S4.TaskName, ',') WITHIN GROUP (ORDER BY S4.TaskName) AS TaskName
FROM TableA
CROSS APPLY OPENJSON(JsonData)
WITH (ModelName NVARCHAR(255) '$.Model[0].ModelName') S1
CROSS APPLY OPENJSON (JsonData)
WITH (Object NVARCHAR(MAX) '$.Model[0].Object' AS JSON) S2
CROSS APPLY OPENJSON (S2.Object)
WITH (ObjectID INT '$.ID',
ObjectName NVARCHAR(255) '$.Name',
Task NVARCHAR(MAX) '$.Task' AS JSON) S3
CROSS APPLY OPENJSON (S3.Task)
WITH (TaskID NVARCHAR(MAX) '$.TaskID',
TaskName NVARCHAR(MAX) '$.Name') S4
GROUP BY S1.ModelName, S3.ObjectID, S3.ObjectName
使用WITHIN GROUP (ORDER BY TaskName)
是可选的,如果您不想订购,那么您可以从函数中删除该部分,如下所示:
Demo
【讨论】:
通过上述查询,订单正在发生变化。我不想改变顺序。有什么我们可以修改的吗?我们也有可能重复模型名称、对象 ID 和对象名称。如果我们再次使用 Group by,就会出现问题。 然后只使用STRING_AGG(S3.TaskName, ',') AS TaskName
部分@AshokYaganti
甚至订单也在改变。不使用Group by还有其他方法吗?
我添加了一个 Demo 并根据它更改了答案中的查询 @AshokYaganti
Barbaros Özhan 上面的查询是正确的,但是一些极端情况下失败了。下面的查询给了我正确的结果。感谢您在这方面帮助我。以上是关于SQL Query 以逗号分隔获取 Json 内部的 Json 值的主要内容,如果未能解决你的问题,请参考以下文章