Question

I have an XML parameter @Xml in SQL Stored procedure like below:

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

now, I want to delete several nodes in this xml, the filter is like this (Id = 2 AND Name = 'Alex') OR (Id = 3 AND Name = 'Amy'), I don't want to use Cursor or something like this, just using one single script to do it, I am try to my best for this, but I can't get the answer, anybody can help me ? Thanks in advance!!!

The output should be :

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

PS: the filter is a #table, so, the actually question is , how to remove the specific records in XML which contains in #table?

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

I got results like this 1 Kevin

But I need the the whole xml contains Root node:

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

How can I reach this? Any help? I am an new leaner for SQL to XML, please help me !!!

Was it helpful?

Solution

I got the answer, thanks all you guys

    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'+@sql+''')'
    select @sql
    exec sp_executesql @sql, N'@xml xml output', @xml output
    select @xml

OTHER TIPS

You can shred the xml on the nodes in the root node @xml.nodes('/Root/*') and rebuild it using the XML from the shredded nodes R.X.query('.').

In a where not exists clause you exclude the Data nodes that is present in the temp table.

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

Result:

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

SQL Fiddle

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top