【问题标题】:Update multiple attributes on sql server xml data field at once一次更新sql server xml数据字段的多个属性
【发布时间】:2012-08-07 02:28:59
【问题描述】:

是否可以在一个更新中修改单个节点上的多个属性?

我有类似的东西:

<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

【问题讨论】:

标签: sql-server xml


【解决方案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
------------------------------------------------------------------------------------------------

【讨论】:

  • 谢谢,我已经着手重建整个 XML 字符串,一次完成所有更改。
【解决方案2】:

不,这是不可能的。

来自replace value of (XML DML)

表达式1
标识要更新其值的节点。它必须 只识别一个节点。也就是说,Expression1 必须是静态的 单身人士。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-08-26
    • 2011-02-22
    • 2018-08-31
    • 1970-01-01
    • 2015-10-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多