Sql Server - 从聚合构建整数的 json 数组

A_V*_*A_V 5 sql-server json sql-server-2019

我想使用聚合来构建一个简单的单维标量值 JSON 数组,如下面示例中的 LuckyNumbers 数组:

[{
    "id": 1,
    "name": "Josian",
    "LuckyNumbers": [581, 777]
}, {
    "id": 2,
    "name": "Paul",
    "LuckyNumbers": [123551, 5, 646464, 1345, 75, 76]
}, {
    "id": 3,
    "name": "Seasonique",
    "LuckyNumbers": [1]
}]
Run Code Online (Sandbox Code Playgroud)

使用 Postgresql 12,您可以使用本机聚合函数(fiddle)来完成此操作

--Postgresql 12 schema
create table person (   Id int primary key,   name varchar(20) ); 
insert into person values (1,'Josian'), (2,'Paul'), (3,'Seasonique');  
create table LuckyNumbers (PersonId int references person(Id), LuckyNumber int);
insert into LuckyNumbers (PersonId, LuckyNumber) values (1,581), (1,777), (2,123551), (2,5), (2,646464), (2,1345), (2,75), (2,76), (3,1);

--Query to JSON
select
  array_to_json(array_agg(row_to_json(r))) "PersonsNumbers"
from (
    select
      p.id,p.name,json_agg(ln.LuckyNumber) "LuckyNumbers"
    from person as p
      inner join
        LuckyNumbers as ln
        on
          p.id=ln.PersonId
    group by p.id,p.name
  )
  r
Run Code Online (Sandbox Code Playgroud)

这将输出所需的结果,与上面完全相同。

然而,下面的 SqlServer2019 示例需要使用 string_agg (一个字符串函数),然后手动连接数组括号。(小提琴

--Sqlserver 2019 schema creation
create table person (   Id int primary key,   name nvarchar(20) );
insert person values (1,'Josian'), (2,'Paul'), (3,'Seasonique');
create table LuckyNumbers (PersonId int foreign key references person(Id), LuckyNumber int);
insert LuckyNumbers (PersonId, LuckyNumber) values (1,581), (1,777), (2,123551), (2,5), (2,646464), (2,1345), (2,75), (2,76), (3,1); 

--Query to JSON
SELECT p.id
    ,p.NAME
    ,Json_Query('[' + string_agg(ln.LuckyNumber, ',') + ']') 'LuckyNumbers'
FROM person p
INNER JOIN LuckyNumbers ln ON p.id = ln.PersonId
GROUP BY p.id
    ,p.NAME
FOR json path

--JSON to Query : OPENJSON and out apply allow you to read back the array !
DECLARE @JsonOutput NVARCHAR(max) = (
        SELECT p.id
            ,p.NAME
            ,Json_Query('[' + string_agg(ln.LuckyNumber, ',') + ']') 'LuckyNumbers'
        FROM person p
        INNER JOIN LuckyNumbers ln ON p.id = ln.PersonId
        GROUP BY p.id
            ,p.NAME
        FOR json path
        );

SELECT id
    ,NAME
    ,luckynumber
FROM openjson(@JsonOutput) WITH (
        id INT 'strict $.id'
        ,NAME NVARCHAR(50) '$.name'
        ,LuckyNumbers NVARCHAR(MAX) '$.LuckyNumbers' AS JSON
        )
OUTER APPLY OPENJSON(LuckyNumbers) WITH (LuckyNumber NVARCHAR(8) '$');
Run Code Online (Sandbox Code Playgroud)

有没有更好的方法来使用 Sqlserver 来做到这一点?我是否错过了类似于 Postgre 的本机聚合函数json_agg

Han*_*non 5

您可以像这样近似所需的输出:

SELECT p.id
    , p.[name]
    , LuckNumbers = (
            SELECT ln.LuckyNumber 
            FROM #LuckyNumbers ln 
            WHERE ln.PersonId = p.Id 
            FOR JSON PATH
        )
FROM #person p
FOR JSON PATH;
Run Code Online (Sandbox Code Playgroud)

本质上,为每个人的幸运数字创建一个 JSONint值数组。我不知道如何从每个值中删除“LuckyNumber”标签;这是我第一次在 SQL Server 上使用 JSON。

输出看起来像:

[
    {
        “id”:1
        ,"name":"乔斯安"
        ,“幸运数字”:[
             {“幸运号码”:581}
            ,{"幸运数字":777}
            ]
    }
    ,{
        “id”:2
        ,"name":"保罗"
        ,“幸运数字”:[
             {“幸运号码”:123551}
            ,{"幸运数字":5}
            ,{"幸运号码":646464}
            ,{"幸运号码":1345}
            ,{"幸运数字":75}
            ,{"幸运数字":76}
            ]
    }
    ,{
        “id”:3
        ,"name":"季节"
        ,“幸运数字”:[
            {“幸运数字”:1}
            ]
    }
]