【问题标题】:SQL: Delete XML node in an UPDATE statementSQL:在 UPDATE 语句中删除 XML 节点
【发布时间】:2020-06-18 13:04:12
【问题描述】:

我不断收到此错误:

Incorrect use of the XML data type method 'modify'. A non-mutator method is expected in this context.

在寻找这个答案的解决方案时,我看到了这篇关于在 SELECT 语句中更新的 SO 文章:How do I UPDATE from a SELECT in SQL Server?

示例...注意:CustomProperties 字段是 nvarchar(max),我将其转换为 xml。

<CustomProperties
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <CustomProperty>
        <Dev>....</Dev>
        <Key>FieldA</Key>
        <Value>....</Value>
    </CustomProperty>
    <CustomProperty>
        <Dev>....</Dev>
        <Key>FieldB</Key>
        <Value>....</Value>
    </CustomProperty>
    <CustomProperty>
        <Dev>....</Dev>
        <Key>FieldC</Key>
        <Value>....</Value>
    </CustomProperty>
    <CustomProperty>
        <Dev>....</Dev>
        <Key>FieldD</Key>
        <Value>....</Value>
    </CustomProperty>
</CustomProperties>


DECLARE @myVar varchar(50) = 'FieldA';

UPDATE Table_1
SET 
    Table_1.CustomProperties = CONVERT(xml, Table_2.CustomProperties).modify('delete (/CustomProperties/CustomProperty[Key = sql:variable("@myVar")])')
FROM
    [dbo].MyTable AS Table_1
    INNER JOIN [dbo].MyTable AS Table_2 on Table_1.id = Table_1.id
WHERE
    // shortened for brevity

我也尝试了光标(讨厌的东西),但得到了同样的错误。

有没有一种方法可以对所有行进行全面更新。我的目标是从 CustomProperties XML 中删除此表中特定行数据的一个节点。

【问题讨论】:

  • 所以你的数据库是 SQLServer ?
  • 是的。让我更新一下问题。

标签: sql sql-server xml tsql xquery


【解决方案1】:

您已经被告知,将 XML 存储为字符串类型是一个非常糟糕的主意。在数据设计中使用适当的类型始终是最佳选择。

除此之外,如果你必须坚持这个设计(有时我们必须做一些古怪的事情),你可以试试这个:

--创建一个 mockup-table 来模拟您的问题:

DECLARE @tbl TABLE(CustomProperties VARCHAR(1000));
INSERT INTO @tbl VALUES
('<CustomProperties
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <CustomProperty>
        <Dev>....</Dev>
        <Key>FieldA</Key>
        <Value>....</Value>
    </CustomProperty>
    <CustomProperty>
        <Dev>....</Dev>
        <Key>FieldB</Key>
        <Value>....</Value>
    </CustomProperty>
    <CustomProperty>
        <Dev>....</Dev>
        <Key>FieldC</Key>
        <Value>....</Value>
    </CustomProperty>
    <CustomProperty>
        <Dev>....</Dev>
        <Key>FieldD</Key>
        <Value>....</Value>
    </CustomProperty>
</CustomProperties>');

--你的搜索字符串

DECLARE @myVar varchar(50) = 'FieldA';

--查询

UPDATE @tbl SET CustomProperties = CAST(CAST(CustomProperties AS XML)
                                   .query('
                                            <CustomProperties>
                                            {/CustomProperties/CustomProperty[Key != sql:variable("@myVar")]}
                                            </CustomProperties>
                                         ') AS VARCHAR(1000));
SELECT * FROM @tbl;

简而言之:

我们使用简单的UPDATE ... SET ... 代替XMLDML(通过.modify())并分配重新创建的XML。 XML 方法.query() 将返回一个没有&lt;CustomProperty&gt; 匹配谓词的XML。

【讨论】:

  • 是的,你已经告诉我了。不幸的是我不能改变设计。今天下午我会尝试这个解决方案并报告。与往常一样,也感谢您在答案中提供的信息。
【解决方案2】:

归结为你不能做SET CustomProperties = CONVERT(xml, CustomProperties).modify(...),因为你不能在同一个语句中结合 DML 和 XMLDML 操作。

换句话说,CustomProperties 列实际上必须是 xml sql 类型,而不是 nvarchar(max) 或其他任何类型。在这种情况下,您的 XML 删除语句将成功:

select [CustomProperties] = cast('<CustomProperties
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <CustomProperty>
        <Dev>....</Dev>
        <Key>FieldA</Key>
        <Value>....</Value>
    </CustomProperty>
    <CustomProperty>
        <Dev>....</Dev>
        <Key>FieldB</Key>
        <Value>....</Value>
    </CustomProperty>
    <CustomProperty>
        <Dev>....</Dev>
        <Key>FieldC</Key>
        <Value>....</Value>
    </CustomProperty>
    <CustomProperty>
        <Dev>....</Dev>
        <Key>FieldD</Key>
        <Value>....</Value>
    </CustomProperty>
</CustomProperties>' as xml)
into #tempTable;

declare @myVar varchar(50) = 'FieldA';

update #tempTable
set [CustomProperties].modify('delete (/CustomProperties/CustomProperty[Key = sql:variable("@myVar")])')

select * from #tempTable

产量:

<CustomProperties xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <CustomProperty>
        <Dev>....</Dev>
        <Key>FieldB</Key>
        <Value>....</Value>
    </CustomProperty>
    <CustomProperty>
        <Dev>....</Dev>
        <Key>FieldC</Key>
        <Value>....</Value>
    </CustomProperty>
    <CustomProperty>
        <Dev>....</Dev>
        <Key>FieldD</Key>
        <Value>....</Value>
    </CustomProperty>
</CustomProperties>

【讨论】:

  • 虽然你总体上是对的(我这边+1),但如果不改变桌子的设计就不能做到这一点是不正确的。看我的回答。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-02-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多