有效地从 xml 中删除节点

delete nodes from xml efficiently

这是一个挑战。 下面的代码显示了从 xml 变量中删除一些行的工作方法。 目的是删除没有将 primaryKey 属性设置为 1 的行,其中 oldValue 和 newValue 属性相同。 (我的意思是,两者都可以为空或都具有相同的值)下面的代码演示了这种情况。但是,下面的代码使用了游标。 如果可以使用单个 @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

总而言之,问题是,我怎样才能有效地完成这项工作?

"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)"

可以将其翻译成单个 @xml.modify 表达式,如下所示(在 SQL Server 2008R2 中测试和工作):

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