如何反转 SQL Server 中的 OPENJSON() 函数?
Posted
技术标签:
【中文标题】如何反转 SQL Server 中的 OPENJSON() 函数?【英文标题】:How to reverse the OPENJSON() function in SQL server? 【发布时间】:2017-09-30 21:03:06 【问题描述】:sql-server OPENJSON() 函数可以将一个json数组转换成带有键值对的sql表,例如:
DECLARE @json NVARCHAR(MAX);
SET @json = '
"key1": "val1",
"key2": "val2",
"key3": "val3"
';
SELECT * FROM OPENJSON(@json, '$')
结果:
key value type
--------------------
key1 val1 1
key2 val2 1
key3 val3 1
将此键/值表转换回 json 数组的最佳通用方法是什么?
为什么?如果我们可以用一个函数做到这一点,它会打开一系列 json 修改,否则在 sql server 上是不可能的,例如:
重新排序元素 重命名属性(键名) 将 json 数组拆分为更小的数组/合并 json 数组 比较 json 数组(两个 json 中都存在哪些键/值元素?有什么区别?) 清理 json(删除语法空格/换行符以对其进行压缩)现在,我可以开始做简单的 CONCAT('"',[key],'":"',[value]),然后做一个逗号列表聚合。但如果我想要一个既是易于在我的代码库中应用并适用于所有数据类型, 这不是一项简单的任务. 通过查看json format definition, 转换应考虑 a) 6 种不同的数据类型, b) 转义字符, c) SQL NULL/json null 处理,d) 我可能忽略的内容,即至少应该支持以下示例:
DECLARE @test_json NVARCHAR(MAX);
SET @test_json = '
"myNull": null,
"myString": "start_\\_\"_\/_\b_\f_\n_\r_\t_\u2600_stop",
"myNumber": 3.14,
"myBool": true,
"myArray": ["1", 2],
"myObject": "key":"val"
'
SELECT * FROM OPENJSON(@test_json, '$')
结果:
key value type
------------------------------------------------
myNull NULL 0
myString start_\_"_/___ _ _ _☀_stop 1
myNumber 3.14 2
myBool true 3
myArray ["1", 2] 4
myObject "key":"val" 5
对于字符串聚合部分,我们长期遭受“FOR XML PATH”的痛苦。幸运的是,我们在 SQL2017/AzureDB 上有 STRING_AGG(),我将接受一个取决于 STRING_AGG() 的解决方案。
【问题讨论】:
函数当然应该接受参数(key nvarchar(4000), value nvarchar(max), type int)
,其中type
是0,...,5。
这是一个古老但有趣的问题 (+1)。当我处于类似情况时,我使用了以下解决方案(当然,不是作为 UDF,而是基于问题中的 JSON):SELECT CONCAT('', STRING_AGG(t.Pair, ',') ,'') FROM (SELECT CONCAT('"', [key], '":', CASE WHEN [type] = 0 THEN 'null' WHEN [type] = 1 THEN CONCAT('"', STRING_ESCAPE([value], 'json'), '"') WHEN [type] = 2 THEN [value] WHEN [type] = 3 THEN [value] WHEN [type] = 4 THEN JSON_QUERY([value]) WHEN [type] = 5 THEN JSON_QUERY([value]) END) AS Pair FROM OPENJSON(@test_json, '$')) t
@Zhorov 我最终也用 CASE 编写了自定义函数。随时发布答案。
【参考方案1】:
你可以使用这个命令,使用FOR JSON
select * from table for json auto
我的结果:
["LogId":1,"DtLog":"2017-09-30T21:04:45.6700000","FileId":1, "LogId":2,"DtLog":"2017-09-30T21:08:35.8633333","FileId":3,"LogId":3,"DtLog":"2017-09-30T21:08: 36.4433333","FileId":2,"LogId":4,"DtLog":"2017-09-30T21:08:36.9866667","FileId":12,"LogId":5,"DtLog" :"2017-09-30T21:15:22.5366667","FileId":13,"LogId":6,"DtLog":"2017-09-30T21:38:43.7866667","FileId":17]
【讨论】:
谢谢,但这不起作用。主要是因为“值”字段都将被转换回文本。您无法考虑“类型”。【参考方案2】:我使用 string_agg
declare @json table ( Name varchar(80), Value varchar(max) )
insert into @json
select [Key], Value from openjson(@attributes)
insert into @json values ( 'name', @name )
insert into @json values ( 'title', @title )
insert into @json values ( 'description', @description )
set @attributes = '' + (select STRING_AGG( '"' + Name + '":"' +
REPLACE (value, '"', '\"' ) +'"', ',') from @json) + ''
【讨论】:
以上是关于如何反转 SQL Server 中的 OPENJSON() 函数?的主要内容,如果未能解决你的问题,请参考以下文章