英文:
SQL Server: Transform arrays of JSON objects into table format
问题
以下是提供的JSON数据:
DECLARE @Jdata NVARCHAR(MAX) =
'{
"EmployeeDetails": {
"BusinessEntityID": 3,
"NationalIDNumber": 509647174,
"JobTitle": "Engineering Manager",
"BirthDate": "1974-11-12",
"MaritalStatus": "M",
"Gender": "M",
"StoreDetail": {
"Store": [
{
"AnnualSales": 800000,
"AnnualRevenue": 80000,
"BankName": "Guardian Bank",
"BusinessType": "BM",
"YearOpened": 1987,
"Specialty": "Touring",
"SquareFeet": 21000
},
{
"AnnualSales": 300000,
"AnnualRevenue": 30000,
"BankName": "International Bank",
"BusinessType": "BM",
"YearOpened": 1982,
"Specialty": "Road",
"SquareFeet": 9000
}
]
}
}
}';
需要显示:
BusinessEntityID | AnnualSales | BusinessType
3 300000 BM
3 800000 BM
我的尝试:
select *
from OPENJSON(@jdata)
WITH(
BusinessEntityID VARCHAR(20) '$.EmployeeDetails.BusinessEntityID',
AnnualSales integer '$.EmployeeDetails.StoreDetail.Store[0].AnnualSales',
BusinessType VARCHAR(100) '$.EmployeeDetails.StoreDetail.Store[0].BusinessType'
) as a
但得到了错误的输出。
BusinessEntityID | AnnualSales | BusinessType
3 NULL NULL
要正确地提取多个店铺的数据,您可以使用CROSS APPLY。以下是修正后的查询:
SELECT
BusinessEntityID,
StoreData.AnnualSales,
StoreData.BusinessType
FROM OPENJSON(@Jdata, '$.EmployeeDetails')
WITH (
BusinessEntityID INT '$.BusinessEntityID',
Stores NVARCHAR(MAX) '$.StoreDetail.Store' AS JSON
) AS EmployeeDetails
CROSS APPLY OPENJSON(EmployeeDetails.Stores)
WITH (
AnnualSales INT '$.AnnualSales',
BusinessType NVARCHAR(100) '$.BusinessType'
) AS StoreData;
这将为您提供正确的输出:
BusinessEntityID | AnnualSales | BusinessType
3 800000 BM
3 300000 BM
英文:
Following is the given JSON data:
DECLARE @Jdata NVARCHAR(MAX) =
'{
"EmployeeDetails": {
"BusinessEntityID": 3,
"NationalIDNumber": 509647174,
"JobTitle": "Engineering Manager",
"BirthDate": "1974-11-12",
"MaritalStatus": "M",
"Gender": "M",
"StoreDetail": {
"Store": [
{
"AnnualSales": 800000,
"AnnualRevenue": 80000,
"BankName": "Guardian Bank",
"BusinessType": "BM",
"YearOpened": 1987,
"Specialty": "Touring",
"SquareFeet": 21000
},
{
"AnnualSales": 300000,
"AnnualRevenue": 30000,
"BankName": "International Bank",
"BusinessType": "BM",
"YearOpened": 1982,
"Specialty": "Road",
"SquareFeet": 9000
}
]
}
}
}';
Need to display:
BusinessEntityID | AnnualSales | BusinessType
-------------------------------------------------
3 300000 BM
3 800000 BM
My try:
select *
from OPENJSON(@jdata)
WITH(
BusinessEntityID VARCHAR(20) '$.EmployeeDetails.BusinessEntityID',
AnnualSales integer '$.EmployeeDetails.StoreDetail.Store.AnnualSales',
BusinessType VARCHAR(100) '$.EmployeeDetails.StoreDetail.Store.BusinessType'
) as a
But getting wrong output.
BusinessEntityID | AnnualSales | BusinessType
-------------------------------------------------
3 NULL NULL
答案1
得分: 2
你需要额外的 OPENJSON()
调用和一个 APPLY
操作符来解析嵌套的 JSON 内容。在这种情况下,您需要在 WITH
子句中使用 AS JSON
修饰符来指定所引用的属性($.EmployeeDetails.StoreDetail.Store
)包含一个内部的 JSON 数组。
SELECT j1.BusinessEntityID, j2.AnnualSales, j2.BusinessType
FROM OPENJSON(@jdata) WITH (
BusinessEntityID VARCHAR(20) '$.EmployeeDetails.BusinessEntityID',
Store NVARCHAR(max) '$.EmployeeDetails.StoreDetail.Store' AS JSON
) j1
OUTER APPLY OPENJSON(j1.Store) WITH (
AnnualSales integer '$.AnnualSales',
BusinessType VARCHAR(100) '$.BusinessType'
) j2
当然,也可以选择使用 JSON_VALUE()
和一个 OPENJSON()
调用的组合:
SELECT
JSON_VALUE(@jdata, '$.EmployeeDetails.BusinessEntityID') AS BusinessEntityID,
AnnualSales,
BusinessType
FROM OPENJSON(@jdata, '$.EmployeeDetails.StoreDetail.Store') WITH (
AnnualSales integer '$.AnnualSales',
BusinessType VARCHAR(100) '$.BusinessType'
) j
英文:
You need an additional OPENJSON()
call and an APPLY
operator to parse the nested JSON content. In this case you need to use the AS JSON
modifier in the WITH
clause to specify that the referenced property ($.EmployeeDetails.StoreDetail.Store
) contains an inner JSON array.
SELECT j1.BusinessEntityID, j2.AnnualSales, j2.BusinessType
FROM OPENJSON(@jdata) WITH (
BusinessEntityID VARCHAR(20) '$.EmployeeDetails.BusinessEntityID',
Store NVARCHAR(max) '$.EmployeeDetails.StoreDetail.Store' AS JSON
) j1
OUTER APPLY OPENJSON(j1.Store) WITH (
AnnualSales integer '$.AnnualSales',
BusinessType VARCHAR(100) '$.BusinessType'
) j2
Of course, a combination of JSON_VALUE()
and one OPENJSON()
call is also an option:
SELECT
JSON_VALUE(@jdata, '$.EmployeeDetails.BusinessEntityID') AS BusinessEntityID,
AnnualSales,
BusinessType
FROM OPENJSON(@jdata, '$.EmployeeDetails.StoreDetail.Store') WITH (
AnnualSales integer '$.AnnualSales',
BusinessType VARCHAR(100) '$.BusinessType'
) j
答案2
得分: 2
你需要两个级别的OPENJSON
。第一个需要使用AS JSON
来检索内部数组。然后,您可以使用CROSS APPLY
将其传递给下一个。
您还可以将'$.EmployeeDetails'
路径放入OPENJSON
调用本身,以避免重复它
SELECT
emp.BusinessEntityID,
store.*
FROM OPENJSON(@Jdata, '$.EmployeeDetails')
WITH (
BusinessEntityID varchar(20),
Store nvarchar(max) '$.StoreDetail.Store' AS JSON
) AS emp
CROSS APPLY OPENJSON(emp.Store)
WITH (
AnnualSales integer,
BusinessType varchar(100)
) AS store;
英文:
You need two levels of OPENJSON
. The first one needs to retrieve the inner array using AS JSON
. Then you feed that into the next using CROSS APPLY
.
You can also put the '$.EmployeeDetails'
path into the OPENJSON
call itself to avoid having to repeat it
SELECT
emp.BusinessEntityID,
store.*
FROM OPENJSON(@Jdata, '$.EmployeeDetails')
WITH (
BusinessEntityID varchar(20),
Store nvarchar(max) '$.StoreDetail.Store' AS JSON
) AS emp
CROSS APPLY OPENJSON(emp.Store)
WITH (
AnnualSales integer,
BusinessType varchar(100)
) AS store;
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论