0

テーブルのSQLServerXMLデータ列にいくつかのデータが格納されています。これは、HTMLコンテンツ(電子メールとして送信される)を構成するために使用され、正常に機能します。ただし、一部のデータを変更したいのですが、必要なビットだけを実行するための正しい呪文を見つけることができないようです。

例として以下を取り上げます。

declare @s1 varchar(max);
declare @s2 varchar(max);
declare @s3 varchar(max);

-- rough approximation of my data
set @s1 = '<email sender="bob"><html><body><table><tbody><tr><td><b>'
set @s2 = '</b></td></tr><tr><td><b>'
set @s3 = '</b></td></tr></tbody></table></body></html></email>'

declare @t table (id int, data xml)

insert into @t values (1, @s1 + 'Hello World' + @s2 + 'Goodbye cruel world' + @s3)
insert into @t values (2, @s1 + 'Hello World' + @s2 + 'I''m leaving you today' + @s3)
insert into @t values (3, @s1 + 'Hello World' + @s2 + 'Goodbye, goodbye, goodbye' + @s3)

select data from @t

update @t -- change sender to "fred"
set data.modify('replace value of (/email/@sender)[1] with "fred"')

select data from @t

select data,x.nd.value('b[1]','varchar(max)') -- find the "hello world" bits
from @t
cross apply data.nodes('email/html/body/table/tbody/tr/td') as x(nd)
where x.nd.value('b[1]','varchar(max)') = 'Hello World'

「送信者」データ(私が解決したと思う)と「HelloWorld」データを変更したいのですが、変更方法がわかりません。「crossapply」構文で何が起こっているのかよくわかりません。XPathのものを記述して、「where」句のない「HelloWorld」ノードのみを見つけることができると思いますか?

私のテーブルには約9行しかないため、必要に応じて9つの更新コマンドを記述できます。これは1回限りのデータ保守タスクです。

どんな助けでもいただければ幸いです。

編集:

これはその方法ですか?

update @t
set data.modify('replace value of (email/html/body/table/tbody/tr/td/b/text())[1] with "bonjour monde"')
from @t
cross apply data.nodes('email/html/body/table/tbody/tr/td') as x(nd)
where x.nd.value('b[1]','varchar(max)') = 'Hello World'

ありがとう。

4

1 に答える 1

1

ほとんど:)Editの例では最初 email/html/body/table/tbody/tr/td/bの例が更新されますが、WHERE句は任意のを検索します email/html/body/table/tbody/tr/td。したがって、たとえば2つtrあり、2番目の電子メールがフィルターと一致する電子メールがある場合でも、最初の電子メールを更新します。例えば。

 insert into @t values (4, '<email sender="bob"><html><body><table><tbody>
   <tr><td><b>Ciao mondo!</b></td></tr><tr><td><b>Goodbye, goodbye, goodbye</b></td></tr>
   <tr><td><b>Hello World</b></td></tr><tr><td><b>Can''t get rid of me!</b></td></tr>
   </tbody></table></body></html></email>');

上記のxmlは正しく更新されません。実際にはフィルターと一致しない最初のtrが変更され、変更されるべきものであるにもかかわらず、2番目のtrは影響を受けません。これにアプローチする方法はいくつかあります。個人的には、XPath/XQueryを.modify使用して作業を行います。XML.existまた、十分な場合は、クロスアプライの使用を批評します。

update @t
set data.modify('replace value of (email/html/body/table/tbody/tr/td/b[.="Hello World"]/text())[1] with "bonjour monde"')
from @t
where data.exist('email/html/body/table/tbody/tr/td/b[.="Hello World"]') = 1;

これはより正確ですが、一度に変更できるXML要素は1つだけなので、繰り返し実行する必要があります(つまり、2つtrにHello Worldがある場合、変更は最初の要素のみを更新します)。

あなたの最初のアップデートがおそらく仕事をしたので、おそらくこれらのすべてのポイントはあなたにとって学術的です。しかし、将来の参考のために。ところで、XPathフィルターがどのように機能するかを学びましょう。これらは非常に役立ちます。

于 2012-11-26T12:22:57.033 に答える