SQL to JSON - Grouping Results into JSON Array

倾然丶 夕夏残阳落幕 提交于 2020-02-28 07:20:08

问题


I am trying to come up with an SQL solution for arranging output to match an expected JSON format.

I have some simple SQL to highlight where the issue is coming from;

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

Which will return JSON as;

[
{
    "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"
    }
}
]

What I need to is to add extra objects into the "telecome" array so it would appear as;

[
{
    "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"
    },
}
]

I have incorrectly assume I could keep adding to my SQL as follows;

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

And it would nest the items as per my naming indents however;

Property 'telecom.use' cannot be generated in JSON output due to a conflict with another column name or alias. Use different names and aliases for each column in SELECT list.

Is there a way to handle this nesting with SQL or will I need to create separate for JSON queries and merge them?

Thanks

Using @@Version Microsoft SQL Server 2017 (RTM) - 14.0.1000.169 (X64) Aug 22 2017 17:04:49 Copyright (C) 2017 Microsoft Corporation Express Edition (64-bit) on Windows Server 2012 R2 Datacenter 6.3 (Build 9600: ) (Hypervisor)

Small edit to the question to use dynamic values rather than forced static members.

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

The "value" items will be taken from columns within the tblCustomer table. I've tried to make good on the responses below but cant get the logic quite correct in the sub query.

Thanks again

FURTHER EDIT

I have some SQL that is giving me the output I expect however I am not sure its the best that it could be, is my approach less than optimal?

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

回答1:


Using a subselect with a few hard-coded rows:

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

Note the lack of the telecom. prefix inside the subquery.

Results (without the table reference):

[
    {
        "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"
            }
        ]
    }
]

PD: Particularly for SQL Server I find using the alias on the left side more readable:

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



回答2:


SELECT  
       EMP.ID,
       EMP.NAME,
       DEP.NAME

FROM EMPLOYEE EMP INNER JOIN DEPARTMENT DEP ON EMP.DEPID=DEP.DEPID
WHERE EMP.SALARY>1000
FOR JSON PATH


来源:https://stackoverflow.com/questions/54669930/sql-to-json-grouping-results-into-json-array

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!