我有一个Asset表和一个Attributes表,其中的属性是简单的键/值对。
DECLARE @Asset TABLE(AssetID INT)
INSERT @Asset VALUES (1)
DECLARE @Att TABLE (AssetID INT, Name NVARCHAR(100), Val NVARCHAR(100))
INSERT @Att VALUES (1, 'height', '100px'), (1, 'width', '200px')
我想编写一个按资产分组的查询,并包含一个包含所有属性的JSON表示的列。例如:
AssetID Attributes
------------ -----------------------------------------------
1 {"height":"100px","width":"200px"}
如何编写查询以便属性名称值成为生成的JSON对象中的键?当我使用FOR JSON PATH时,键是列名:
SELECT
AssetID,
(
SELECT Name, Val
FROM @Att att
WHERE att.AssetID = asset.AssetID
FOR JSON PATH
) Attributes
FROM @Asset asset
返回......
AssetID Attributes
------------ -----------------------------------------------
1 [{"Name":"height","Val":"100px"},{"Name":"width","Val":"200px"}]
答案 0 :(得分:1)
我不确定在[{1}}中将列数据作为JSON
获取的任何原生Key
方法。 JSON
名称将转换为Alias
中的键值。
所以这是我的尝试
您需要透过数据来获取JSON
如果JSON
是静态的,那么
key
<{1}} SELECT
AssetID,
(
SELECT Max(CASE WHEN NAME = 'height' THEN Val END) AS height,
Max(CASE WHEN NAME = 'width' THEN Val END) AS width
FROM @Att att
WHERE att.AssetID = asset.AssetID
FOR JSON path, WITHOUT_ARRAY_WRAPPER
) Attributes
FROM @Asset asset
子句JSON
输出的方括号
结果:
FOR JSON
由于密钥可以是我们需要使用动态查询来转动数据的任何东西
对于演示,我已将表变量更改为临时表
+---------+--------------------------------------+
| AssetID | Attributes |
+---------+--------------------------------------+
| 1 | [{"height":"100px","width":"200px"}] |
+---------+--------------------------------------+
<强>结果:强>
CREATE TABLE #Asset
(
AssetID INT
)
INSERT #Asset
VALUES (1)
CREATE TABLE #Att
(
AssetID INT,
NAME NVARCHAR(100),
Val NVARCHAR(100)
)
INSERT #Att
VALUES (1,'height','100px'),
(1,'width','200px')
DECLARE @col VARCHAR(8000)= ''
SET @col = (SELECT ',Max(CASE WHEN NAME = ''' + NAME
+ ''' THEN Val END) as ' + Quotename(NAME)
FROM #Att
FOR xml path(''))
SET @col = Stuff(@col, 1, 1, '')
EXEC ('
SELECT
AssetID,
(
SELECT '+@col+'
FROM #Att att
WHERE att.AssetID = asset.AssetID
FOR JSON path, WITHOUT_ARRAY_WRAPPER
) Attributes
FROM #Asset asset')
答案 1 :(得分:0)
我知道您的原始问题要求使用FOR XML
的解决方案,但您还说您想要一个解决方案:
您是否考虑过&#34; stuff方法&#34;完成此操作,使用STUFF
函数和FOR XML
?
我已经成功使用了一段时间,但在某些用例中,您可能会遇到性能问题。
它不需要透视,不需要使用动态查询,并且每行允许不同数量的键/值对。
以上是使用上面示例完成的操作...
WITH
ASSETS AS
(
SELECT 1 ASSETID, 'height' NAME, '100px' VALUE UNION
SELECT 1 ASSETID, 'width' NAME, '200px' VALUE UNION
SELECT 2 ASSETID, 'height' NAME, '900px' VALUE UNION
SELECT 2 ASSETID, 'width' NAME, '1800px' VALUE UNION
SELECT 2 ASSETID, 'randomKey' NAME, 'ABC123' VALUE
)
SELECT
A.ASSETID,
'[' + STUFF
(
(
SELECT
N',{"name":"' + B.NAME + '","value":"' + B.VALUE + '"}'
FROM
ASSETS B
WHERE
A.ASSETID = B.ASSETID
FOR
XML PATH(N''),
TYPE
).value(N'.[1]', N'nvarchar(max)'), 1, 1, N'' --the last param is blank... it replaces the leading comma with ''
) + ']' VALUE
FROM
ASSETS A
GROUP BY
ASSETID
输出:
ASSETID VALUE
1 [{"name":"height","value":"100px"},{"name":"width","value":"200px"}]
2 [{"name":"height","value":"900px"},{"name":"width","value":"1800px"},{"name":"randomKey","value":"ABC123"}]
我知道它并不是您最初提出的问题的完美解决方案(因为它不会使用FOR JSON
作为您最初的要求,但这是一种符合您所有其他标准的解决方法
答案 2 :(得分:-1)
你也可以使用一些“假的”json作曲,如下所示:
select [AssetID],
[Attributes] = (
select '{'+STRING_AGG ('"'+[Name]+'":"'+[Val]+'"', ',')+'}'
from @Att
where [AssetID] = [Asset].[AssetID]) from @Asset as [Asset]
上的“创建嵌套JSON结构”示例