5

私は持っている:

  1. xml型の列を持つテーブル(ID のリスト)
  2. xml型パラメーター (ID のリストも)

パラメータ内のノードに一致するノードを列から削除し、一致しないノードはそのままにしておく最善の方法は何ですか?

例えば

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*)')

MSDN のドキュメントでは、可能であることが示されています ( Introduction to XQuery in SQL Server 2005 で)。

このストアド プロシージャは、1 つ以上のスキル要素を含む XML フラグメントを受け入れるように簡単に変更できるため、ユーザーはストアド プロシージャを 1 回呼び出すだけで複数のスキル ノードを削除できます。

4

2 に答える 2

3

この方法で削除するのは少し厄介ですが、データが単純な場合(例のように)、代わりに更新を行ってデータを変更することができます。次のクエリは、基本的に2つのXML文字列をテーブルに分割し、それらを結合し、null以外の(一致する)値を除外して、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
)
于 2009-06-22T17:54:37.947 に答える
3

次の形式のものが必要です。

[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 は SQL2005 の xml SQL 型をサポートしておらず、modify メソッドは文字列リテラルのみを受け入れます (変数は許可されていません)。

これは、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

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

列ではなく xml 変数を更新する場合は、sp_executesql と出力パラメーターを使用します。

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

カーソルを使用して削除値を反復処理する別の方法。おそらく複数の更新により効率が低下します。

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

SQL2005 での XML 変数の制限の詳細については、次を参照してください。

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

誰かがより良い方法を持っていますか?

于 2009-06-20T02:55:52.450 に答える