简体   繁体   English

有效地从xml中删除节点

[英]delete nodes from xml efficiently

Here's a challange.这是一个挑战。 The code below shows a working method of deleting some rows from an xml variable.下面的代码显示了从 xml 变量中删除一些行的工作方法。 The intention is to delete the rows which do not have the primaryKey attribute set to 1, where the oldValue and newValue attributes are the same.目的是删除primaryKey 属性未设置为1 的行,其中oldValue 和newValue 属性相同。 (by the same I mean, both can be null or both having the same value) The code below demonstrates this happening. (同样我的意思是,两者都可以为 null 或都具有相同的值)下面的代码演示了这种情况。 However, the code below makes use of a cursor.但是,下面的代码使用了游标。 It would not surprise me if it was possible to perform the delete using a single @xml.modify or at least without having to resort to using the cursor.如果可以使用单个 @xml.modify 或至少不必求助于使用游标来执行删除,我不会感到惊讶。

declare @xml xml ='<changes schemaName="Security" tableName="AccessProfiles">
  <column name="AccessProfileId" primaryKey="1" oldValue="114" newValue="114" />
  <column name="AccessProfileName" oldValue="test" newValue="Testing" />
  <column name="DeleteMeSame" oldValue="testValue" newValue="testValue" />
  <column name="DeleteMeNull" />
  <column name="KeepMePrimaryNull" primaryKey="1" />
  <column name="KeepMePrimarySame" primaryKey="1" oldValue="sameValue" newValue="sameValue"/>
</changes>';

declare @columnName sysname;

declare deleteNodesCursor cursor fast_forward for
    with shreddedXml as (
        select
            N.value( '@name' , 'sysname' ) as name,
            N.value( '@primaryKey' , 'bit' ) as primaryKey,
            N.value( '@oldValue' , 'varchar(max)' ) as oldValue,
            N.value( '@newValue' , 'varchar(max)' ) as newValue
        from @xml.nodes('/changes/column') as T(N)
    )
    select
        Name
    from shreddedXml
    where primaryKey is null
    and (oldValue = newValue
    or  (oldValue is null and newValue is null))

open deleteNodesCursor

while (1=1)
begin
    fetch next from deleteNodesCursor into @columnName
    if @@fetch_status != 0
        break;

    set @xml.modify( 'delete /changes[1]/column[@name= sql:variable("@columnName")]' )
end;

close deleteNodesCursor;
deallocate deleteNodesCursor;

select @xml

In summary, the question is, how can I accomplish this efficiently?总而言之,问题是,我怎样才能有效地做到这一点?

"The intention is to delete the rows which do not have the primaryKey attribute set to 1, where the oldValue and newValue attributes are the same. (by the same I mean, both can be null or both having the same value)" “目的是删除没有将 primaryKey 属性设置为 1 的行,其中 oldValue 和 newValue 属性相同。(我的意思是,两者都可以为 null 或都具有相同的值)”

That can be translated into a single @xml.modify expression as follow (tested and worked in SQL Server 2008R2) :可以将其转换为单个@xml.modify表达式,如下所示(在 SQL Server 2008R2 中测试和工作):

set @xml.modify('delete /changes/column[not(@primaryKey=1) and not(@oldValue!=@newValue)]')

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM