【问题标题】:Create json object and aggregate into json array in SqlServer在Sql Server中创建json对象并聚合成json数组
【发布时间】:2020-04-09 15:22:58
【问题描述】:

我在 ORACLE 中有以下查询:

SELECT *
FROM "Supplier" s
OUTER APPLY( 
    SELECT JSON_ARRAYAGG(JSON_OBJECT(p."Id", p."Description", p."Price")) as "Products"
    FROM "Products" p
    WHERE p."SupplierId" = s."Id"
) sp

OUTER APPLY 子查询中,我从我需要的列创建 json,然后将这些对象聚合到 json 数组中。我需要这两个功能,因为有时我只使用其中一个。我想在 SqlServer 中执行相同的操作。这是我目前管理的解决方案:

SELECT *
FROM "Supplier" as s
OUTER APPLY(
    SELECT p."Id", p."Description", p."Price"
    FROM "Products" as p
    WHERE p."SupplierId" = s."Id"
    FOR JSON PATH
) as sp("Products")

问题是 SqlServer 同时执行这两个函数(这是FOR JSON PATH 语句的目的)。所以这是我的问题:

1) 是否可以创建 json 对象而不将其包装到数组中(类似 oracle 的语法)?

2) 是否可以将 json 对象聚合成一个数组?

更新 我正在使用 SqlServer 版本 2019 15.0.2000.5

预期结果(json格式的产品单条记录)

"Products":{
    "Id":"FEB0646B709B45B5A306E10599716F28",
    "Description":"Database Manager",
    "Price":149.99
}

【问题讨论】:

    标签: json sql-server


    【解决方案1】:

    如果我对问题的理解正确,以下陈述是可能的解决方案(当然,它们是基于问题中的示例数据和陈述):

    如何创建单个 JSON 对象:

    如果要生成单个 JSON 对象,则需要对 OUTER APPLY 语句中的每一行使用 FOR JSON PATh 并使用适当的 path 表达式。 JSON_QUERY() 是必需的,因为它返回一个有效的 JSON 并且 FOR JSON 不会转义特殊字符。

    表格:

    CREATE TABLE Supplier (
       Id int,
       Description varchar(50),
       DateStart date
    )
    CREATE TABLE Products (
       Id varchar(5),
       SupplierId int,
       Description varchar(100),
       Price numeric(10, 2)
    )
    INSERT INTO Supplier (Id, Description, DateStart)
    VALUES (1, 'Oracle', '19900505')
    INSERT INTO Products (Id, SupplierId, Description, Price)
    VALUES ('11111', 1, 'Database Manager', 149.99)
    INSERT INTO Products (Id, SupplierId, Description, Price)
    VALUES ('22222', 1, 'Chassi', 249.99)
    

    声明:

    SELECT *
    FROM "Supplier" s
    OUTER APPLY(
        SELECT Products = JSON_QUERY((
           SELECT 
              p."Id" AS 'Product.Id', 
              p."Description" AS 'Product.Description', 
              p."Price" AS 'Product.Price'
           FOR JSON PATH, WITHOUT_ARRAY_WRAPPER
        ))
        FROM "Products" as p
        WHERE p."SupplierId" = s."Id"
    ) sp ("Products")
    

    结果:

    Id  Description DateStart   Products
    1   Oracle      1990-05-05  {"Product":{"Id":"11111","Description":"Database Manager","Price":149.99}}
    1   Oracle      1990-05-05  {"Product":{"Id":"22222","Description":"Chassi","Price":249.99}}
    

    如何将 JSON 对象聚合成数组:

    默认情况下,FOR JSON 创建一个 JSON 数组,其中每一行都有一个 JSON 对象。您只需要设置一个根密钥:

    声明:

    SELECT *
    FROM "Supplier" s
    OUTER APPLY(
        SELECT p."Id", p."Description", p."Price"
        FROM "Products" p
        WHERE p."SupplierId" = s."Id"
        FOR JSON PATH
    ) sp("Products")
    

    结果:

    Id  Description DateStart   Products
    1   Oracle      1990-05-05  [{"Id":"11111","Description":"Database Manager","Price":149.99},{"Id":"22222","Description":"Chassi","Price":249.99}]
    

    【讨论】:

    • 第一个答案很好,但我测试了第二个,这对我来说是不可接受的。我想要一个仅包含聚合行的数组,例如:[{"Id":"11111","Description":"Database Manager","Price":149.99},{"Id":"22222","Description":"Chassi","Price":249.99}] 没有“产品”根。我发现 string_agg 函数可能会有所帮助,但也许还有其他方法可以实现?
    • 这会产生:[{"Products":{"Product":{"Id":"AD071CD2-1F75-4DF5-8CC1-352DC01AB317","Description":"Rack","Price":1450.79000}}},{"Products":{"Product":{"Id":"8E5D1F1B-3932-463E-BACA-661DF5431E95","Description":"Database Manager","Price":149.99000}}}] 所以情况更糟,因为我有一系列产品。
    • @AdamMrozek 第二条语句(来自How to aggregate JSON objects into an array 部分)返回答案的结果。如果我在第一条语句的末尾使用FOR JSON PATH,我就能得到你意想不到的结果。请注意,SQL Server 使用 FOR JSON 生成 JSON 输出,没有像 JSON_ARRAYAGGJSON_OBJECT 这样的函数。如果您选择基于字符串的方法来生成有效的 JSON 输出,STRING_AGG 会有所帮助。我不确定你是否只能使用一个语句(就像 ORACLE 一样)。
    • 好的,你的回答真的很有帮助,下一步我只需要字符串来解析c#。谢谢你的帮助:)
    猜你喜欢
    • 1970-01-01
    • 2021-10-20
    • 1970-01-01
    • 2018-07-03
    • 2020-05-10
    • 1970-01-01
    • 1970-01-01
    • 2016-12-16
    • 2018-06-03
    相关资源
    最近更新 更多