SQL 到 JSON - 将结果分组到 JSON 数组中

Ber*_*682 5 sql arrays json sql-server-2017

我正在尝试提出一个 SQL 解决方案来安排输出以匹配预期的 JSON 格式。

我有一些简单的 SQL 来强调问题的来源;

SELECT TOP 1 'Surname' AS 'name.family'
,'Forename, Middle Name' AS 'name.given'
,'Title' AS 'name.prefix'
,getDATE() AS 'birthdate'
,'F' AS 'gender'
,'Yes' AS 'active'
,'work' AS 'telecom.use'
,'phone' AS 'telecom.system'
,'12344556' AS 'telecom.value'
FROM tblCustomer
FOR json path
Run Code Online (Sandbox Code Playgroud)

这将返回 JSON 为;

[
{
    "name": {
        "family": "Surname",
        "given": "Forename, Middle Name",
        "prefix": "Title"
    },
    "birthdate": "2019-02-13T12:06:45.490",
    "gender": "F",
    "active": "Yes",
    "telecom": {
        "use": "work",
        "system": "phone",
        "value": "12344556"
    }
}
]
Run Code Online (Sandbox Code Playgroud)

我需要的是将额外的对象添加到“telecome”数组中,这样它就会显示为;

[
{
    "name": {
        "family": "Surname",
        "given": "Forename, Middle Name",
        "prefix": "Title"
    },
    "birthdate": "2019-02-13T12:06:45.490",
    "gender": "F",
    "active": "Yes",
    "telecom": {
        "use": "work",
        "system": "phone",
        "value": "12344556"
    },
    {
        "use": "work",
        "system": "home",
        "value": "12344556"
    },
}
]
Run Code Online (Sandbox Code Playgroud)

我错误地假设我可以继续添加到我的 SQL 中,如下所示;

SELECT TOP 1 'Surname' AS 'name.family'
,'Forename, Middle Name' AS 'name.given'
,'Title' AS 'name.prefix'
,getDATE() AS 'birthdate'
,'F' AS 'gender'
,'Yes' AS 'active'
,'work' AS 'telecom.use'
,'phone' AS 'telecom.system'
,'12344556' AS 'telecom.value'
,'home' AS 'telecom.use'
FROM tblCustomer
FOR json path
Run Code Online (Sandbox Code Playgroud)

但是它会按照我的命名缩进嵌套项目;

由于与其他列名或别名冲突,无法在 JSON 输出中生成属性“telecom.use”。对 SELECT 列表中的每一列使用不同的名称和别名。

有没有办法用 SQL 处理这种嵌套,还是我需要为 JSON 查询创建单独的并合并它们?

谢谢

使用 @@Version Microsoft SQL Server 2017 (RTM) - 14.0.1000.169 (X64) 2017 年 8 月 22 日 17:04:49 版权所有 (C) 2017 Microsoft Corporation Express Edition(64 位),Windows Server 2012 R2 Datacenter 6.3(Build 9600) :)(管理程序)

对该问题的小编辑以使用动态值而不是强制静态成员。

SELECT TOP 1 'Surname' AS 'name.family'
    ,'Forename, Middle Name' AS 'name.given'
    ,'Title' AS 'name.prefix'
    ,getDATE() AS 'birthdate'
    ,'F' AS 'gender'
    ,'Yes' AS 'active'
    ,'work' AS 'telecom.use'
    ,'phone' AS 'telecom.system'
    ,customerWorkTelephone AS 'telecom.value'
    ,'home' AS 'telecom.use'
    ,'phone' AS 'telecom.system'
    ,customerHomeTelephone AS 'telecom.value'
FROM tblCustomer
FOR json path
Run Code Online (Sandbox Code Playgroud)

“值”项将从 tblCustomer 表中的列中获取。我试图在下面的回复中做得很好,但无法在子查询中获得完全正确的逻辑。

再次感谢

进一步编辑

我有一些 SQL 为我提供了我期望的输出,但是我不确定它可能是最好的,我的方法是否不是最佳的?

SELECT TOP 1 [name.family] = 'Surname'
,[name.given] = 'Forename, Middle Name'
,[name.prefix] = 'Title'
,[birthdate] = GETDATE()
,[gender] = 'F'
,[active] = 'Yes'
,[telecom] = (
    SELECT [use] = V.used
        ,[system] = 'phone'
        ,[value] = CASE V.used
            WHEN 'work'
                THEN cu.customerWorkTelephone
            WHEN 'home'
                THEN cu.customerHomeTelephone
            when 'mobile'
                then cu.customerMobileTelephone
            END
    FROM (
        VALUES ('work')
            ,('home')
            ,('mobile')
        ) AS V(used)

    FOR json path
    )
FROM tblCustomer cu
FOR JSON PATH
Run Code Online (Sandbox Code Playgroud)

EzL*_*zLo 5

使用带有一些硬编码行的子选择:

SELECT TOP 1 
    'Surname' AS 'name.family'
    ,'Forename, Middle Name' AS 'name.given'
    ,'Title' AS 'name.prefix'
    ,getDATE() AS 'birthdate'
    ,'F' AS 'gender'
    ,'Yes' AS 'active'
    ,'telecom' = (
            SELECT
                'work' AS 'use'
                ,V.system AS 'system'
                ,'12344556' AS 'value'
            FROM
                (VALUES 
                    ('phone'),
                    ('home')) AS V(system)
            FOR JSON PATH)
FROM tblCustomer
FOR JSON PATH
Run Code Online (Sandbox Code Playgroud)

telecom.请注意子查询内缺少前缀。

结果(没有表格参考):

[
    {
        "name": {
            "family": "Surname",
            "given": "Forename, Middle Name",
            "prefix": "Title"
        },
        "birthdate": "2019-02-13T12:53:08.400",
        "gender": "F",
        "active": "Yes",
        "telecom": [
            {
                "use": "work",
                "system": "phone",
                "value": "12344556"
            },
            {
                "use": "work",
                "system": "home",
                "value": "12344556"
            }
        ]
    }
]
Run Code Online (Sandbox Code Playgroud)

PD:特别是对于 SQL Server,我发现使用左侧的别名更具可读性:

SELECT TOP 1 
    [name.family] = 'Surname',
    [name.given] = 'Forename, Middle Name',
    [name.prefix] = 'Title',

    [birthdate] = GETDATE(),
    [gender] = 'F',
    [active] = 'Yes',

    [telecom] = (
        SELECT
            [use] = 'work',
            [system] = V.system,
            [value] = '12344556'
        FROM
            (VALUES ('phone'), ('home')) AS V(system)
        FOR JSON 
            PATH)
FROM tblCustomer
FOR JSON 
    PATH
Run Code Online (Sandbox Code Playgroud)