如何使用 FOR JSON PATH 将包含键/值对的表查询到 JSON 对象中?

Cha*_*ert 5 sql-server sql-server-2016

我有一个资产表和一个属性表,其中属性是简单的键/值对。

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')
Run Code Online (Sandbox Code Playgroud)

我想编写一个按资产分组的查询,并包含一个包含所有属性的 JSON 表示形式的列。例如:

AssetID      Attributes
------------ -----------------------------------------------
1            {"height":"100px","width":"200px"}
Run Code Online (Sandbox Code Playgroud)

如何编写查询以使属性名称值成为结果 JSON 对象中的键?当我使用 FOR JSON PATH 时,键是列名称:

AssetID      Attributes
------------ -----------------------------------------------
1            {"height":"100px","width":"200px"}
Run Code Online (Sandbox Code Playgroud)

返回...

AssetID      Attributes
------------ -----------------------------------------------
1            [{"Name":"height","Val":"100px"},{"Name":"width","Val":"200px"}]
Run Code Online (Sandbox Code Playgroud)

Pரத*_*ீப் 2

不确定是否有任何本机JSON方法来获取列数据,KeyJSON. Alias名称将被转换为 中的键值JSON

所以这是我的尝试

您需要对数据进行透视以获得所需的键值对格式JSON

如果key是静态的那么

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
Run Code Online (Sandbox Code Playgroud)

WITHOUT_ARRAY_WRAPPER是默认删除子句输出周围JSON的方括号FOR JSON

结果:

+---------+--------------------------------------+
| AssetID |              Attributes              |
+---------+--------------------------------------+
|       1 | [{"height":"100px","width":"200px"}] |
+---------+--------------------------------------+
Run Code Online (Sandbox Code Playgroud)

由于键可以是任何我们需要使用动态查询来透视数据的内容

对于演示,我已将表变量更改为临时表

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') 
Run Code Online (Sandbox Code Playgroud)

结果:

+---------+--------------------------------------+
| AssetID |              Attributes              |
+---------+--------------------------------------+
|       1 | [{"height":"100px","width":"200px"}] |
+---------+--------------------------------------+
Run Code Online (Sandbox Code Playgroud)