SQL Server:将JSON对象数组转换为表格格式

huangapple go评论71阅读模式
英文:

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;

db<>fiddle

英文:

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 &#39;$.EmployeeDetails&#39; path into the OPENJSON call itself to avoid having to repeat it

SELECT
  emp.BusinessEntityID,
  store.*
FROM OPENJSON(@Jdata, &#39;$.EmployeeDetails&#39;)
  WITH ( 
    BusinessEntityID varchar(20),
    Store nvarchar(max) &#39;$.StoreDetail.Store&#39; AS JSON
  ) AS emp
CROSS APPLY OPENJSON(emp.Store)
  WITH (
    AnnualSales integer,
    BusinessType varchar(100)
  ) AS store;

db<>fiddle

huangapple
  • 本文由 发表于 2023年6月19日 19:32:02
  • 转载请务必保留本文链接:https://go.coder-hub.com/76506208.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定