OpenJson 解析和部分更新 json 列列
OpenJson to parse and partially update a json column column
我有这个table:
CREATE TABLE [dbo].[Device]
(
[Id] [bigint] IDENTITY(1,1) NOT NULL,
[DeviceStatus] [int] NOT NULL,
[Type] [nvarchar](64) NOT NULL,
[Serial] [nvarchar](64) NOT NULL,
[Group] [nvarchar](max) NULL,
[Name] [nvarchar](max) NULL,
[IP] [nvarchar](max) NULL,
[Description] [nvarchar](max) NULL,
[JsonConfig] [nvarchar](max) NULL,
[JsonStatus] [nvarchar](max) NULL,
[RSSI] [int] NOT NULL,
[DateCreated] [datetime2](7) NOT NULL,
[DateUpdated] [datetime2](7) NOT NULL,
[DateLastSeen] [datetime2](7) NOT NULL,
[BatteryVoltage] [int] NOT NULL,
[IsBatteryPowered] [bit] NOT NULL,
[Uptime] [int] NOT NULL,
[Memory] [int] NOT NULL,
[Version] [nvarchar](max) NULL
)
JsonConfig
列有此数据
declare @json nvarchar(max)
set @json = '
[
{
"item": 0,
"type": "switch",
"name": "item 1",
"status": {}
},
{
"item": 1,
"type": "switch",
"name": "item 2",
"status": {}
},
{
"item": 2,
"type": "switch",
"name": "item 3",
"status": {}
},
{
"item": 3,
"type": "switch",
"name": "item 4",
"status": {}
},
{
"item": 4,
"type": "switch",
"name": "item 5",
"status": {}
},
{
"item": 5,
"type": "switch",
"name": "item 6",
"status": {}
},
{
"item": 6,
"type": "switch",
"name": "item 7",
"status": {}
},
{
"item": 7,
"type": "switch",
"name": "item 8",
"status": {}
}
]';
我收到了这样的 json 文档:
declare @jsonStat nvarchar(max)
set @jsonStat = '{
"serial": "locker-7C9EBD6074F8",
"type": "locker",
"ver": "0.1",
"ip": "192.168.1.133",
"uptime": 79,
"mem": 210888,
"rssi": -36,
"resources": [
{
"busy": false,
"enabled": true,
"duration": 0,
"timer": false,
"valueA" : 1
},
{
"busy": false,
"enabled": true,
"duration": 0,
"timer": false,
"valueB" : "test B"
},
{
"busy": true,
"enabled": true,
"duration": 5,
"timer": true
},
{
"busy": false,
"enabled": true,
"duration": 0,
"timer": false
},
{
"busy": false,
"enabled": true,
"duration": 0,
"timer": false
},
{
"busy": false,
"enabled": true,
"duration": 0,
"timer": false
},
{
"busy": false,
"enabled": true,
"duration": 0,
"timer": false
},
{
"busy": false,
"enabled": true,
"duration": 0,
"timer": false
}
]
}';
我想update/replace“状态”与新文档中包含的任何信息在同一数组位置(预先不知道状态中包含的字段名称),例如:
{
"item": 0,
"type": "switch",
"name": "item 1",
"status": {}
},
变成:
{
"item": 0,
"type": "switch",
"name": "item 1",
"status": {
"busy": false,
"enabled": true,
"duration": 0,
"timer": false,
"valueA" : 1
}
},
这是我到目前为止所做的,但不知道如何提取每个 resource[]
项目以将其字段插入项目 [].status
ALTER PROCEDURE sp_process_device_stat
(@json nvarchar(MAX))
AS
BEGIN
UPDATE device
SET [type] = Item.[type],
[version] = Item.ver,
[ip] = Item.[ip],
[uptime] = Item.uptime,
[memory] = Item.mem,
[rssi] = Item.rssi,
[jsonStatus] = Item.resources,
[DateLastSeen] = GETDATE()
FROM
OPENJSON(@json)
WITH
([serial] nvarchar(100),
[type] nvarchar(100),
[ver] nvarchar(100),
[ip] nvarchar(100),
[uptime] nvarchar(100),
[mem] nvarchar(100),
[rssi] nvarchar(100),
[resources] nvarchar(max) as JSON) as Item
JOIN
[Device] device ON Item.serial = device.serial;
END
你可以试试这个:
--声明你的两个 json 字符串
declare @json nvarchar(max)
set @json = '
[
{
"item": 0,
"type": "switch",
"name": "item 1",
"status": {}
},
{
"item": 1,
"type": "switch",
"name": "item 2",
"status": {}
},
{
"item": 2,
"type": "switch",
"name": "item 3",
"status": {}
},
{
"item": 3,
"type": "switch",
"name": "item 4",
"status": {}
},
{
"item": 4,
"type": "switch",
"name": "item 5",
"status": {}
},
{
"item": 5,
"type": "switch",
"name": "item 6",
"status": {}
},
{
"item": 6,
"type": "switch",
"name": "item 7",
"status": {}
},
{
"item": 7,
"type": "switch",
"name": "item 8",
"status": {}
}
]';
declare @jsonStat nvarchar(max)
set @jsonStat = '{
"serial": "locker-7C9EBD6074F8",
"type": "locker",
"ver": "0.1",
"ip": "192.168.1.133",
"uptime": 79,
"mem": 210888,
"rssi": -36,
"resources": [
{
"busy": false,
"enabled": true,
"duration": 0,
"timer": false,
"valueA" : 1
},
{
"busy": false,
"enabled": true,
"duration": 0,
"timer": false,
"valueB" : "test B"
},
{
"busy": true,
"enabled": true,
"duration": 5,
"timer": true
},
{
"busy": false,
"enabled": true,
"duration": 0,
"timer": false
},
{
"busy": false,
"enabled": true,
"duration": 0,
"timer": false
},
{
"busy": false,
"enabled": true,
"duration": 0,
"timer": false
},
{
"busy": false,
"enabled": true,
"duration": 0,
"timer": false
},
{
"busy": false,
"enabled": true,
"duration": 0,
"timer": false
}
]
}';
--查询将使用游标(因为JSON_MODIFY()
只允许单个更改)
DECLARE @insP INT;
DECLARE @stat NVARCHAR(MAX);
DECLARE cur CURSOR FOR SELECT B.[key] AS InsertPosition
,B.[value] AS statusToInsert
FROM OPENJSON(@jsonStat) WITH([resources] NVARCHAR(MAX) AS JSON) A
OUTER APPLY OPENJSON(A.resources) B;
OPEN CUR;
FETCH NEXT FROM cur INTO @insP,@stat;
WHILE @@FETCH_STATUS = 0
BEGIN
--PRINT CONCAT(@insP ,' ->', @stat);
SET @json = JSON_MODIFY(@json,CONCAT(N'$[',@insP,'].status'),JSON_QUERY(@stat));
FETCH NEXT FROM cur INTO @insP,@stat;
END
CLOSE CUR;
DEALLOCATE CUR;
PRINT @json
简而言之:
- 我们使用
WITH
子句从 @jsonStat
读取 resources
以告诉引擎该片段本身是 JSON 部分。
- 我们使用另一个
APPLY OPENJSON
检索项目的位置和值。
- 对于这个查询,我们使用游标向下遍历
- 在游标内我们可以使用位置和内容分别执行
JSON_MODIFY()
一次
- 最后
PRINT
说明成功
提示:如果您事先知道 JSON 的字段(并且预计不会对此进行任何更改),您可能会将其解构为 table 并在其中重建 JSON走。为此,您将使用 WITH
子句来获取表格结果中的所有字段,并在末尾使用 FOR JSON PATH
构建 JSON。
我有这个table:
CREATE TABLE [dbo].[Device]
(
[Id] [bigint] IDENTITY(1,1) NOT NULL,
[DeviceStatus] [int] NOT NULL,
[Type] [nvarchar](64) NOT NULL,
[Serial] [nvarchar](64) NOT NULL,
[Group] [nvarchar](max) NULL,
[Name] [nvarchar](max) NULL,
[IP] [nvarchar](max) NULL,
[Description] [nvarchar](max) NULL,
[JsonConfig] [nvarchar](max) NULL,
[JsonStatus] [nvarchar](max) NULL,
[RSSI] [int] NOT NULL,
[DateCreated] [datetime2](7) NOT NULL,
[DateUpdated] [datetime2](7) NOT NULL,
[DateLastSeen] [datetime2](7) NOT NULL,
[BatteryVoltage] [int] NOT NULL,
[IsBatteryPowered] [bit] NOT NULL,
[Uptime] [int] NOT NULL,
[Memory] [int] NOT NULL,
[Version] [nvarchar](max) NULL
)
JsonConfig
列有此数据
declare @json nvarchar(max)
set @json = '
[
{
"item": 0,
"type": "switch",
"name": "item 1",
"status": {}
},
{
"item": 1,
"type": "switch",
"name": "item 2",
"status": {}
},
{
"item": 2,
"type": "switch",
"name": "item 3",
"status": {}
},
{
"item": 3,
"type": "switch",
"name": "item 4",
"status": {}
},
{
"item": 4,
"type": "switch",
"name": "item 5",
"status": {}
},
{
"item": 5,
"type": "switch",
"name": "item 6",
"status": {}
},
{
"item": 6,
"type": "switch",
"name": "item 7",
"status": {}
},
{
"item": 7,
"type": "switch",
"name": "item 8",
"status": {}
}
]';
我收到了这样的 json 文档:
declare @jsonStat nvarchar(max)
set @jsonStat = '{
"serial": "locker-7C9EBD6074F8",
"type": "locker",
"ver": "0.1",
"ip": "192.168.1.133",
"uptime": 79,
"mem": 210888,
"rssi": -36,
"resources": [
{
"busy": false,
"enabled": true,
"duration": 0,
"timer": false,
"valueA" : 1
},
{
"busy": false,
"enabled": true,
"duration": 0,
"timer": false,
"valueB" : "test B"
},
{
"busy": true,
"enabled": true,
"duration": 5,
"timer": true
},
{
"busy": false,
"enabled": true,
"duration": 0,
"timer": false
},
{
"busy": false,
"enabled": true,
"duration": 0,
"timer": false
},
{
"busy": false,
"enabled": true,
"duration": 0,
"timer": false
},
{
"busy": false,
"enabled": true,
"duration": 0,
"timer": false
},
{
"busy": false,
"enabled": true,
"duration": 0,
"timer": false
}
]
}';
我想update/replace“状态”与新文档中包含的任何信息在同一数组位置(预先不知道状态中包含的字段名称),例如:
{
"item": 0,
"type": "switch",
"name": "item 1",
"status": {}
},
变成:
{
"item": 0,
"type": "switch",
"name": "item 1",
"status": {
"busy": false,
"enabled": true,
"duration": 0,
"timer": false,
"valueA" : 1
}
},
这是我到目前为止所做的,但不知道如何提取每个 resource[]
项目以将其字段插入项目 [].status
ALTER PROCEDURE sp_process_device_stat
(@json nvarchar(MAX))
AS
BEGIN
UPDATE device
SET [type] = Item.[type],
[version] = Item.ver,
[ip] = Item.[ip],
[uptime] = Item.uptime,
[memory] = Item.mem,
[rssi] = Item.rssi,
[jsonStatus] = Item.resources,
[DateLastSeen] = GETDATE()
FROM
OPENJSON(@json)
WITH
([serial] nvarchar(100),
[type] nvarchar(100),
[ver] nvarchar(100),
[ip] nvarchar(100),
[uptime] nvarchar(100),
[mem] nvarchar(100),
[rssi] nvarchar(100),
[resources] nvarchar(max) as JSON) as Item
JOIN
[Device] device ON Item.serial = device.serial;
END
你可以试试这个:
--声明你的两个 json 字符串
declare @json nvarchar(max)
set @json = '
[
{
"item": 0,
"type": "switch",
"name": "item 1",
"status": {}
},
{
"item": 1,
"type": "switch",
"name": "item 2",
"status": {}
},
{
"item": 2,
"type": "switch",
"name": "item 3",
"status": {}
},
{
"item": 3,
"type": "switch",
"name": "item 4",
"status": {}
},
{
"item": 4,
"type": "switch",
"name": "item 5",
"status": {}
},
{
"item": 5,
"type": "switch",
"name": "item 6",
"status": {}
},
{
"item": 6,
"type": "switch",
"name": "item 7",
"status": {}
},
{
"item": 7,
"type": "switch",
"name": "item 8",
"status": {}
}
]';
declare @jsonStat nvarchar(max)
set @jsonStat = '{
"serial": "locker-7C9EBD6074F8",
"type": "locker",
"ver": "0.1",
"ip": "192.168.1.133",
"uptime": 79,
"mem": 210888,
"rssi": -36,
"resources": [
{
"busy": false,
"enabled": true,
"duration": 0,
"timer": false,
"valueA" : 1
},
{
"busy": false,
"enabled": true,
"duration": 0,
"timer": false,
"valueB" : "test B"
},
{
"busy": true,
"enabled": true,
"duration": 5,
"timer": true
},
{
"busy": false,
"enabled": true,
"duration": 0,
"timer": false
},
{
"busy": false,
"enabled": true,
"duration": 0,
"timer": false
},
{
"busy": false,
"enabled": true,
"duration": 0,
"timer": false
},
{
"busy": false,
"enabled": true,
"duration": 0,
"timer": false
},
{
"busy": false,
"enabled": true,
"duration": 0,
"timer": false
}
]
}';
--查询将使用游标(因为JSON_MODIFY()
只允许单个更改)
DECLARE @insP INT;
DECLARE @stat NVARCHAR(MAX);
DECLARE cur CURSOR FOR SELECT B.[key] AS InsertPosition
,B.[value] AS statusToInsert
FROM OPENJSON(@jsonStat) WITH([resources] NVARCHAR(MAX) AS JSON) A
OUTER APPLY OPENJSON(A.resources) B;
OPEN CUR;
FETCH NEXT FROM cur INTO @insP,@stat;
WHILE @@FETCH_STATUS = 0
BEGIN
--PRINT CONCAT(@insP ,' ->', @stat);
SET @json = JSON_MODIFY(@json,CONCAT(N'$[',@insP,'].status'),JSON_QUERY(@stat));
FETCH NEXT FROM cur INTO @insP,@stat;
END
CLOSE CUR;
DEALLOCATE CUR;
PRINT @json
简而言之:
- 我们使用
WITH
子句从@jsonStat
读取resources
以告诉引擎该片段本身是 JSON 部分。 - 我们使用另一个
APPLY OPENJSON
检索项目的位置和值。 - 对于这个查询,我们使用游标向下遍历
- 在游标内我们可以使用位置和内容分别执行
JSON_MODIFY()
一次 - 最后
PRINT
说明成功
提示:如果您事先知道 JSON 的字段(并且预计不会对此进行任何更改),您可能会将其解构为 table 并在其中重建 JSON走。为此,您将使用 WITH
子句来获取表格结果中的所有字段,并在末尾使用 FOR JSON PATH
构建 JSON。