根据 xml 字段中的连接值与 T-SQL 更新 xml 中的特定节点
Update xml specific nodes in table based on joining values in xml field with T-SQL
我必须花很多时间和搜索这个问题。我什至几乎得到了输出,但问题是导致我出现问题的一对多连接。
这是我的数据
--notice some of the Account nodes have elements that others don't
DECLARE @tbl TABLE(ID INT,fkey int, YourXML XML)
INSERT INTO @tbl (id, fkey, YourXML)
SELECT
98, 8,
N'<Params>
<Account>
<FirstName>Michael</FirstName>
<LastName>Bar</LastName>
<tcode>8</tcode>
</Account>
<Account>
<FirstName>Pam</FirstName>
<LastName>Bar</LastName>
</Account>
</Params>'
UNION
SELECT
99, 9,
N'<Params>
<Account>
<FirstName>Phil</FirstName>
<LastName>Foo</LastName>
</Account>
<Account>
<FirstName>Rebecca</FirstName>
<LastName>Foo</LastName>
<whatever>argh</whatever>
</Account>
</Params>'
DECLARE @tbl2 TABLE(id INT, fkey INT, sfirst VARCHAR(255), slast VRACHAR(255))
INSERT INTO @tbl2 (id, fkey, sfirst, slast)
SELECT 1, 8, 'Michael', 'Bar'
UNION
SELECT 2, 8, 'Pam', 'Bar'
UNION
SELECT 3, 9, 'Phil', 'Foo'
UNION
SELECT 4, 9, 'Rebecca', 'Foo'
--expected output
/* expected output
<Params>
<Account>
<FirstName>first1</FirstName>
<LastName>last1</LastName>
<tcode>8</tcode>
</Account>
<Account>
<FirstName>first2</FirstName>
<LastName>last2</LastName>
</Account>
<Account>
<FirstName>first3</FirstName>
<LastName>last3</LastName>
</Account>
<Account>
<FirstName>first4</FirstName>
<LastName>last4</LastName>
<whatever>argh</whatever>
</Account>
</Params>'
*/
最终的解决方案是看起来像这样的代码,但没有保留变量 xml 标签,例如一个帐户中的 <tcode>
和另一个帐户中的 <whatever>
;WITH cte AS
(
SELECT
YourXML,
(SELECT DISTICNT
'first' + REPLACE(STR(se.ID,9),' ','') AS FirstName,
'last' + REPLACE(STR(se.ID,9),' ','') AS LastName
FROM
@tbl AS sea
INNER JOIN
@tbl2 se ON sea.fkey = se.fkey
CROSS APPLY
sea.YourXML.nodes(N'/Params/Account') AS x(nth)
WHERE
sea.id = ilv.id
FOR XML PATH('Account'), ROOT('Params'), TYPE) AS NewAdditionalInfo
FROM
@tbl AS ilv
)
UPDATE cte
SET YourXML = NewAdditionalInfo;
然后我继续执行双嵌套 while 循环:1 个用于 @tbl
id,2 个用于 count()
在多少个节点上。
我确实注意到
update @tbl
set YourXML.modify('replace value of (//Account/FirstName/text())[sql:variable("@tenantcount")][1] with concat(sql:column("sfirst"),sql:column("ValTbl.id") cast as xs:string ?)')
....
where @tbl.id = @current_id
确实有效,但又会成为一对多问题的受害者
这个怎么样:
SELECT t.YourXML
.query(N'/Params/Account[(FirstName/text())[1]=sql:column("sfirst")
and (LastName/text())[1]=sql:column("slast")]')
.query(N'<Account>
{
for $nd in /Account/*
return
if(local-name($nd)="FirstName") then
<FirstName>{concat($nd/text()[1],xs:string(sql:column("t2.id")))}</FirstName>
else if(local-name($nd)="LastName") then
<LastName>{concat($nd/text()[1],xs:string(sql:column("t2.id")))}</LastName>
else
$nd
}
</Account> ') AS [*]
FROM @tbl AS t
INNER JOIN @tbl2 AS t2 ON t.fkey=t2.fkey
ORDER BY t2.id
FOR XML PATH(''),ROOT('Params');
结果
<Params>
<Account>
<FirstName>Michael1</FirstName>
<LastName>Bar1</LastName>
<tcode>8</tcode>
</Account>
<Account>
<FirstName>Pam2</FirstName>
<LastName>Bar2</LastName>
</Account>
<Account>
<FirstName>Phil3</FirstName>
<LastName>Foo3</LastName>
</Account>
<Account>
<FirstName>Rebecca4</FirstName>
<LastName>Foo4</LastName>
<whatever>argh</whatever>
</Account>
</Params>
一些解释
XML 的 .query()
允许将其放入系列中:
SomeXML.query(N'XQuery').query(N'OtherXQuery')
第一个.query()
使用sql:column
过滤<Account>
,其中FirstName
和LastName
等于sfirst
和slast
.
下一个 .query()
使用 FLWOR
查询遍历 <Account>
和 return 下面的所有节点,具体取决于它们的名称。
这样做,其他节点只是通过...
T-SQL 的 XQuery
相当有限,您不能动态定义新元素或属性,也不能创建通用结构,但您可以做很多事情:-D
这不会更新原始 table 但它 return 正是您预期的输出。
感谢社区的帮助
;WITH cte AS
(
SELECT *
,(
SELECT
t.YourXML
.query(N'/Params/Account[(FirstName/text())[1]=sql:column("sfirst")
and (LastName/text())[1]=sql:column("slast")]')
.query(N'<Account>
{
for $nd in /Account/*
return
if(local-name($nd)="FirstName") then
<FirstName>{concat("first"[1],xs:string(sql:column("t2.id")))}</FirstName>
else if(local-name($nd)="LastName") then
<LastName>{concat("last"[1],xs:string(sql:column("t2.id")))}</LastName>
else
$nd
}
</Account> ') AS [*]
FROM tbl AS t
INNER JOIN tbl2 AS t2 ON t.fkey=t2.fkey
where t.id = tt.id
ORDER BY t2.id
FOR XML PATH(''),ROOT('Params'),TYPE
) AS NewXML
FROM tbl AS tt
)
update cte set YourXML = NewXML
select * from tbl
我必须花很多时间和搜索这个问题。我什至几乎得到了输出,但问题是导致我出现问题的一对多连接。 这是我的数据
--notice some of the Account nodes have elements that others don't
DECLARE @tbl TABLE(ID INT,fkey int, YourXML XML)
INSERT INTO @tbl (id, fkey, YourXML)
SELECT
98, 8,
N'<Params>
<Account>
<FirstName>Michael</FirstName>
<LastName>Bar</LastName>
<tcode>8</tcode>
</Account>
<Account>
<FirstName>Pam</FirstName>
<LastName>Bar</LastName>
</Account>
</Params>'
UNION
SELECT
99, 9,
N'<Params>
<Account>
<FirstName>Phil</FirstName>
<LastName>Foo</LastName>
</Account>
<Account>
<FirstName>Rebecca</FirstName>
<LastName>Foo</LastName>
<whatever>argh</whatever>
</Account>
</Params>'
DECLARE @tbl2 TABLE(id INT, fkey INT, sfirst VARCHAR(255), slast VRACHAR(255))
INSERT INTO @tbl2 (id, fkey, sfirst, slast)
SELECT 1, 8, 'Michael', 'Bar'
UNION
SELECT 2, 8, 'Pam', 'Bar'
UNION
SELECT 3, 9, 'Phil', 'Foo'
UNION
SELECT 4, 9, 'Rebecca', 'Foo'
--expected output
/* expected output
<Params>
<Account>
<FirstName>first1</FirstName>
<LastName>last1</LastName>
<tcode>8</tcode>
</Account>
<Account>
<FirstName>first2</FirstName>
<LastName>last2</LastName>
</Account>
<Account>
<FirstName>first3</FirstName>
<LastName>last3</LastName>
</Account>
<Account>
<FirstName>first4</FirstName>
<LastName>last4</LastName>
<whatever>argh</whatever>
</Account>
</Params>'
*/
最终的解决方案是看起来像这样的代码,但没有保留变量 xml 标签,例如一个帐户中的 <tcode>
和另一个帐户中的 <whatever>
;WITH cte AS
(
SELECT
YourXML,
(SELECT DISTICNT
'first' + REPLACE(STR(se.ID,9),' ','') AS FirstName,
'last' + REPLACE(STR(se.ID,9),' ','') AS LastName
FROM
@tbl AS sea
INNER JOIN
@tbl2 se ON sea.fkey = se.fkey
CROSS APPLY
sea.YourXML.nodes(N'/Params/Account') AS x(nth)
WHERE
sea.id = ilv.id
FOR XML PATH('Account'), ROOT('Params'), TYPE) AS NewAdditionalInfo
FROM
@tbl AS ilv
)
UPDATE cte
SET YourXML = NewAdditionalInfo;
然后我继续执行双嵌套 while 循环:1 个用于 @tbl
id,2 个用于 count()
在多少个节点上。
我确实注意到
update @tbl
set YourXML.modify('replace value of (//Account/FirstName/text())[sql:variable("@tenantcount")][1] with concat(sql:column("sfirst"),sql:column("ValTbl.id") cast as xs:string ?)')
....
where @tbl.id = @current_id
确实有效,但又会成为一对多问题的受害者
这个怎么样:
SELECT t.YourXML
.query(N'/Params/Account[(FirstName/text())[1]=sql:column("sfirst")
and (LastName/text())[1]=sql:column("slast")]')
.query(N'<Account>
{
for $nd in /Account/*
return
if(local-name($nd)="FirstName") then
<FirstName>{concat($nd/text()[1],xs:string(sql:column("t2.id")))}</FirstName>
else if(local-name($nd)="LastName") then
<LastName>{concat($nd/text()[1],xs:string(sql:column("t2.id")))}</LastName>
else
$nd
}
</Account> ') AS [*]
FROM @tbl AS t
INNER JOIN @tbl2 AS t2 ON t.fkey=t2.fkey
ORDER BY t2.id
FOR XML PATH(''),ROOT('Params');
结果
<Params>
<Account>
<FirstName>Michael1</FirstName>
<LastName>Bar1</LastName>
<tcode>8</tcode>
</Account>
<Account>
<FirstName>Pam2</FirstName>
<LastName>Bar2</LastName>
</Account>
<Account>
<FirstName>Phil3</FirstName>
<LastName>Foo3</LastName>
</Account>
<Account>
<FirstName>Rebecca4</FirstName>
<LastName>Foo4</LastName>
<whatever>argh</whatever>
</Account>
</Params>
一些解释
XML 的 .query()
允许将其放入系列中:
SomeXML.query(N'XQuery').query(N'OtherXQuery')
第一个.query()
使用sql:column
过滤<Account>
,其中FirstName
和LastName
等于sfirst
和slast
.
下一个 .query()
使用 FLWOR
查询遍历 <Account>
和 return 下面的所有节点,具体取决于它们的名称。
这样做,其他节点只是通过...
T-SQL 的 XQuery
相当有限,您不能动态定义新元素或属性,也不能创建通用结构,但您可以做很多事情:-D
这不会更新原始 table 但它 return 正是您预期的输出。
感谢社区的帮助
;WITH cte AS
(
SELECT *
,(
SELECT
t.YourXML
.query(N'/Params/Account[(FirstName/text())[1]=sql:column("sfirst")
and (LastName/text())[1]=sql:column("slast")]')
.query(N'<Account>
{
for $nd in /Account/*
return
if(local-name($nd)="FirstName") then
<FirstName>{concat("first"[1],xs:string(sql:column("t2.id")))}</FirstName>
else if(local-name($nd)="LastName") then
<LastName>{concat("last"[1],xs:string(sql:column("t2.id")))}</LastName>
else
$nd
}
</Account> ') AS [*]
FROM tbl AS t
INNER JOIN tbl2 AS t2 ON t.fkey=t2.fkey
where t.id = tt.id
ORDER BY t2.id
FOR XML PATH(''),ROOT('Params'),TYPE
) AS NewXML
FROM tbl AS tt
)
update cte set YourXML = NewXML
select * from tbl