使用 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_code
和 location_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;
在 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_code
和 location_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;