Как изменить подузлы xml с помощью XQuery на SQL Server

Для поля xml (SQL Server) мне нужно добавить узел в каждый подузел на основе исходной таблицы и условия. Это мои данные xml:

declare @X table (XMLDATA xml)
insert @X values('
<row>
  <node>
    <name>Francesco</name>
  </name>
  <node>
    <label>Alessandro</name>
  </node>
  <node>
    <name>Daniele</name>
  </node>
</row>')

Для каждого <name> я хочу добавить узел <number>. Совпадения номеров и имен записываются в таблицу @T:

declare @T table (name varchar(20), number int)
insert @T values
('Alessandro', 24)
,('Francesco', 10)
,('Daniele', 16)

Для обновления узлов я использую XMLDATA.modify и использую условия xpath для выбора правильного узла:

update @X set XMLDATA.modify('insert element number {sql:column("number")} as last into (row/node[name=sql:column("name")])[1]')
from @X
cross join @T

Приведенный выше запрос работает только для первой строки @T (в примере это Alessandro/24). Остальные 2 строки @T игнорируются. Мне нужно добавить number к каждому node. Это окончательные XMLDATA:

<row>
  <node>
    <name>Francesco</name>
  </node>
  <node>
    <name>Alessandro</name>
    <number>24</number>
  </node>
  <node>
    <name>Daniele</name>
  </node>
</row>

person Radioleao    schedule 07.02.2017    source источник
comment
Даже если ответ Ронака Пателя является хорошим обходным путем (который я оценил), я хотел бы знать, как работает fieldxml.modify() и синтаксис для обновления многих узлов подряд. Я ошибаюсь, и обходной путь, который мне помог, должен быть помечен как правильный ответ?   -  person Radioleao    schedule 16.02.2017
comment
Правильное замечание ... Ниже моего ответа вы прокомментировали * Я просто пишу образец подмножества * (пожалуйста, добавьте ожидаемый результат, соответствующий образцу). Это поможет дать вам точный ответ.   -  person Shnugo    schedule 16.02.2017
comment
Я написал, что у меня сотни нод на разном уровне. Необходимо, чтобы я разместил реальный пример, чтобы задать синтаксис MS SQL?   -  person Radioleao    schedule 20.02.2017
comment
Конечно! Ваш вопрос сильно зависит от фактической структуры вашего XML. Пожалуйста, создайте (сокращенный) XML и ожидаемый результат. Это может быть ясно для вас, но для постороннего человека это не так.   -  person Shnugo    schedule 20.02.2017


Ответы (2)


Я использую цикл while. Пожалуйста, проверьте приведенный ниже код, он может вам помочь.

declare @X table (XMLDATA xml)
insert @X values('
<row>
  <node>
    <name>Alessandro</name>
  </node>
  <node>
    <name>Francesco</name>
  </node>
  <node>
    <name>Daniele</name>
  </node>
</row>')


declare @T table (name1 varchar(20), number int,RowID int identity(1,1) not null)
insert @T values
('Alessandro', 24)
,('Francesco', 10)
,('Daniele', 16)

DECLARE @i int,@iCount int,@namevalue varchar(100)='',@number int
SET @i = 1


SELECT @iCount=MAX(RowID) FROM @T

WHILE (@i <= @iCount)
BEGIN

SELECT @namevalue=name1 FROM @T WHERE RowID=@i
SELECT @number=number FROM @T WHERE RowID=@i

update @X set XMLDATA.modify('insert element number {sql:variable("@number")} as last into (row/node)[name=sql:variable("@namevalue")][1]')
from @X
cross join @T

  SET @i = @i + 1
END

SELECT * FROM @X

Выход :

<row>
  <node>
    <name>Alessandro</name>
    <number>24</number>
  </node>
  <node>
    <name>Francesco</name>
    <number>10</number>
  </node>
  <node>
    <name>Daniele</name>
    <number>16</number>
  </node>
</row>

Спасибо .

person Ronak Patel    schedule 07.02.2017
comment
Это хорошее решение, мне даже больше нравится, если вы используете курсор вместо цикла. Я хотел бы найти правильный запрос на обновление без использования цикла, но это хороший обходной путь. Спасибо - person Radioleao; 07.02.2017
comment
Это лучшее решение, которое я получил. Я ожидал какого-то другого синтаксиса для работы с подузлами, но, боюсь, его нет. - person Radioleao; 03.03.2017

Если ваши реальные данные так же просты, как в примере, решение может быть найдено намного проще:

declare @X table (XMLDATA xml)
insert @X values(
'<row>
  <node>
    <name>Francesco</name>
  </node>
  <node>
    <name>Alessandro</name>
  </node>
  <node>
    <name>Daniele</name>
  </node>
</row>')

declare @T table (name varchar(20), number int)
insert @T values
('Alessandro', 24)
,('Francesco', 10)
,('Daniele', 16);

SELECT nm.value(N'.','nvarchar(max)') AS name
        ,t.number 
FROM @X
CROSS APPLY XMLDATA.nodes(N'/row/node/name') AS A(nm)
INNER JOIN @T AS t ON t.name=nm.value(N'.','nvarchar(max)')
FOR XML PATH('node'),ROOT('row')

Если это не работает для вас, пожалуйста, предоставьте более реалистичные примеры данных!

person Shnugo    schedule 07.02.2017
comment
У меня есть сотни узлов и множество подузлов. Я просто пишу образец подмножества, чтобы быть максимально понятным. - person Radioleao; 08.02.2017