2014-03-07 73 views
1

我有一个XML参数@xml在SQL存储过程像下面使用循环:如何使用XQuery删除XML节点

<Root> 
    <Data> 
    <Id>1</Id> 
    <Name>Kevin</Name> 
    <Des>Des1</Des> 
    </Data> 
    <Data> 
    <Id>2</Id> 
    <Name>Alex</Name> 
    <Des>Des2</Des> 
    </Data> 
    <Data> 
    <Id>3</Id> 
    <Name>Amy</Name> 
    <Des>Des3</Des> 
    </Data> 
</Root> 

现在,我想在这个XML删除几个节点,过滤器像这样(Id = 2 AND Name ='Alex')OR(Id = 3 AND Name ='Amy'),我不想使用Cursor或类似的东西,只用一个脚本来完成,我是尽我所能为此,但我无法得到答案,任何人都可以帮助我?提前致谢!!!

输出应该是:

<Root> 
    <Data> 
    <Id>1</Id> 
    <Name>Kevin</Name> 
    <Des>Des1</Des> 
    </Data> 
</Root> 

PS:过滤器是#table,因此,实际的问题是,如何去除其中含有#table XML的具体记录?

Id Name 
2  Alex 
3  Amy 

Declare @Xml XML 
set @Xml = '<Root> 
    <Data> 
    <Id>1</Id> 
    <Name>Kevin</Name> 
    <Des>Des1</Des> 
    </Data> 
    <Data> 
    <Id>2</Id> 
    <Name>Alex</Name> 
    <Des>Des2</Des> 
    </Data> 
    <Data> 
    <Id>3</Id> 
    <Name>Amy</Name> 
    <Des>Des3</Des> 
    </Data> 
</Root>' 

create TABLE #tempResult 
(
    Id Int, 
    Name Varchar(10) 
) 

insert into #tempResult 
values(2, 'Alex'), (3, 'Amy') 

SET @Xml = (
SELECT Node.value('Id[1]','int') AS PId, Node.value('Name[1]','Varchar(10)') AS PName 
FROM @Xml.nodes('//Data') AS T(Node) 
OUTER APPLY (
    SELECT tr.Id, tr.Name 
    FROM #tempResult tr 
    WHERE Node.value('Id[1]','int') = tr.Id and Node.value('Name[1]','Varchar(10)') = tr.Name 
) a 
WHERE a.Id IS NULL 
FOR XML PATH(''), TYPE 
) 

select @Xml 
drop table #tempResult 

我喜欢这个凯文

结果,但我需要的整个XML包含根节点:

<Root> 
    <Data> 
    <Id>1</Id> 
    <Name>Kevin</Name> 
    <Des>Des1</Des> 
    </Data> 
</Root> 

我怎么能达到呢?任何帮助?我是SQL到XML的新精简者,请帮助我!

+1

这种重复的链接只是删除特定记录在一个表中,我想删除在XML参数的记录,这是不同的... –

+2

它没有什么不同。你只需要指向你的参数/变量而不是表格列,该方法是相同的。 – JNK

+1

@JNK提出的问题是关于使用另一个XML从XML中删除项目,该项目*与您的问题不同,但[其中一个答案](http://stackoverflow.com/questions/1020305/deleting-multiple -nodes-in-single-xquery-for-sql-server/1020821#1020821)确实包含适合你的有用信息,提供了在多种情况下删除多个节点的各种方法。您只需要将变量的引用替换为列引用即可。 –

回答

1

我得到了答案,感谢所有你们

declare @xml xml 
    set @xml = '<Root><Header>123</Header><Data><Id>1</Id><Name>Kevin</Name><Des>Des1</Des></Data><Data><Id>2</Id><Name>Alex</Name><Des>Des2</Des></Data><Data><Id>3</Id><Name>Amy</Name><Des>Des3</Des></Data><Tail>456</Tail></Root>' 
    --set @xml.modify('delete /Root/Data[(Id[.=1] and Name[.="Kevin"]) or (Id[.=2] and Name[.="Alex"])]') 
    select @xml 
    declare @parameter XML 
    set @parameter = (SELECT Node.value('(Id)[1]', 'Int') AS Id, 
          Node.value('(Name)[1]', 'Varchar(10)') AS Name 
        FROM @xml.nodes('Root/Data') TempXML(Node) 
        WHERE Node.value('(Id)[1]', 'Int') != 3 
        for xml path('Root'), TYPE) 
    --select @parameter 
    declare @sql nvarchar(max) 
    set @sql = convert(nvarchar(max), 
    @parameter.query('for $i in (/Root) return concat("(Id[.=", 
                  string($i/Id[1]), 
                  "] and Name[.=""", 
                  string($i/Name[1]), 
                  """]) or")') 
                  ) 
    set @sql = '['+substring(@sql,0,len(@sql)-2)+']' 
    set @sql = 'set @xml.modify(''delete /Root/Data'[email protected]+''')' 
    select @sql 
    exec sp_executesql @sql, N'@xml xml output', @xml output 
    select @xml 
0

您可以撕碎节点上的XML根节点@xml.nodes('/Root/*')并使用XML从粉碎的节点R.X.query('.')重建。

where not exists子句中,排除了存在于临时表中的数据节点。

select R.X.query('.') 
from @xml.nodes('/Root/*') as R(X) 
where not exists (
       select * 
       from #tempResult as T 
       where T.Id = R.X.value('(Id/text())[1]', 'int') and 
         T.Name = R.X.value('(Name/text())[1]', 'varchar(100)') and 
         R.X.value('local-name(.)', 'varchar(100)') = 'Data' 
       ) 
for xml path(''), root('Root'), type 

结果:

<Root> 
    <Header>123</Header> 
    <Data> 
    <Id>1</Id> 
    <Name>Kevin</Name> 
    <Des>Des1</Des> 
    </Data> 
    <Tail>456</Tail> 
</Root> 

SQL Fiddle