将 SQL 输出格式化为 JSON 的最佳方式?
Best way to format SQL output to a JSON?
一直在尝试进行 SQL 查询并输出完美的 JSON 但我 运行 遇到了问题。查询仅涉及 tables,当我使用“For JSON Auto”时,它会生成一个平面对象数组:enter image description here
但是存在层级关系:
Q2C号---
订单项----
标识符
我尝试使用“For JSON Path”,但它只构建每个 json 对象(例如,它不会聚合其父 LineItem 下的所有标识符)。
我已经通过将 table 连接到自身来让它看起来像这样(相同的查询只是额外的连接,“For JSON Path Auto”似乎喜欢这样)和它看起来更像这样:enter image description here
哪个好。问题是查询花费的时间几乎是原来的 20 倍(2 秒对 20 秒)。
可能是我的self join写的不好,或者join得到这些结果效率低下。
无论如何,如果有人知道如何做到这一点,请告诉我(不能分享太多,我相信你注意到了图像上的色块)。
更新:
这是查询的图片 enter image description here。问题是我得到一个平面 JSON (只是一个对象数组)。
Select OWS.Q2CNum,
OWS.LineItem,
OWS.Identifier,
OWS.ProductType,
OWS.Workstation,
OWS.Calculation,
OWS.UnitOfMeasure,
OWS.CurrentStatus,
LS.Location,
LS.ProgramStamp_LocalTime
FROM table1 AS OWS
INNER JOIN table2 AS LS
ON OWS.Q2CNum = LS.[Order]
AND OWS.LineItem = LS.LineItem
AND OWS.Identifier = LS.Identifier
WHERE LS.ProgramStamp_LocalTime =
(Select TOP 1 LS2.ProgramStamp_LocalTime
from dbo.view_Location_Stamps_Local AS LS2
Where LS2.[Order] = OWS.Q2CNum
AND LS2.LineItem= OWS.LineItem
AND LS2.Identifier = OWS.Identifier
Order by LS2.ProgramStamp_LocalTime Desc)
AND LS.[Order] = @testVar
AND LS.LineItem = COALESCE('001',OWS.LineItem)
AND LS.Identifier like '%'
---Group by Q2CNum
ORDER BY Q2CNum, LineItem, Identifier DESC
FOR JSON Auto
但我需要它是分层的:
{
Q2CNum: value,
LineItems: [{
LineItem: value,
Identifiers: [{
identifier: value,
etc...
}],
}],
}
更新 2:
如果我运行这个查询我得到更多我想要的:
Select Q2C.Q2CNum,
Li.LineItem ,
OWS.Identifier,
OWS.ProductType,
OWS.Workstation,
OWS.Calculation,
OWS.UnitOfMeasure,
OWS.CurrentStatus,
LS.Location,
LS.ProgramStamp_LocalTime
FROM table1 AS OWS
INNER JOIN table2 AS Q2C
ON Q2C.Q2CNum = OWS.Q2CNum and Q2C.LineItem = OWS.LineItem and Q2C.Identifier = OWS.Identifier and Q2C.Workstation = OWS.Workstation
INNER JOIN table3 AS Li
ON Li.Q2CNum = OWS.Q2CNum and Li.LineItem = OWS.LineItem and Li.Identifier = OWS.Identifier and Li.Workstation = OWS.Workstation
INNER JOIN table4 AS LS
ON OWS.Q2CNum = LS.[Order]
AND OWS.LineItem = LS.LineItem
AND OWS.Identifier = LS.Identifier
WHERE LS.ProgramStamp_LocalTime =
(Select TOP 1 LS2.ProgramStamp_LocalTime
from table5 AS LS2
Where LS2.[Order] = OWS.Q2CNum
AND LS2.LineItem= OWS.LineItem
AND LS2.Identifier = OWS.Identifier
Order by LS2.ProgramStamp_LocalTime Desc)
AND LS.[Order] = @testVar
AND LS.LineItem = COALESCE('001',OWS.LineItem)
AND LS.Identifier like '%'
---Group by Q2CNum
ORDER BY Q2CNum, LineItem, Identifier DESC
FOR JSON Auto
但查询时间较长
最终更新:
好的,Mike Petri 的解决方案有效。我不得不修补它并尝试围绕它(仍在这样做 - 在此之前我对我的 SQL 技能更有信心)。无论如何,这是我使用的最终代码(上半部分并不重要,我已经编写了该查询,唯一重要的是使用临时 table。我会使用视图,但我有资源限制,所以这是更好的 atm)。真正的魔法从查询的下半部分开始:
IF OBJECT_ID('tempdb..#Temp') IS NOT NULL
BEGIN
DROP TABLE #Temp;
END;
SELECT OWS.Q2CNum
,OWS.LineItem
,OWS.Identifier
,OWS.ProductType
,OWS.Workstation
,OWS.Calculation
,OWS.UnitOfMeasure
,OWS.CurrentStatus
,LS.Location
,LS.ProgramStamp_LocalTime
INTO #Temp
FROM table1 AS OWS
INNER JOIN table2 AS LS ON OWS.Q2CNum = LS.[Order]
AND OWS.LineItem = LS.LineItem
AND OWS.Identifier = LS.Identifier
WHERE LS.ProgramStamp_LocalTime = (
SELECT TOP 1
LS2.ProgramStamp_LocalTime
FROM talbe3 AS LS2
WHERE LS2.[Order] = OWS.Q2CNum
AND LS2.LineItem = OWS.LineItem
AND LS2.Identifier = OWS.Identifier
ORDER BY
LS2.ProgramStamp_LocalTime DESC
)
AND LS.[Order] = @testVar
AND LS.LineItem = COALESCE('001', OWS.LineItem)
AND LS.Identifier LIKE '%';
----REAL MAGIC HAPPENS HERE
SELECT t.Q2CNum
,(
SELECT DISTINCT(t2.LineItem)
,(
SELECT DISTINCT(t3.Identifier)
,t3.Location
,t3.ProgramStamp_LocalTime
,(
SELECT t4.Workstation
,t4.ProductType
,t4.Calculation
,t4.UnitOfMeasure
,t4.CurrentStatus
FROM #Temp AS t4
WHERE t3.Q2CNum = t4.Q2CNum and t3.LineItem = t4.LineItem and t3.Identifier = t4.Identifier
FOR JSON PATH
) AS Workstations
FROM #Temp AS t3
WHERE t3.Q2CNum = t2.Q2CNum and t2.LineItem = t3.LineItem
FOR JSON PATH
) AS Identifiers
FROM #Temp AS t2
WHERE t.Q2CNum = t2.Q2CNum
FOR JSON PATH
) AS LineItems
FROM (
SELECT DISTINCT
Q2CNum
FROM #Temp
) AS t
FOR JSON AUTO;
DROP TABLE #Temp;
欢迎所有批评(我想知道的一件事是过滤(使用 Where 子句)同心 SQL 选择的正确方法,即 table t4 应该过滤到 table t3(它是直接的层次父级?)还是我也应该向 t4 和 t2 添加约束?还是 t4 和 t?
我使用“FOR JSON PATH”作为列表
和“FOR JSON PATH,WITHOUT_ARRAY_WRAPPER”对于 Item
看看这是否能让你们更亲近。
由于您涉及连接,因此引用 inner/outer 查询会变得很冒险。您可以将基本查询设为 VIEW,并替换 #Temp 引用,或者使用下面的代码将其存储在临时 table 中,然后通过内部查询引用外部 table 以获取您想要的分组。
IF OBJECT_ID('tempdb..#Temp') IS NOT NULL
BEGIN
DROP TABLE #Temp;
END;
SELECT OWS.Q2CNum
,OWS.LineItem
,OWS.Identifier
,OWS.ProductType
,OWS.Workstation
,OWS.Calculation
,OWS.UnitOfMeasure
,OWS.CurrentStatus
,LS.Location
,LS.ProgramStamp_LocalTime
INTO #Temp
FROM table1 AS OWS
INNER JOIN table2 AS LS ON OWS.Q2CNum = LS.[Order]
AND OWS.LineItem = LS.LineItem
AND OWS.Identifier = LS.Identifier
WHERE LS.ProgramStamp_LocalTime = (
SELECT TOP 1
LS2.ProgramStamp_LocalTime
FROM dbo.view_Location_Stamps_Local AS LS2
WHERE LS2.[Order] = OWS.Q2CNum
AND LS2.LineItem = OWS.LineItem
AND LS2.Identifier = OWS.Identifier
ORDER BY
LS2.ProgramStamp_LocalTime DESC
)
AND LS.[Order] = @testVar
AND LS.LineItem = COALESCE('001', OWS.LineItem)
AND LS.Identifier LIKE '%';
SELECT t.Q2CNum
,(
SELECT t2.LineItem
,(
SELECT t2.Identifier AS value
,t2.ProductType
,t2.Workstation
,t2.Calculation
,t2.UnitOfMeasure
,t2.CurrentStatus
,t2.Location
,t2.ProgramStamp_LocalTime
FOR JSON PATH
) AS Identifiers
FROM #Temp AS t2
WHERE t.Q2CNum = t2.Q2CNum
FOR JSON PATH, WITHOUT_ARRAY_WRAPPER
) AS LineItems
FROM (
SELECT DISTINCT
Q2CNum
FROM #Temp
) AS t
FOR JSON AUTO;
DROP TABLE #Temp;
一直在尝试进行 SQL 查询并输出完美的 JSON 但我 运行 遇到了问题。查询仅涉及 tables,当我使用“For JSON Auto”时,它会生成一个平面对象数组:enter image description here
但是存在层级关系:
Q2C号--- 订单项---- 标识符
我尝试使用“For JSON Path”,但它只构建每个 json 对象(例如,它不会聚合其父 LineItem 下的所有标识符)。
我已经通过将 table 连接到自身来让它看起来像这样(相同的查询只是额外的连接,“For JSON Path Auto”似乎喜欢这样)和它看起来更像这样:enter image description here
哪个好。问题是查询花费的时间几乎是原来的 20 倍(2 秒对 20 秒)。
可能是我的self join写的不好,或者join得到这些结果效率低下。
无论如何,如果有人知道如何做到这一点,请告诉我(不能分享太多,我相信你注意到了图像上的色块)。
更新:
这是查询的图片 enter image description here。问题是我得到一个平面 JSON (只是一个对象数组)。
Select OWS.Q2CNum,
OWS.LineItem,
OWS.Identifier,
OWS.ProductType,
OWS.Workstation,
OWS.Calculation,
OWS.UnitOfMeasure,
OWS.CurrentStatus,
LS.Location,
LS.ProgramStamp_LocalTime
FROM table1 AS OWS
INNER JOIN table2 AS LS
ON OWS.Q2CNum = LS.[Order]
AND OWS.LineItem = LS.LineItem
AND OWS.Identifier = LS.Identifier
WHERE LS.ProgramStamp_LocalTime =
(Select TOP 1 LS2.ProgramStamp_LocalTime
from dbo.view_Location_Stamps_Local AS LS2
Where LS2.[Order] = OWS.Q2CNum
AND LS2.LineItem= OWS.LineItem
AND LS2.Identifier = OWS.Identifier
Order by LS2.ProgramStamp_LocalTime Desc)
AND LS.[Order] = @testVar
AND LS.LineItem = COALESCE('001',OWS.LineItem)
AND LS.Identifier like '%'
---Group by Q2CNum
ORDER BY Q2CNum, LineItem, Identifier DESC
FOR JSON Auto
但我需要它是分层的:
{
Q2CNum: value,
LineItems: [{
LineItem: value,
Identifiers: [{
identifier: value,
etc...
}],
}],
}
更新 2:
如果我运行这个查询我得到更多我想要的:
Select Q2C.Q2CNum,
Li.LineItem ,
OWS.Identifier,
OWS.ProductType,
OWS.Workstation,
OWS.Calculation,
OWS.UnitOfMeasure,
OWS.CurrentStatus,
LS.Location,
LS.ProgramStamp_LocalTime
FROM table1 AS OWS
INNER JOIN table2 AS Q2C
ON Q2C.Q2CNum = OWS.Q2CNum and Q2C.LineItem = OWS.LineItem and Q2C.Identifier = OWS.Identifier and Q2C.Workstation = OWS.Workstation
INNER JOIN table3 AS Li
ON Li.Q2CNum = OWS.Q2CNum and Li.LineItem = OWS.LineItem and Li.Identifier = OWS.Identifier and Li.Workstation = OWS.Workstation
INNER JOIN table4 AS LS
ON OWS.Q2CNum = LS.[Order]
AND OWS.LineItem = LS.LineItem
AND OWS.Identifier = LS.Identifier
WHERE LS.ProgramStamp_LocalTime =
(Select TOP 1 LS2.ProgramStamp_LocalTime
from table5 AS LS2
Where LS2.[Order] = OWS.Q2CNum
AND LS2.LineItem= OWS.LineItem
AND LS2.Identifier = OWS.Identifier
Order by LS2.ProgramStamp_LocalTime Desc)
AND LS.[Order] = @testVar
AND LS.LineItem = COALESCE('001',OWS.LineItem)
AND LS.Identifier like '%'
---Group by Q2CNum
ORDER BY Q2CNum, LineItem, Identifier DESC
FOR JSON Auto
但查询时间较长
最终更新:
好的,Mike Petri 的解决方案有效。我不得不修补它并尝试围绕它(仍在这样做 - 在此之前我对我的 SQL 技能更有信心)。无论如何,这是我使用的最终代码(上半部分并不重要,我已经编写了该查询,唯一重要的是使用临时 table。我会使用视图,但我有资源限制,所以这是更好的 atm)。真正的魔法从查询的下半部分开始:
IF OBJECT_ID('tempdb..#Temp') IS NOT NULL
BEGIN
DROP TABLE #Temp;
END;
SELECT OWS.Q2CNum
,OWS.LineItem
,OWS.Identifier
,OWS.ProductType
,OWS.Workstation
,OWS.Calculation
,OWS.UnitOfMeasure
,OWS.CurrentStatus
,LS.Location
,LS.ProgramStamp_LocalTime
INTO #Temp
FROM table1 AS OWS
INNER JOIN table2 AS LS ON OWS.Q2CNum = LS.[Order]
AND OWS.LineItem = LS.LineItem
AND OWS.Identifier = LS.Identifier
WHERE LS.ProgramStamp_LocalTime = (
SELECT TOP 1
LS2.ProgramStamp_LocalTime
FROM talbe3 AS LS2
WHERE LS2.[Order] = OWS.Q2CNum
AND LS2.LineItem = OWS.LineItem
AND LS2.Identifier = OWS.Identifier
ORDER BY
LS2.ProgramStamp_LocalTime DESC
)
AND LS.[Order] = @testVar
AND LS.LineItem = COALESCE('001', OWS.LineItem)
AND LS.Identifier LIKE '%';
----REAL MAGIC HAPPENS HERE
SELECT t.Q2CNum
,(
SELECT DISTINCT(t2.LineItem)
,(
SELECT DISTINCT(t3.Identifier)
,t3.Location
,t3.ProgramStamp_LocalTime
,(
SELECT t4.Workstation
,t4.ProductType
,t4.Calculation
,t4.UnitOfMeasure
,t4.CurrentStatus
FROM #Temp AS t4
WHERE t3.Q2CNum = t4.Q2CNum and t3.LineItem = t4.LineItem and t3.Identifier = t4.Identifier
FOR JSON PATH
) AS Workstations
FROM #Temp AS t3
WHERE t3.Q2CNum = t2.Q2CNum and t2.LineItem = t3.LineItem
FOR JSON PATH
) AS Identifiers
FROM #Temp AS t2
WHERE t.Q2CNum = t2.Q2CNum
FOR JSON PATH
) AS LineItems
FROM (
SELECT DISTINCT
Q2CNum
FROM #Temp
) AS t
FOR JSON AUTO;
DROP TABLE #Temp;
欢迎所有批评(我想知道的一件事是过滤(使用 Where 子句)同心 SQL 选择的正确方法,即 table t4 应该过滤到 table t3(它是直接的层次父级?)还是我也应该向 t4 和 t2 添加约束?还是 t4 和 t?
我使用“FOR JSON PATH”作为列表 和“FOR JSON PATH,WITHOUT_ARRAY_WRAPPER”对于 Item
看看这是否能让你们更亲近。 由于您涉及连接,因此引用 inner/outer 查询会变得很冒险。您可以将基本查询设为 VIEW,并替换 #Temp 引用,或者使用下面的代码将其存储在临时 table 中,然后通过内部查询引用外部 table 以获取您想要的分组。
IF OBJECT_ID('tempdb..#Temp') IS NOT NULL
BEGIN
DROP TABLE #Temp;
END;
SELECT OWS.Q2CNum
,OWS.LineItem
,OWS.Identifier
,OWS.ProductType
,OWS.Workstation
,OWS.Calculation
,OWS.UnitOfMeasure
,OWS.CurrentStatus
,LS.Location
,LS.ProgramStamp_LocalTime
INTO #Temp
FROM table1 AS OWS
INNER JOIN table2 AS LS ON OWS.Q2CNum = LS.[Order]
AND OWS.LineItem = LS.LineItem
AND OWS.Identifier = LS.Identifier
WHERE LS.ProgramStamp_LocalTime = (
SELECT TOP 1
LS2.ProgramStamp_LocalTime
FROM dbo.view_Location_Stamps_Local AS LS2
WHERE LS2.[Order] = OWS.Q2CNum
AND LS2.LineItem = OWS.LineItem
AND LS2.Identifier = OWS.Identifier
ORDER BY
LS2.ProgramStamp_LocalTime DESC
)
AND LS.[Order] = @testVar
AND LS.LineItem = COALESCE('001', OWS.LineItem)
AND LS.Identifier LIKE '%';
SELECT t.Q2CNum
,(
SELECT t2.LineItem
,(
SELECT t2.Identifier AS value
,t2.ProductType
,t2.Workstation
,t2.Calculation
,t2.UnitOfMeasure
,t2.CurrentStatus
,t2.Location
,t2.ProgramStamp_LocalTime
FOR JSON PATH
) AS Identifiers
FROM #Temp AS t2
WHERE t.Q2CNum = t2.Q2CNum
FOR JSON PATH, WITHOUT_ARRAY_WRAPPER
) AS LineItems
FROM (
SELECT DISTINCT
Q2CNum
FROM #Temp
) AS t
FOR JSON AUTO;
DROP TABLE #Temp;