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

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

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

чтобы:

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

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

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

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

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

Искренне

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

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

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

Другие вопросы по тегам