我试图将更新语句写入格式如下的表中的XML列。
这是在表的字段
<Params>
<Account>
<FirstName>Michael</FirstName>
<LastName>Bar</LastName>
</Account>
<Account>
<FirstName>Pam</FirstName>
<LastName>Foo</LastName>
</Account>
</Params>
**this is in on field of ONE of another record in that table
<Params>
<Account>
<FirstName>Darold</FirstName>
<LastName>ok</LastName>
</Account>
<Account>
<FirstName>Fred</FirstName>
<LastName>whatever</LastName>
</Account>
<Account>
<FirstName>amy</FirstName>
<LastName>whatever</LastName>
</Account>
</Params>
**
期望的输出
<Params>
<Account>
<FirstName>Michael2334</FirstName>
<LastName>Bar2334</LastName>
</Account>
<Account>
<FirstName>Pam2334</FirstName>
<LastName>Foo2334</LastName>
</Account>
</Params>
<Params>
<Account>
<FirstName>Darold2335</FirstName>
<LastName>ok2335</LastName>
</Account>
<Account>
<FirstName>Fred2335</FirstName>
<LastName>whatever2335</LastName>
</Account>
<Account>
<FirstName>amy2335</FirstName>
<LastName>whatever2335</LastName>
</Account>
</Params>
我的最终目标是更新整个表的xml字段,该字段具有第n个具有连接表ID列的节点,并将该ID附加到名字和姓氏
&#34;规格&#34;是更新名字并将id(整数)列放在姓氏和名字的末尾(我已经从下面的SQLFiddle中解决了PoC,但没有完全,因为只有在有一条记录的情况下它才有效该表,现在只尝试使用firstname)
我全天都
我查看了互联网并且功能修改(替换......的值)一次只能影响其中一个帐户。因此,我必须创建一个这样的循环。但是如果SQL Server支持XPath函数matches()
并且可以检查是否存在带有正则表达式的数字,那么它非常难看且底层变量KeepGoing会更好用,但这是不在SQL Server 2017中。我的工作将使用contains()
10次!要查看我是否已完成并可以继续下一条记录。
如果有人有更优雅的解决方案,请告诉我。请求此功能的人希望这是一个声明而不是游标。我已经从下面的代码中删除了当然已经放弃了。
1)从下面返回的XML
返回的查询是什么4
4
4
表示FirstName中的最后一个字符
和
4
表示第二个节点中FirstName的最后一个字符
此选择也应返回
5
5
用于下一条记录
但这不是主要问题,这是一个试图在xpath中使用子字符串的文件
我试图通过while循环进行评估,所以我知道何时停止在1上执行 通过在最后一个字符上查找整数,我尝试写下面
失败了选择 XMLCol.value(&#39; // Account / FirstName / text()[substring(。,string-length(x)-1,11)]&#39;,&#39; nvarchar(255)) 从 XMLtbl
我一直在尝试下面的所有形式,只是为了得到这样的消息......
Msg 2203,Level 16,State 1,Line 114
XQuery [XMLtbl.XMLCol.value()]:只有&#39; http://www.w3.org/2001/XMLSchema#decimal?&#39;,&#39; http://www.w3.org/2001/XMLSchema#boolean?&#39;或者&#39;节点()*&#39;表达式允许作为谓词,找到&#39; xs:string&#39;
以下是我正在处理的所有事情
这比使用EXEC
创建SQL字符串并动态运行SQL要少一点,只是尝试尽可能做到最好。
http://sqlfiddle.com/#!18/7eed1
很有必要我知道xquery / xpath并不容易,并且远离它并留给专家
最后的小提琴(根据下面的答案,但它还有一些我使用的字段与问题无关)
答案 0 :(得分:3)
你的问题很长,几乎是 TL; DR ,但仍然不是很清楚...这将有助于提供预期的输出......
一些假设和陈述:
.modify()
允许每次通话只进行一次更改 - 非常有限...... 但是,在您的情况下,最好切碎XML并从头开始重新创建它。您可以使用任何T-SQL
功能:
DECLARE @tbl TABLE(ID INT IDENTITY, YourXML XML);
INSERT INTO @tbl VALUES
(N'<Params>
<Account>
<FirstName>Michael</FirstName>
<LastName>Bar</LastName>
</Account>
<Account>
<FirstName>Pam</FirstName>
<LastName>Foo</LastName>
</Account>
</Params>')
,(N'<Params>
<Account>
<FirstName>John</FirstName>
<LastName>Wood</LastName>
</Account>
<Account>
<FirstName>Jane</FirstName>
<LastName>Smith</LastName>
</Account>
<Account>
<FirstName>Jim</FirstName>
<LastName>Stone</LastName>
</Account>
</Params>');
- 查询使用“可更新的CTE”来创建值,之后可以在UPDATE中使用。
WITH cte AS
(
SELECT t.YourXML
,(
SELECT
--just silly, to show how it works: append "blah" to the first name
Acc.value(N'(FirstName/text())[1]',N'nvarchar(max)') + '_blah' AS FirstName
--Just pick the last character as LastName
,RIGHT(Acc.value(N'(LastName/text())[1]',N'nvarchar(max)'),1) AS LastName
--Add the ID in the last place
,t2.ID
FROM @tbl AS t2
CROSS APPLY t2.YourXML.nodes(N'/Params/Account') AS A(Acc)
WHERE t2.ID=t.ID
FOR XML PATH('Account'),ROOT('Params'),TYPE
) AS NewXML
FROM @tbl AS t
)
UPDATE cte SET YourXML=NewXML;
SELECT * FROM @tbl;
在操作
之后,其中一个XML看起来像这样<Params>
<Account>
<FirstName>Michael_blah</FirstName>
<LastName>r</LastName>
<ID>1</ID>
</Account>
<Account>
<FirstName>Pam_blah</FirstName>
<LastName>o</LastName>
<ID>1</ID>
</Account>
</Params>
此查询会将行的ID(填充为五位数字)附加到两个名称部分:
WITH cte AS
(
SELECT t.YourXML
,(
SELECT
Acc.value(N'(FirstName/text())[1]',N'nvarchar(max)') + REPLACE(STR(t2.ID,5),' ','0') AS FirstName
,Acc.value(N'(LastName/text())[1]',N'nvarchar(max)') + REPLACE(STR(t2.ID,5),' ','0') AS LastName
FROM @tbl AS t2
CROSS APPLY t2.YourXML.nodes(N'/Params/Account') AS A(Acc)
WHERE t2.ID=t.ID
FOR XML PATH('Account'),ROOT('Params'),TYPE
) AS NewXML
FROM @tbl AS t
)
UPDATE cte SET YourXML=NewXML;
SELECT * FROM @tbl;
此查询将传递每个名称的最后一个字符
SELECT Acc.value(N'substring((FirstName/text())[1],string-length((FirstName/text())[1]),1)',N'char(1)')
FROM @tbl AS t
CROSS APPLY t.YourXML.nodes(N'/Params/Account') AS A(Acc);