是否可以在一个更新中修改单个节点上的多个属性?
我有类似的东西:
<ENTITY NAME="entity1">
<ATTR ID="attr1" CAPTION="Attributes to Change" SIZE="100" WIDTH="100"></ATTR>
</ENTITY>
我已经能够使用三个单独的更新来修改CAPTION,SIZE和WIDTH属性,但是我认为将它们组合成一个更新的某种方式是徒劳的。有可能吗?
我使用过的更新示例:
UPDATE t
SET [column_name].modify('replace value of (/ENTITY/ATTR/@CAPTION)[1] with "New Attribute Caption"')
FROM table t
UPDATE t
SET [column_name].modify('replace value of (/ENTITY/ATTR/@SIZE)[1] with "200"')
FROM table t
UPDATE t
SET [column_name].modify('replace value of (/ENTITY/ATTR/@WIDTH)[1] with "200"')
FROM table t
答案 0 :(得分:3)
答案 1 :(得分:1)
你确实有几个选项,但可能没有比你的三个更新好多少。选项是1)重建XML或2)创建映射表。
对XML的DML操作很昂贵,因此在重构XML 可能更高效时有一个转折点 - 取决于XML的大小,要替换的属性数等等。
映射表解决方案使用循环,因此类似于三个更新解决方案。但是,您确实具有使其成为数据驱动的优势。
无论如何,请看看这个演示,让我知道你是如何进行的:
USE tempdb
GO
SET NOCOUNT ON
DECLARE @t TABLE ( yourXML XML )
INSERT INTO @t ( yourXML )
SELECT '<ENTITY NAME="entity1">
<ATTR ID="attr1" CAPTION="Attributes to Change" SIZE="100" WIDTH="100"></ATTR>
</ENTITY>'
SELECT 'before' s, * FROM @t
------------------------------------------------------------------------------------------------
-- Reconstruct the inner xml START
------------------------------------------------------------------------------------------------
-- Delete current element and attributes
UPDATE @t
SET yourXML.modify('delete ENTITY[@NAME="entity1"]/ATTR' )
DECLARE @xml XML = '', @caption VARCHAR(100), @size INT, @width INT
SELECT @caption = 'New Attribute Caption', @size = 200, @width = 300
-- Construct new element with attributes
SET @xml = @xml.query ( '<ATTR ID="attr1" CAPTION="{sql:variable("@caption")}" SIZE="{sql:variable("@size")}" WIDTH="{sql:variable("@width")}"></ATTR> ' )
-- Insert it back in
UPDATE t
SET yourXML.modify('insert sql:variable("@xml") into (ENTITY[@NAME="entity1"])[1] ')
FROM @t t
SELECT 'after' s, * FROM @t
-- Reconstruct the inner xml END
------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------
-- Create mapping table and loop START
------------------------------------------------------------------------------------------------
DECLARE @i INT = 0
DECLARE @map TABLE ( attributeName VARCHAR(50) PRIMARY KEY, newValue VARCHAR(50) NOT NULL )
INSERT INTO @map ( attributeName, newValue ) VALUES ( 'CAPTION', 'New Attribute Caption 3' )
INSERT INTO @map ( attributeName, newValue ) VALUES ( 'SIZE', 123 )
INSERT INTO @map ( attributeName, newValue ) VALUES ( 'WIDTH', 456 )
SELECT 'before 2' s, * FROM @t
WHILE 1=1
BEGIN
SET @i += 1
-- Update the XML based on the mapping table
UPDATE @t
SET yourXML.modify('replace value of (/ENTITY/ATTR/@*[local-name()= sql:column("attributeName")])[1] with sql:column("newValue")')
FROM @t
CROSS JOIN @map m
WHERE yourXML.exist('(/ENTITY/ATTR/@*[local-name()= sql:column("attributeName")][. != sql:column("newValue")])') = 1
IF @@rowcount = 0 BREAK
-- Guard against infinite loop
IF @i > 99 BEGIN RAISERROR( 'Too many loops! %i', 16, 1, @i ) BREAK END
END
SELECT @i loops
SELECT 'after' s, * FROM @t
-- Create mapping table and loop END
------------------------------------------------------------------------------------------------