我要使用SQL Server获取列数据并将其复制到json对象列中
我正在使用SQL Server查询列和json数据。我想做的是将下面代码中的ename
列中的数据复制到fieldvalue
列中。如果我可以使用SQL做到这一点,那就太好了。
SELECT
a.id, a.ssn, a.ename, p.CaptionName, p.FieldName, p.FieldType, p.FieldValue
FROM
TelecentersDB.dbo.tblUissAssignments as a
CROSS APPLY
OPENJSON (details)
WITH (CaptionName NVARCHAR(100),
FieldName NVARCHAR(100),
FieldType NVARCHAR(15),
FieldValue NVARCHAR(50)) AS P
WHERE
p.captionname = 'txtEname'
AND a.ssn = '000-00-0000'
详细信息列中的我的json字符串
[{"CaptionName":"txtEname","FieldName":null,"FieldType":null,"FieldValue":""}]
我真的不太喜欢sql,这是我要使用的。将数据复制到json对象后,我将删除ename列。
答案 0 :(得分:1)
这是经过修改的解决方案,适用于JSON中包含多个值的情况:https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=1fde45dfb604b2d5540c56f6c17a822d
update a
set details = JSON_MODIFY(details, '$[' + x.[key] + '].FieldValue', ename)
from dbo.tblUissAssignments a
CROSS APPLY OPENJSON (details, '$') x
CROSS APPLY OPENJSON (x.Value)
WITH (CaptionName NVARCHAR(100),
FieldName NVARCHAR(100),
FieldType NVARCHAR(15),
FieldValue NVARCHAR(50)) AS P
WHERE a.ssn = '000-00-0000'
and p.CaptionName = 'txtEname'
这类似于我的原始答案(见下文)。但是:
cross apply
语句。第一个用于将JSON数组拆分为元素,因此我们获得了键(索引)和值(JSON对象为字符串),如此处所示:https://docs.microsoft.com/en-us/sql/t-sql/functions/openjson-transact-sql?view=sql-server-2017#path [key]
返回的cross apply
来定位我们要在JSON_MODIFY
语句中更新的数组中的项目。注意:如果您的JSON数组可能包含多个需要更新的对象,那么我能想到的最好的解决方案是将上述语句放入循环中。因为1次更新只会更新给定JSON上的1个索引。这是一个示例:https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=120d2ac7dd3a024e5e503a5f64b0089e
declare @doWhileTrueFlag bit = 1
while (@doWhileTrueFlag = 1)
begin
update a
set details = JSON_MODIFY(details, '$[' + x.[key] + '].FieldValue', ename)
from dbo.tblUissAssignments a
CROSS APPLY OPENJSON (details, '$') x
CROSS APPLY OPENJSON (x.Value)
WITH (CaptionName NVARCHAR(100),
FieldName NVARCHAR(100),
FieldType NVARCHAR(15),
FieldValue NVARCHAR(50)) AS P
WHERE a.ssn = '000-00-0000'
and p.CaptionName = 'txtEname'
and p.FieldValue != ename --if it's already got the correct value, don't update it again
set @doWhileTrueFlag = case when @@RowCount > 0 then 1 else 0 end
end
尝试一下:https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=b7b4d075cac6cd46239561ddb992ac90
update a
set details = JSON_MODIFY(details, '$[0].FieldValue', ename)
from dbo.tblUissAssignments a
cross apply
OPENJSON (details)
WITH (CaptionName NVARCHAR(100),
FieldName NVARCHAR(100),
FieldType NVARCHAR(15),
FieldValue NVARCHAR(50)) AS P
where a.ssn = '000-00-0000'
and p.captionname = 'txtEname'
此处提供有关JSON_MODIFY方法的更多信息:https://docs.microsoft.com/en-us/sql/t-sql/functions/json-modify-transact-sql?view=sql-server-2017
微妙的一点是,您正在更新包含json对象的json数组;不是单个对象。为此,您必须在根元素上包括索引。如果您不熟悉,请参阅此帖子以获取有关JsonPath的一些有用信息:https://support.smartbear.com/alertsite/docs/monitors/api/endpoint/jsonpath.html
对于数组中有多个项目的情况,理想情况下,我们将使用过滤器表达式,例如:
update a
set details = JSON_MODIFY(details, '$[?(@.CaptionName == ''txtEname'')].FieldValue', ename)
from dbo.tblUissAssignments a
where a.ssn = '000-00-0000'
遗憾的是,MS SQL尚不支持这些功能(请参见此出色的帖子:https://modern-sql.com/blog/2017-06/whats-new-in-sql-2016)
因此,我认为我们需要进行讨厌的修改。我想到了两种这样的方法:
我会考虑这些/是否有更清洁的东西,因为目前都没有舒适的坐姿...
答案 1 :(得分:0)
如果我理解您的问题,那么一种可能的方法(如果您使用SQL Server 2017+)是对OPENJSON()
使用STRING_AGG()
和字符串操作:
表格:
CREATE TABLE #Data (
id int,
ssn varchar(12),
ename varchar(40),
details nvarchar(max)
)
INSERT INTO #Data
(id, ssn, ename, details)
VALUES
(1, '000-00-0000', 'stackoverflow1', N'[{"CaptionName":"txtEname","FieldName":null,"FieldType":null,"FieldValue":""}, {"CaptionName":"txtEname","FieldName":null,"FieldType":null,"FieldValue":""}]'),
(2, '000-00-0000', 'stackoverflow2', N'[{"CaptionName":"txtEname","FieldName":null,"FieldType":null,"FieldValue":""}, {"CaptionName":"txtEname","FieldName":null,"FieldType":null,"FieldValue":""}]')
声明:
SELECT
d.id, d.ssn, d.ename,
CONCAT(N'[', STRING_AGG(JSON_MODIFY(j.[value], '$.FieldValue', ename), ','), N']') AS details
FROM #Data d
CROSS APPLY OPENJSON (d.details) j
WHERE JSON_VALUE(j.[value], '$.CaptionName') = N'txtEname' AND (d.ssn = '000-00-0000')
GROUP BY d.id, d.ssn, d.ename
输出:
id ssn ename details
1 000-00-0000 stackoverflow1 [{"CaptionName":"txtEname","FieldName":null,"FieldType":null,"FieldValue":"stackoverflow1"},{"CaptionName":"txtEname","FieldName":null,"FieldType":null,"FieldValue":"stackoverflow1"}]
2 000-00-0000 stackoverflow2 [{"CaptionName":"txtEname","FieldName":null,"FieldType":null,"FieldValue":"stackoverflow2"},{"CaptionName":"txtEname","FieldName":null,"FieldType":null,"FieldValue":"stackoverflow2"}]
对于SQL Server 2016,您可以使用FOR XML PATH
进行字符串聚合:
SELECT
d.id, d.ssn, d.ename,
CONCAT(N'[', STUFF(s.details, 1, 1, N''), N']') AS details
FROM #Data d
CROSS APPLY (
SELECT CONCAT(N',', JSON_MODIFY(j.[value], '$.FieldValue', ename))
FROM #Data
CROSS APPLY OPENJSON (details) j
WHERE
(JSON_VALUE(j.[value], '$.CaptionName') = N'txtEname') AND
(ssn = '000-00-0000') AND
(id = d.id) AND (d.ssn = ssn) AND (d.ename = ename)
FOR XML PATH('')
) s(details)