SQL Server 2016 for JSON 输出整数数组

SQL Server 2016 for JSON output integer array

我想使用 SQL Server 2016 的 For JSON 功能获得 JSON 整数数组。我对整数数组感到困惑。

数据库table结构:

declare @Employees table (ID int, Name nvarchar(50))
insert into @Employees values
(1, 'Bob'),
(2, 'Randy')

declare @Permissions table (ID int, PermissionName nvarchar(50))
insert into @Permissions values
(1, 'Post'),
(2, 'Comment'),
(3, 'Edit'),
(4, 'Delete')

declare @EmployeePermissions table (EmployeeID int, PermissionID int)
insert into @EmployeePermissions values
(1, 1),
(1, 2),
(2, 1),
(2, 2),
(2, 3)

期望的结果:

{"EmployeePermissions": [
  {"Employee":"Bob", "Permissions":[1,2]},
  {"Employee":"Randy", "Permissions":[1,2,3]}
]}

这是我得到的最接近的,但不是我想要的。

select
    e.Name as Employee,
    (select 
         convert(nvarchar(10),ep.PermissionID) as PermID 
     from @EmployeePermissions ep 
     where ep.EmployeeID=e.ID 
     for json path) as 'Permissions'
from
    @Employees e
for json path, root('EmployeePermissions')

returns:

{"EmployeePermissions": [
  {"Employee":"Bob", "Permissions":[{"permID":1},{"permID":2}]},
  {"Employee":"Randy", "Permissions":[{"permID":1},{"permID":2},{"permID":3}]}
]}

解决方案 - SQL Server 2017 及更高版本


select
    e.Name as Employee,
    (select 
         '[' + STRING_AGG(ep.PermissionID, ',') + ']' 
     from @EmployeePermissions ep 
     where ep.EmployeeID=e.ID) as Permissions 
from
    @Employees e
for json path, root('EmployeePermissions')

可以用FOR XML PATHSTUFFPermissionID一串逗号隔开Employee,用QUOTENANE就可以了,然后把所有在变量中并将 "[ 替换为 [ 并将 ]" 替换为 ] :

DECLARE @json NVARCHAR(max)

SELECT @json = REPLACE(REPLACE((
    SELECT  e.Name as [Employee],
            QUOTENAME(STUFF((SELECT ','+CAST(ep.PermissionID as nvarchar(10))
            FROM EmployeePermissions ep
            WHERE e.ID = ep.EmployeeID
            FOR XML PATH('')),1,1,''))
            as [Permissions]
    FROM Employees e 
    FOR JSON AUTO, ROOT('EmployeePermissions')
),'"[','['),']"',']')

SELECT @json

输出:

{"EmployeePermissions":[
    {"Employee":"Bob","Permissions":[1,2]},
    {"Employee":"Randy","Permissions":[1,2,3]}
]}

编辑:

另一种方式:

SELECT '{"EmployeePermissions":[' + STUFF((
SELECT  ',{"Employee":"' + e.Name + '","Permissions":[' +
        STUFF((SELECT ',' + CAST(PermissionID as nvarchar(10))
        FROM EmployeePermissions ep
        WHERE ep.EmployeeID = e.ID
        FOR XML PATH('')),1,1,'') +']}'
FROM Employees e
FOR XML PATH('')),1,1,'') + ']}'

输出:

{"EmployeePermissions":[
    {"Employee":"Bob","Permissions":[1,2]},
    {"Employee":"Randy","Permissions":[1,2,3]}
]}

在 AdventureWorks 2016 CTP3 JSON 示例中,您可以找到一个可以清除 key:value 对数组并创建数组 od 值的函数:

DROP FUNCTION IF EXISTS dbo.ufnToRawJsonArray
GO
CREATE FUNCTION
[dbo].[ufnToRawJsonArray](@json nvarchar(max), @key nvarchar(400)) returns nvarchar(max)
AS BEGIN
       declare @new nvarchar(max) = replace(@json, CONCAT('},{"', @key,'":'),',')
       return '[' + substring(@new, 1 + (LEN(@key)+5), LEN(@new) -2 - (LEN(@key)+5)) + ']'
END

只需提供 SELECT FOR JSON 表达式的结果作为 @json 参数和要删除的键的名称作为第二个参数。可能是这样的:

select
e.Name as Employee,
JSON_QUERY(dbo.ufnToRawJsonArray(
    (select 
     convert(nvarchar(10),ep.PermissionID) as PermID 
     from @EmployeePermissions ep 
     where ep.EmployeeID=e.ID 
     for json path)
  , 'PermID'))
   as 'Permissions'
from
@Employees e
for json path, root('EmployeePermissions')

这应该适用于 SQL Server 2017 (14.x) 及更高版本

SELECT '[' + STRING_AGG(ep.PermissionID, ',') + ']'
FROM @EmployeePermissions ep

仅当您的结果字符串超过 8000 字节时,您才必须将您的值转换为 NVarchar(max)

SELECT '[' + STRING_AGG(cast(ep.PermissionID AS NVARCHAR(MAX)), ',') + ']'
FROM @EmployeePermissions ep

全查询

SELECT e.Name as Employee,
    (SELECT 
         '[' + STRING_AGG(cast(ep.PermissionID AS NVARCHAR(MAX)), ',') + ']' 
     FROM @EmployeePermissions ep 
     WHERE ep.EmployeeID=e.ID) as Permissions 
FROM
    @Employees e
FOR JSON PATH, root('EmployeePermissions')