使用 OPENJSON 将 JSON 转换为 SQL 服务器中的逗号分隔列表

Convert JSON to comma-separated list in SQL Server with OPENJSON

在 SQL Server 2016 中,我正在尝试转换以下 JSON:

DECLARE @json NVARCHAR(MAX);

SET @json = 
N' {
        "date": "2021-12-31",
        "distributor_name": "Test",

        "movies": [
            {
                "category_id": 3,
                "name": "Dune",
                "budget": 165,
                "release_date": "2021-09-03",

                "location": [
                    {
                        "location_type": 1, 
                        "location_code": "US"
                    },
                    {
                        "location_type": 2,
                        "location_code": "CA"
                    },
                    {
                        "location_type": 2,
                        "location_code": "UK"
                    }
                ]
            },
            {
                "category_id": 2,
                "name": "No Time to Die",
                "budget": 250,
                "release_date": "2021-09-28",
                
                "location": [
                    {
                        "location_type": 1, 
                        "location_code": "US"
                    },
                    {
                        "location_type": 1, 
                        "location_code": "UK"
                    }
                ]
            }
        ]
    }
';

进入:

category_id name budget release_date country distribution
3 Dune 165 2021-09-03 US CA, UK
2 No Time to Die 250 2021-09-28 US, UK NULL

应向以下语句添加什么以确保所有 location_codelocation_type = 1 以逗号分隔的列表格式在 country 下,并且所有 location_code使用 location_type = 2 以逗号分隔的列表格式进入 distribution

SELECT *
FROM OPENJSON(@json, '$.movies')
  WITH (
    category_id INT '$.category_id',
    name VARCHAR(255) '$.name',
    budget INT '$.budget',
    release_date DATE '$.release_date'
  )

您可以在子查询中再次使用 OPENJSON 来分解内部 location 数组。

对于SQL Server 2016,需要使用FOR XML聚合。

DECLARE @sep varchar(10) = ',';

SELECT
  j.category_id,
  j.name,
  j.budget,
  j.release_date,
  country = STUFF((
      SELECT
        @sep + location_code
      FROM OPENJSON(j.location)
        WITH (
          location_type int,
          location_code char(2)
        ) j2
      WHERE j2.location_type = 1
      FOR XML PATH(''), TYPE
  ).value('text()[1]','varchar(max)'), 1, LEN(@sep), ''),
  distribution = STUFF((
      SELECT
        @sep + location_code
      FROM OPENJSON(j.location)
        WITH (
          location_type int,
          location_code char(2)
        ) j2
      WHERE j2.location_type = 2
      FOR XML PATH(''), TYPE
  ).value('text()[1]','varchar(max)'), 1, LEN(@sep), '')
FROM OPENJSON(@json, '$.movies')
  WITH (
    category_id int,
    name nvarchar(200),
    budget int,
    release_date datetime,
    location nvarchar(max) AS JSON
  ) j;

以后的版本可以更简单地使用STRING_AGG

SELECT
  j.category_id,
  j.name,
  j.budget,
  j.release_date,
  country = (
      SELECT STRING_AGG(j2.location_code, ',')
      FROM OPENJSON(j.location)
        WITH (
          location_type int,
          location_code char(2)
        ) j2
      WHERE j2.location_type = 1
  ),
  distribution = (
      SELECT STRING_AGG(j2.location_code, ',')
      FROM OPENJSON(j.location)
        WITH (
          location_type int,
          location_code char(2)
        ) j2
      WHERE j2.location_type = 2
  )
FROM OPENJSON(@json, '$.movies')
  WITH (
    category_id int,
    name nvarchar(200),
    budget int,
    release_date datetime,
    location nvarchar(max) AS JSON
  ) j;

db<>fiddle