sql - SQL Server:OPENJSON 错误,动态 JSON 列存储在数据库表中
问题描述
我在为我的项目使用 SQL Server JSON 函数的地方遇到以下代码错误。
我想尝试将 json 键值对存储到数据库中的某些表中。
基本上我试图点击返回 JSON 并且我必须存储在我的数据库中的 REST API。
--- JSON document ---
DECLARE @json nvarchar(max) = N'
[
{
"ProductId":1,
"ProductName":"Food",
"ProductDescription":"Apple",
"DatePurchased":"1995-05-01T00:00:00"
},
{
"ProductId":2,
"ProductName":"Electronics",
"ProductDescription":"TV",
"DatePurchased":"2018-09-17T00:00:00"
}
]
'
-- selecting key values from json
SELECT [Key]
FROM OPENJSON((@json), '$')
DECLARE @columns varchar(max) = N''
DECLARE @schema varchar(max) = N''
DECLARE @stm varchar(max)
-- Columns preparation
SELECT
@columns = CONCAT(@columns, ',', QUOTENAME([key])),
@schema = CONCAT(@schema, ',', QUOTENAME([key]),' varchar(max) ''$.', [key], '')
FROM OPENJSON(@json, '$[0]')
DROP TABLE IF EXISTS #TestData
-- inserting the json values to db table Statement
SET @stm = 'SELECT '+
CONCAT(STUFF(@columns, 1, 1, ''),' INTO #TestData FROM OPENJSON((SELECT * FROM @json),''$.records'') WITH (',
STUFF(@schema, 1, 1, ''),')'
)
PRINT @stm
EXEC(@stm)
::::: OUTPUT ::::
SELECT
[ProductId], [ProductName], [ProductDescription], [DatePurchased]
INTO #TestData
FROM OPENJSON((SELECT * FROM @json), '$.records')
WITH (
[ProductId] varchar(max) '$.ProductId,
[ProductName] varchar(max) '$.ProductName,
[ProductDescription] varchar(max) '$.ProductDescription,
[DatePurchased] varchar(max) '$.DatePurchased
)
我收到这些错误:
Msg 1087, Level 15, State 2, Line 1
必须声明表变量“@json”。
消息 319,级别 15,状态 1,第 1 行
关键字“with”附近的语法不正确。如果此语句是公用表表达式、xmlnamespaces 子句或更改跟踪上下文子句,则前面的语句必须以分号结束
解决方案
您的查询中有一些错误。我将在下面详细说明,但首先这里有一些应该适用于我认为你正在尝试做的事情:
DECLARE @json nvarchar(max) = N'
[
{
"ProductId":1,
"ProductName":"Food",
"ProductDescription":"Apple",
"DatePurchased":"1995-05-01T00:00:00"
},
{
"ProductId":2,
"ProductName":"Electronics",
"ProductDescription":"TV",
"DatePurchased":"2018-09-17T00:00:00"
}
]
';
DECLARE @columns nvarchar(max) = N'';
DECLARE @schema nvarchar(max) = N'';
DECLARE @stm nvarchar(max);
-- Columns preparation
WITH keys AS (
SELECT DISTINCT [Key]
FROM OPENJSON(@json)
WITH (
ObjJson NVARCHAR(MAX) N'$' AS JSON
) l1
CROSS APPLY OPENJSON(l1.ObjJson)
)
SELECT
@columns = CONCAT(@columns, ',', QUOTENAME([key])),
@schema = CONCAT(@schema, ',', QUOTENAME([key]),' varchar(max) ''$.', [key], '''')
FROM keys;
DROP TABLE IF EXISTS dbo.wip_testdata;
-- inserting the json values to db table Statement
SET @stm = 'SELECT '+
CONCAT(STUFF(@columns, 1, 1, ''),
' INTO dbo.wip_testdata
FROM OPENJSON(@json)
WITH (
ObjJson NVARCHAR(MAX) N''$'' AS JSON
) l1
CROSS APPLY OPENJSON(l1.ObjJson)
WITH (',
STUFF(@schema, 1, 1, ''),') l2'
);
EXEC sp_executesql @stm, N'@json NVARCHAR(MAX)', @json;
SELECT * FROM dbo.wip_testdata;
现在,为了解决这些问题:
- 您没有深入挖掘 JSON 以从列名的数组中的对象中获取属性名称。
CROSS APPLY
地址。在您生成的动态 SQL 语句中也是如此。 - 正如评论中提到的,您希望使用
sp_executesql
以便可以将 JSON 向下传递到动态执行的内部范围。运行动态语句的范围无法@json
从外部范围访问,因此您必须将其作为参数传递给sp_executesql
. 这就是导致Must declare the table variable "@json"
您收到错误的原因。 - 范围的另一个问题是您无法访问动态执行返回后动态语句创建的临时表。您将看到我将其转换为物理表,以便您可以在动态语句执行返回后在外部范围内访问它。您可以继续使用临时表,但您需要在执行动态语句之前动态创建该表。动态语句的范围确实可以访问从外部范围预先创建的临时表。
推荐阅读
- alert - 交易视图警报
- gmail-api - 如何使用 google api 客户端检查邮件是回复邮件还是简单邮件?
- javascript - Typescript - 如何有条件地基于另一个属性定义类型
- c++ - 为什么 March=native 在 Apple M1 上不起作用?
- javascript - 编辑和保存输入
- php - PHP - 检查重复条目是基于某些列/数据索引并识别重复行索引的二维数组
- c++ - 无法在 VSCode 终端上运行使用 GLEW 的可执行文件
- java - 如何在heroku中设置构建时环境变量?
- javascript - 使用矩阵链乘法找到有效成本时给出无穷大的结果
- stm32 - STM32 ADC DMA 双/多缓冲器示例