有效地从 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)]')
这是一个挑战。 下面的代码显示了从 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)]')