Frage

ich habe:

  1. Sie eine Tabelle mit xml Typ Spalte (Liste der IDs)
  2. ein xml Typparameter (auch Liste der IDs)

Was ist der beste Weg, Knoten aus der Säule zu entfernen, die die Knoten in dem Parameter übereinstimmen, während alle nicht angepassten Knoten unangetastet bleiben?

z.

declare @table table (
    [column] xml
)

insert @table ([column]) values ('<r><i>1</i><i>2</i><i>3</i></r>')

declare @parameter xml
set @parameter = '<r><i>1</i><i>2</i></r>'

-- this is the problem
update @table set [column].modify('delete (//i *where text() matches @parameter*)')

Die MSDN-Dokumentation gibt an, sollte es möglich sein (in Einführung in XQuery in SQL Server 2005 ):

  

Diese gespeicherte Prozedur kann leicht sein   modifiziert, um ein XML-Fragment zu akzeptieren,   der eine oder mehr Geschick   Elemente, wodurch ermöglicht wird, um den Benutzer zu   Löschen mehrerer Fähigkeiten Knoten mit einem   einziger Aufruf der gespeicherten Prozedur.

War es hilfreich?

Lösung

Während der Lösch ein wenig umständlich ist, so zu tun, können Sie stattdessen ein Update tun, um die Daten zu ändern, sofern Ihre Daten einfach sind (wie das Beispiel, das Sie gegeben haben). Die folgende Abfrage wird geteilt grundsätzlich die beiden XML-Strings in Tabellen, sich anzuschließen, schließen Sie die Nicht-Null (Matching) Werte, und wandeln es wieder in XML:

UPDATE @table 
SET [column] = (
    SELECT p.i.value('.','int') AS c
    FROM [column].nodes('//i') AS p(i)
    OUTER APPLY (
        SELECT x.i.value('.','bigint') AS i
        FROM @parameter.nodes('//i') AS x(i)
        WHERE p.i.value('.','bigint') = x.i.value('.','int')
    ) a
    WHERE a.i IS NULL
    FOR XML PATH(''), TYPE
)

Andere Tipps

Sie müssen etwas in der Form:

[column].modify('delete (//i[.=(1, 2)])') -- like SQL IN
-- or
[column].modify('delete (//i[.=1 or .=2])')
-- or
[column].modify('delete (//i[.=1], //i[.=2])')
-- or
[column].modify('delete (//i[contains("|1|2|",concat("|",.,"|"))])')

XQuery nicht xml SQL-Typen in SQL2005 unterstützen, und die ändern Methode akzeptiert nur Zeichenketten (keine Variablen erlaubt).

Hier ist ein hässliches Hack w / die Funktion contains:

declare @table table ([column] xml)
insert @table ([column]) values ('<r><i>1</i><i>2</i><i>3</i></r>')

declare @parameter xml
set @parameter = '<r><i>1</i><i>2</i></r>'

-- build a pipe-delimited string
declare @in nvarchar(max)
set @in = convert(nvarchar(max),
    @parameter.query('for $i in (/r/i) return concat(string($i),"|")')
  )
set @in = '|'+replace(@in,'| ','|')

update @table set [column].modify ('
  delete (//i[contains(sql:variable("@in"),concat("|",.,"|"))])
  ')
select * from @table

Hier ist eine andere w / dynamische SQL:

-- replace table variable with temp table to get around variable scoping
if object_id('tempdb..#table') is not null drop table #table
create table #table ([column] xml)
insert #table ([column]) values ('<r><i>1</i><i>2</i><i>3</i></r>')

declare @parameter xml
set @parameter = '<r><i>1</i><i>2</i></r>'

-- we need dymamic SQL because the XML modify method only permits string literals
declare @sql nvarchar(max)
set @sql = convert(nvarchar(max), 
    @parameter.query('for $i in (/r/i) return concat(string($i),",")')
  )
set @sql = substring(@sql,1,len(@sql)-1)
set @sql = 'update #table set [column].modify(''delete (//i[.=('+@sql+')])'')'
print @sql
exec (@sql)

select * from #table

Wenn Sie ein XML-Variable, anstatt eine Spalte aktualisieren, verwenden Sp_executesql und Ausgangsparameter:

declare @xml xml
set @xml = '<r><i>1</i><i>2</i><i>3</i></r>'

declare @parameter xml
set @parameter = '<r><i>1</i><i>2</i></r>'

declare @sql nvarchar(max)
set @sql = convert(nvarchar(max), 
    @parameter.query('for $i in (/r/i) return concat(string($i),",")')
  )
set @sql = substring(@sql,1,len(@sql)-1)
set @sql = 'set @xml.modify(''delete (//i[.=('+@sql+')])'')'
exec sp_executesql @sql, N'@xml xml output', @xml output

select @xml

Alternative Verfahren unter Verwendung eines Cursors durch Lösch Werte zu durchlaufen, wahrscheinlich weniger effizient durch mehrere Updates:

declare @table table ([column] xml)
insert @table ([column]) values ('<r><i>1</i><i>2</i><i>3</i></r>')

declare @parameter xml
set @parameter = '<r><i>1</i><i>2</i></r>'

/*
-- unfortunately, this doesn't work:
update t set [column].modify('delete (//i[.=sql:column("p.i")])')
from @table t, (
  select i.value('.', 'nvarchar')
  from @parameter.nodes('//i') a (i)
  ) p (i)
select * from @table
*/

-- so we have to use a cursor
declare @cursor cursor
set @cursor = cursor for
  select i.value('.', 'varchar') as i
  from @parameter.nodes('//i') a (i)

declare @i int
open @cursor
while 1=1 begin
  fetch next from @cursor into @i
  if @@fetch_status <> 0 break
  update @table set [column].modify('delete (//i[.=sql:variable("@i")])')
end

select * from @table

Weitere Informationen zu den Einschränkungen von XML-Variablen in SQL2005 hier:

http://blogs.msdn.com/denisruc /archive/2006/05/17/600250.aspx

Hat jemand einen besseren Weg?

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top