我正在尝试在 SQL Server 中使用 OPENJSON 从 JSON 文件构建规范化表。 JSON 的形式为:
{
"actions":[
{"action":"delete","table":"users","key":4}],
{"action":"update","table":"users","key":5,
"fields":[{"Name":"FirstName":,"OldValue":"X","NewValue":"Bob"},
{"Name":"LastName":,"OldValue":"Y","NewValue":"Dobbs"}]
}
我的目标是使用动态 SQL 中的这些条目来生成有效的查询:
UPDATE [users] SET [FirstName]='Bob',[LastName]='Dobbs' WHERE [key]=5
目前我正在使用这个SQL:
SELECT * FROM OPENJSON(@json, '$.actions')
WITH (
[Action] varchar(25) '$.action',
[Table] varchar(25) '$.table',
[Key] varchar(25) '$.key',
[fields] nvarchar(MAX) AS JSON
)
这给了我有用的结果,例如:
update users 5 {"name":...
我最初的想法是使用字符串解析来分解字段中的数据,但现在我意识到这是个坏主意。我相信我可以从临时表中查询出来并进入 JSON 解析器,并将其分解为行集,但我已经到处查看,但找不到显示这一点的示例。
有人对如何处理不同长度的字段列表有任何建议吗?
看起来您需要
OUTER APPLY
和 STRING_AGG
来突破并重新聚合 fields
属性。
另请注意
sysname
作为对象和列名称。QUOTENAME
转义对象和列名称,使用 REPLACE
转义长字符串。INSERT
,但你应该能够适应这一点。DECLARE @json nvarchar(max) = N'{
"actions":[
{"action":"delete","table":"users","key":4},
{"action":"update","table":"users","key":5,
"fields":[{"Name":"FirstName","OldValue":"X","NewValue":"Bob"},
{"Name":"LastName","OldValue":"Y","NewValue":"Dobbs"}]
}
]}';
DECLARE @sql nvarchar(max);
SELECT @sql = STRING_AGG(
UPPER(j1.action) +
' ' +
QUOTENAME(j1.[table]) +
CASE WHEN j1.action = 'update'
THEN '
SET
' + updateFields.allCols
ELSE ''
END + '
WHERE [key] = ' +
CAST(j1.[key] AS nvarchar(10)) +
';',
'
')
FROM OPENJSON(@json, '$.actions')
WITH (
action nvarchar(25),
[table] sysname,
[key] int,
fields nvarchar(MAX) AS JSON
) j1
OUTER APPLY (
SELECT STRING_AGG(
' ' + QUOTENAME(j2.Name) + ' = ' + ISNULL('N''' + REPLACE(j2.NewValue, '''', '''''') + '''', 'NULL'),
'
'
)
FROM OPENJSON(j1.fields)
WITH (
Name sysname,
NewValue nvarchar(max)
) j2
) updateFields(allCols)
WHERE j1.action IN ('update', 'delete');
PRINT @sql; -- your friend
EXEC sp_executesql @sql;