所以我正在处理包含XML数据的表中的字段,并且从一行到另一行,XML字段中的参数数量会有所不同(变量名称也是如此)。
我需要能够为我的<variablename>tminus1</variablename>
搜索包含XML的字段
(我没有设计XML结构,我只是必须解决它的人)并替换<ValueAsString>data here</ValueAsString>
使用监视表更改的触发器动态生成的新数据。
由于XML的设置方式,我花了好几天试图解决这个问题,但我很茫然。有人可以帮忙吗?触发器部分很容易找到正确的XML位置来替换我很难用的。
<Parameters>
<Parameter><VariableID>(1012,14505)</VariableID><VariableName>ArtworkFormat</VariableName><ListID>(1042,1601)</ListID><ListValue>0</ListValue><ValueAsString /></Parameter>
<Parameter><VariableID>(2226,14505)</VariableID><VariableName>ArtworkProofType</VariableName><ListID>(1045,1601)</ListID><ListValue>0</ListValue><ValueAsString /></Parameter>
<Parameter><VariableID>(2224,14505)</VariableID><VariableName>ArtworkReceivedVia</VariableName><ListID>(1043,1601)</ListID><ListValue>0</ListValue><ValueAsString /></Parameter>
<Parameter><VariableID>(2225,14505)</VariableID><VariableName>ArtworkReturnVia</VariableName><ListID>(1044,1601)</ListID><ListValue>0</ListValue><ValueAsString /></Parameter>
<Parameter><VariableID>(10306,14505)</VariableID><VariableName>tminus1</VariableName><ValueAsString>10/12/2016 4:00 PM</ValueAsString></Parameter>
<Parameter><VariableID>(10308,14505)</VariableID><VariableName>tminus3</VariableName><ValueAsString>10/10/2016 4:00 PM</ValueAsString></Parameter>
<Parameter><VariableID>(10307,14505)</VariableID><VariableName>tminus2</VariableName><ValueAsString>10/11/2016 4:00 PM</ValueAsString></Parameter>
</Parameters>
答案 0 :(得分:3)
正如其他人所指出的那样,如果要替换给定为<ValueAsString />
的节点的文本值,则会出现问题。最后.modify(N'replace value of...
要求/text()
作为替换的目标,但是没有......简单的方法适用于给定的情况,但如果在您要更改目标节点的<Parameter>
为空,因为它位于VariableName="ArtworkReturnVia"
:
DECLARE @SearchFor NVARCHAR(100)='tminus1';
DECLARE @SetValue NVARCHAR(100)='NewData';
UPDATE @tbl SET XmlColumn.modify(N'replace value of (/Parameters/Parameter[VariableName=sql:variable("@SearchFor")]/ValueAsString)[1]/text()[1]
with sql:variable("@SetValue")')
一种直接的方法是在任何情况下删除此元素并执行插入:
UPDATE @tbl SET XmlColumn.modify(N'delete (/Parameters/Parameter[VariableName=sql:variable("@SearchFor")]/ValueAsString)[1]')
UPDATE @tbl SET XmlColumn.modify(N'insert <ValueAsString>{sql:variable("@SetValue")}</ValueAsString> into (/Parameters/Parameter[VariableName=sql:variable("@SearchFor")])[1]')
UPDATE @tbl SET XmlColumn=XmlColumn.query
('<Parameters>
{
for $p in /Parameters/Parameter
return <Parameter>
{
if($p/*/text()=sql:variable("@SearchFor")) then
for $nd in $p/*
return
if(local-name($nd)="ValueAsString") then
<ValueAsString>{sql:variable("@SetValue")}</ValueAsString>
else
$nd
else $p
}
</Parameter>
}
</Parameters>
');
WITH Prms AS
(
SELECT ID --needs an ID here
,ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS NodeOrder
,p.query('.') AS prm
FROM @tbl
CROSS APPLY XmlColumn.nodes('/Parameters/Parameter') AS A(p)
)
UPDATE tbl SET XmlColumn=
(
SELECT CASE WHEN prm.value('(/Parameter/VariableName)[1]','nvarchar(max)')=@SearchFor
THEN prm.query('<Parameter>
{
for $nd in /Parameter/*
return
if(local-name($nd)="ValueAsString") then
<ValueAsString>{sql:variable("@SetValue")}</ValueAsString>
else
$nd
}
</Parameter>
')
ELSE prm END
FROM Prms
WHERE Prms.ID=tbl.ID
ORDER BY Prms.NodeOrder
FOR XML PATH(''),ROOT('Parameters')
)
FROM @tbl AS tbl
答案 1 :(得分:2)
您需要查看XML DML,特别是replace value of命令。 XML DML允许通过.modify()
XML函数对XML数据进行内联修改,而无需将其转换为NVARCHAR
,然后再转换回XML
。您将使用以下一个或两个(取决于您从哪里获得替换值):
我使用@ JohnCappelletti的示例代码作为基础编写了以下示例,但SET
的{{1}}子句不同。 UPDATE
XQuery说要获得&#34; / Parameters / Parameter&#34;其中&#34; VariableName&#34;元素名称包含在&#34; @ KeyNode&#34;中找到的字符串。变量,然后抓取&#34; ValueAsString&#34;的文本。儿童元素。这将取代&#34; @ NewValue&#34;变量
我唯一能够开始工作的是替换空元素(即/Parameters/Parameter[//VariableName[1]=sql:variable("@KeyNode")]/ValueAsString/text()
元素)。我确定有办法,但我不会干涉这些东西,足以了解细微差别。
<ValueAsString />
请注意:SQL Server中的DECLARE @KeyNode NVARCHAR(100) = N'tminus1';
DECLARE @NewValue NVARCHAR(100) = N'data here';
DECLARE @YourTable TABLE ([ID] INT, [XMLData] XML);
INSERT INTO @YourTable ([ID], [XMLData]) VALUES
(1, N'<Parameters>
<Parameter><VariableID>(1012,14505)</VariableID><VariableName>ArtworkFormat</VariableName><ListID>(1042,1601)</ListID><ListValue>0</ListValue><ValueAsString /></Parameter>
<Parameter><VariableID>(2226,14505)</VariableID><VariableName>ArtworkProofType</VariableName><ListID>(1045,1601)</ListID><ListValue>0</ListValue><ValueAsString /></Parameter>
<Parameter><VariableID>(2224,14505)</VariableID><VariableName>ArtworkReceivedVia</VariableName><ListID>(1043,1601)</ListID><ListValue>0</ListValue><ValueAsString /></Parameter>
<Parameter><VariableID>(2225,14505)</VariableID><VariableName>ArtworkReturnVia</VariableName><ListID>(1044,1601)</ListID><ListValue>0</ListValue><ValueAsString /></Parameter>
<Parameter><VariableID>(10306,14505)</VariableID><VariableName>tminus1</VariableName><ValueAsString>10/12/2016 4:00 PM</ValueAsString></Parameter>
<Parameter><VariableID>(10308,14505)</VariableID><VariableName>tminus3</VariableName><ValueAsString>10/10/2016 4:00 PM</ValueAsString></Parameter>
<Parameter><VariableID>(10307,14505)</VariableID><VariableName>tminus2</VariableName><ValueAsString>10/11/2016 4:00 PM</ValueAsString></Parameter>
</Parameters>');
UPDATE tmp
SET [XMLData].modify(N'
replace value of
(/Parameters/Parameter[//VariableName[1]=sql:variable("@KeyNode")]/ValueAsString/text())[1]
with sql:variable("@NewValue")')
FROM @YourTable tmp
WHERE tmp.[ID] = 1;
SELECT * FROM @YourTable;
数据始终编码为UTF-16(Little Endian),与XML
/ NVARCHAR
/ NCHAR
相同(但是不要使用NTEXT
),因此最好将NTEXT
用于包含XML的字符串数据,并记住使用大写字母 - NVARCHAR
为文字加前缀。
答案 2 :(得分:1)
使用XML数据进行字符串操作值得极其谨慎。
考虑以下(请记住这是我的蜥蜴大脑方法)
Declare @KeyNode varchar(100)='tminus1'
Declare @NewValue varchar(100)='data here'
Declare @YourTable table (ID int,XMLData xml)
Insert Into @YourTable values
(1,'<Parameters><Parameter><VariableID>(1012,14505)</VariableID><VariableName>ArtworkFormat</VariableName><ListID>(1042,1601)</ListID><ListValue>0</ListValue><ValueAsString /></Parameter><Parameter><VariableID>(2226,14505)</VariableID><VariableName>ArtworkProofType</VariableName><ListID>(1045,1601)</ListID><ListValue>0</ListValue><ValueAsString /></Parameter><Parameter><VariableID>(2224,14505)</VariableID><VariableName>ArtworkReceivedVia</VariableName><ListID>(1043,1601)</ListID><ListValue>0</ListValue><ValueAsString /></Parameter><Parameter><VariableID>(2225,14505)</VariableID><VariableName>ArtworkReturnVia</VariableName><ListID>(1044,1601)</ListID><ListValue>0</ListValue><ValueAsString /></Parameter><Parameter><VariableID>(10306,14505)</VariableID><VariableName>tminus1</VariableName><ValueAsString>10/12/2016 4:00 PM</ValueAsString></Parameter><Parameter><VariableID>(10308,14505)</VariableID><VariableName>tminus3</VariableName><ValueAsString>10/10/2016 4:00 PM</ValueAsString></Parameter><Parameter><VariableID>(10307,14505)</VariableID><VariableName>tminus2</VariableName><ValueAsString>10/11/2016 4:00 PM</ValueAsString></Parameter></Parameters>')
Update @YourTable
Set XMLData = (Select (Select U.VariableID
,U.VariableName
,U.ListID
,U.ListValue
,ValueAsString = case when U.VariableName=@KeyNode then @NewValue else U.ValueAsString end
From ( Select VariableID = B.value('VariableID[1]' ,'varchar(max)')
,VariableName = B.value('VariableName[1]' ,'varchar(max)')
,ListID = B.value('ListID[1]' ,'varchar(max)')
,ListValue = B.value('ListValue[1]' ,'varchar(max)')
,ValueAsString= B.value('ValueAsString[1]','varchar(max)')
From XMLData.nodes('/Parameters') AS A (Lvl1)
Cross Apply A.Lvl1.nodes('Parameter')AS B(B)
) U
For XML Path('Parameter'),Type
) For XML Path ('Parameters'),Type
)
From @YourTable
Select * from @YourTable
更新XML
<Parameters>
<Parameter>
<VariableID>(1012,14505)</VariableID>
<VariableName>ArtworkFormat</VariableName>
<ListID>(1042,1601)</ListID>
<ListValue>0</ListValue>
<ValueAsString></ValueAsString>
</Parameter>
<Parameter>
<VariableID>(2226,14505)</VariableID>
<VariableName>ArtworkProofType</VariableName>
<ListID>(1045,1601)</ListID>
<ListValue>0</ListValue>
<ValueAsString></ValueAsString>
</Parameter>
<Parameter>
<VariableID>(2224,14505)</VariableID>
<VariableName>ArtworkReceivedVia</VariableName>
<ListID>(1043,1601)</ListID>
<ListValue>0</ListValue>
<ValueAsString></ValueAsString>
</Parameter>
<Parameter>
<VariableID>(2225,14505)</VariableID>
<VariableName>ArtworkReturnVia</VariableName>
<ListID>(1044,1601)</ListID>
<ListValue>0</ListValue>
<ValueAsString></ValueAsString>
</Parameter>
<Parameter>
<VariableID>(10306,14505)</VariableID>
<VariableName>tminus1</VariableName> --<< Key Value
<ValueAsString>data here</ValueAsString> --<< Updated Value
</Parameter>
<Parameter>
<VariableID>(10308,14505)</VariableID>
<VariableName>tminus3</VariableName>
<ValueAsString>10/10/2016 4:00 PM</ValueAsString>
</Parameter>
<Parameter>
<VariableID>(10307,14505)</VariableID>
<VariableName>tminus2</VariableName>
<ValueAsString>10/11/2016 4:00 PM</ValueAsString>
</Parameter>
</Parameters>