3

我有一个包含 5 列的非常简单的表,该表一次只能保存 1 条记录。我将从记录中生成一个 JSON 字符串并将其发送到端点。

这就是 JSON 字符串的格式。如您所见,它包含 2 个“根”,这让我很难获得正确的格式

{
    "fields": [
        {
            "fieldName": "Brand",
            "values": [
                "FORD"
            ]
        },
        {
            "fieldName": "Engine",
            "values": [
                "V12"
            ]
        },
        {
            "fieldName": "Location",
            "values": [
                "Monaco"
            ]
        }
    ],
    "categories": [
        {
            "fieldName": "Colour",
            "values": [
                [
                    {
                        "name": "Blue"
                    }
                ]
            ]
        },
        {
            "fieldName": "Interior",
            "values": [
                [
                    {
                        "name": "Red"
                    }
                ]
            ]
        }
    ]
}

这是我的包含 5 列的表

SQL 表

我设法创建了 2 个单独的 SQL 查询来获取 JSON 字符串。但我无法弄清楚如何在一次选择中做到这一点。

SELECT ( 
    SELECT X.* FROM (
    SELECT CASE WHEN CarName IS NOT NULL THEN 'Brand' ELSE NULL END AS fieldName,
           CarName AS [value]
    FROM [dbo].[JSONBODY] 
    UNION
    SELECT CASE WHEN Engine IS NOT NULL THEN 'Engine' ELSE NULL END AS fieldName, 
           Engine AS [value] 
    FROM [dbo].[JSONBODY] 
    UNION
    SELECT CASE WHEN [location] IS NOT NULL THEN 'Location' ELSE NULL END AS fieldName, 
           [Location] AS [value]
    FROM [dbo].[JSONBODY] ) X
FOR JSON PATH, ROOT('fields'))
    
SELECT (
    SELECT Y.* FROM (
    SELECT CASE WHEN Colour IS NOT NULL THEN 'Colour' ELSE NULL END AS fieldName,
           JSON_QUERY('[["' + Colour + '"]]') AS 'value.name'
    FROM [dbo].[JSONBODY]  
    UNION
    SELECT CASE WHEN Interior IS NOT NULL THEN 'Interior' ELSE NULL END AS fieldName, 
           JSON_QUERY('[["' + Interior + '"]]') AS 'value.name'
    FROM [dbo].[JSONBODY]) Y 
FOR JSON PATH, ROOT('categories'))

这是 2 个 JSON 字符串:

{"fields":[{"fieldName":"Brand","value":"Ford"},{"fieldName":"Engine","value":"V6"},{"fieldName":"Location","value":"Boston"}]}
{"categories":[{"fieldName":"Colour","value":{"name":[["Blue"]]}},{"fieldName":"Interior","value":{"name":[["Black"]]}}]}

问题一:
是否可以通过单个 SQL Select 创建 JSON 字符串?我该怎么做?

问题 2:
如果列值为 NULL,它会自动从 JSON 字符串中排除。但是我必须将 ' 添加fieldName到选择中,并希望如果相应的字段为 NULL,它将从 JSON 字符串中排除它。但是,它会{}在 JSON 字符串中创建一个 , 。这在调用端点时不被接受。那么当列值为NULL时还有另一种方法吗?之后我当然可以从 JSON 字符串中删除它....

希望以上内容有意义

4

1 回答 1

1

做一个单一的SELECT,你可以UNION ALL把两个结果放在一起

您可以取消透视这些值,然后检查它们是否为空值。

不幸的是,SQL Server 没有JSON_AGG,因此您必须使用STRING_AGGandSTRING_ESCAPE

SELECT
  v.fieldName,
  value = JSON_QUERY('[' + STRING_AGG('"' + STRING_ESCAPE(v.value, 'json') + '"', ',') + ']')
FROM [dbo].[JSONBODY] jb
CROSS APPLY (VALUES
    ('Brand',    jb.Brand),
    ('Engine',   jb.Engine),
    ('Location', jb.Location)
) v(fieldName, value)
GROUP BY
  v.fieldName
FOR JSON PATH, ROOT('fields');

UNION ALL

SELECT
  v.fieldName,
  [value.name] = JSON_QUERY('[[' + STRING_AGG('"' + STRING_ESCAPE(v.value, 'json') + '"', ',') + ']]')
FROM [dbo].[JSONBODY] jb
CROSS APPLY (VALUES
    ('Colour',   jb.Colour),
    ('Interior', jb.Interior)
) v(fieldName, value)
GROUP BY
  v.fieldName
FOR JSON PATH, ROOT('categories');

如果你知道你只会有一行,你可以通过删除GROUP BY

SELECT (
SELECT
  v.fieldName,
  value = JSON_QUERY('["' + STRING_ESCAPE(v.value, 'json') + '"]')
FROM [dbo].[JSONBODY] jb
CROSS APPLY (VALUES
    ('Brand',    jb.Brand),
    ('Engine',   jb.Engine),
    ('Location', jb.Location)
) v(fieldName, value)
WHERE v.value IS NOT NULL
FOR JSON PATH, ROOT('fields')
)

UNION ALL

SELECT (
SELECT
  v.fieldName,
  [value.name] = JSON_QUERY('[["' + STRING_ESCAPE(v.value, 'json') + '"]]')
FROM [dbo].[JSONBODY] jb
CROSS APPLY (VALUES
    ('Colour',   jb.Colour),
    ('Interior', jb.Interior)
) v(fieldName, value)
WHERE v.value IS NOT NULL
FOR JSON PATH, ROOT('categories')
);

db<>小提琴

于 2021-12-30T21:05:14.860 回答