使用FOR JSON PATH创建嵌套的JSON数组

时间:2017-12-14 13:11:16

标签: json sql-server tsql sql-server-2016

我需要从一个查询创建一个JSON输出,该查询使用具有一对多关系的两个表之间的内连接 我希望将辅助表的值嵌套为主表的数组属性。

考虑以下示例:

DECLARE @Persons AS TABLE
(
    person_id int primary key,
    person_name varchar(20)
)

DECLARE @Pets AS TABLE
(
    pet_owner int, -- in real tables, this would be a foreign key
    pet_id int  primary key,
    pet_name varchar(10)
)

INSERT INTO @Persons (person_id, person_name) VALUES
(2, 'Jack'),
(3, 'Jill')

INSERT INTO @Pets (pet_owner, pet_id, pet_name) VALUES
(2, 4, 'Bug'),
(2, 5, 'Feature'),
(3, 6, 'Fiend')

并查询:

DECLARE @Result as varchar(max)
SET @Result =
(
SELECT  person_id as [person.id],
        person_name as [person.name],
        pet_id as [person.pet.id],
        pet_name as [person.pet.name]
FROM @Persons 
JOIN @Pets ON person_id = pet_owner
FOR JSON PATH, ROOT('pet owners')
)

PRINT @Result

这将打印以下JSON:

{
    "pet owners":
    [
    {"person":{"id":2,"name":"Jack","pet":{"id":4,"name":"Bug"}}},
    {"person":{"id":2,"name":"Jack","pet":{"id":5,"name":"Feature"}}},
    {"person":{"id":3,"name":"Jill","pet":{"id":6,"name":"Fiend"}}}
    ]
}

但是,我想将宠物数据作为所有者数据中的数组:

{
    "pet owners":
    [
        {
            "person":
            {
                "id":2,"name":"Jack","pet":
                [
                    {"id":4,"name":"Bug"},
                    {"id":5,"name":"Feature"}
                ]
            }
        },
        {
            "person":
            {
                "id":3,"name":"Jill","pet":
                {"id":6,"name":"Fiend"}
            }
        }
    ]
}

我该怎么做?

3 个答案:

答案 0 :(得分:9)

您可以使用以下查询:

SELECT pr.person_id AS [person.id], pr.person_name AS [person.name],
    (
        SELECT pt.pet_id AS id, pt.pet_name AS name 
        FROM @Pets pt WHERE pt.pet_owner=pr.person_id 
        FOR JSON PATH
    ) AS [person.pet]
FROM @Persons pr 
FOR JSON PATH, ROOT('pet owners')

有关详细信息,请参阅https://blogs.msdn.microsoft.com/sqlserverstorageengine/2015/10/09/returning-child-rows-formatted-as-json-in-sql-server-queries/

答案 1 :(得分:0)

使用深度嵌套的数组,子查询很快就无法处理:

d = {1: 2,
2:3,
3: 4,
5:6,
6:7}

我创建了一个关系(非json)视图,该视图连接了我的所有表,并在列别名中嵌入了json结构,就像 for json path 一样。但是我也有[]表示json节点是一个数组。像这样:

d= { 1: 4 , 2 :4 , 3:4 , 5:7 , 6:7}

我编写了一个存储过程,该过程在非json视图中创建一个json视图,该视图解析关系视图的列名并使json变得漂亮。见下文。用您的关系视图的名称调用它,它会创建一个视图。尚未经过全面测试,但对我有用。唯一需要说明的是,表需要具有称为 id的 id 列。它使用 string_agg() json_array() sql版本需要非常新。它还设置为在根目录中返回一个数组。需要调整以返回对象。

select id,foo, (select id, bar, (select ... for json path) things, 
(select...) more_things) yet_more, select(...) blarg

答案 2 :(得分:0)

我按照@Razvan Socol 制作了以下 json 格式。

JSON

  [
      "domain_nm": "transactions",
      "tables": [
        {
          "tableName": "transactions_details",
          cols: [
            {
              "col_nm": "audit_transactions_details_guid",
              "col_data_typ": "string"
            }
          ]
        }
      ]
    ]

SQL

select outer1.DOMAIN_NM as domain_nm,
    (select inner2.TBL_NM as tableName,
            (select inner1.COL_NM as col_nm, inner1.COL_DATA_TYP as col_data_typ
            from ONBD_MTDT.CDM_TBL inner1
            where inner1.TBL_NM=inner2.TBL_NM
            FOR JSON PATH ) as cols
    from ONBD_MTDT.CDM_TBL inner2 
    where inner2.DOMAIN_NM=outer1.DOMAIN_NM
    group by inner2.DOMAIN_NM,inner2.TBL_NM
    FOR JSON PATH ) as tables
from ONBD_MTDT.CDM_TBL outer1 
group by outer1.DOMAIN_NM
FOR JSON PATH