Как изменить значение узла, используя текущее значение узла в SQL с помощью XQuery (SQL Server)

Как я могу изменить:

<data>
  <row>
    <a>A</a>
    <a>B</a>
    <a>C</a>
  </row>
</data>

to:

<data>
  <row>
    <a>Data A</a>
    <a>Data B</a>
    <a>Data C</a>
  </row>
</data>

в SQL? Я видел много примеров того, как полностью заменить значение статическим значением, но ни одного примера динамической замены значения.


person Brian    schedule 30.03.2011    source источник


Ответы (3)


Я не знаю, можно ли использовать xml в операторе replace value of. Но вы можете это сделать.

declare @xml xml = '
<data>
  <row>
    <a>A</a>
    <a>B</a>
    <a>C</a>
  </row>
</data>'

declare @Val1 varchar(10) 
declare @Val2 varchar(10) 
declare @Val3 varchar(10) 

select 
  @Val1 = 'Data '+r.value('a[1]', 'varchar(1)'), 
  @Val2 = 'Data '+r.value('a[2]', 'varchar(1)'), 
  @Val3 = 'Data '+r.value('a[3]', 'varchar(1)') 
from @xml.nodes('/data/row') n(r)

set @xml.modify('replace value of (/data/row/a/text())[1] with (sql:variable("@val1"))')
set @xml.modify('replace value of (/data/row/a/text())[2] with (sql:variable("@val2"))')
set @xml.modify('replace value of (/data/row/a/text())[3] with (sql:variable("@val3"))')

Версия 2

declare @xml xml = '
<data>
  <row>
    <a>A</a>
    <a>B</a>
    <a>C</a>
  </row>
  <row>
    <a>1</a>
    <a>2</a>
    <a>3</a>
  </row>
</data>'

;with cte as
(
  select
    r.query('.') as Row,
    row_number() over(order by (select 0)) as rn
  from @xml.nodes('/data/row') n(r)
)
select
  (select 
     'Data '+a.value('.', 'varchar(1)')
   from cte as c2
     cross apply Row.nodes('row/a') as r(a)
   where c1.rn = c2.rn
   for xml path('a'), root('row'), type)  
from cte as c1 
group by rn
for xml path(''), root('data')
person Mikael Eriksson    schedule 30.03.2011
comment
Спасибо Микаэль. Я видел это решение на других сайтах, но оно не динамическое. Что делать, если у меня есть 1000 тегов строк с 1-100 тегами a в каждом? - person Brian; 30.03.2011

У меня была такая же проблема, но я нашел другое решение, я думаю;)

for $n in /data/row
 return replace value of node $n with concat('Data',$n/text())

Искренне

person Christian    schedule 30.01.2014

Вот еще один далеко не идеальный способ сделать это.

SET @temp.modify('replace value of (/data/row/node()/text())[1] with concat("Data ", (/data/row/node()/text())[1])')
SET @temp.modify('replace value of (/data/row/node()/text())[2] with concat("Data ", (/data/row/node()/text())[2])')
SET @temp.modify('replace value of (/data/row/node()/text())[3] with concat("Data ", (/data/row/node()/text())[3])')

Недостатком этого метода является то, что для каждого дочернего элемента строки требуется отдельный оператор. Это работает только в том случае, если вы заранее знаете, сколько потомков будет у узла строки.

person Jason L.    schedule 01.05.2014