Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Microsoft SQL Server Новый топик    Ответить
 Массовый апдейт xml  [new]
Megabyte
Member

Откуда: ближайшее заМКАДье
Сообщений: 4885
Коллеги, добрый день.

Возникла необходимость массового изменения нод в xml.

Дано:
@xml xml = <root>
...
<Endpoint profile="cnghfn" login="bla1" />
<Endpoint profile="bnjhg" login="bla2" />
<Endpoint profile="7hnghf" login="bla3" />
<Endpoint profile="7hnghf" login="bla4" />
<Endpoint profile="bnjhg" login="bla5" />
<Endpoint profile="7hnghf" login="bla6" />
<Endpoint profile="7hnghf" login="bla7" />
...
<root/>

Цель, надо изменить атрибут profile у тех нодов Endpoint , у которых profile = "7hnghf" и при этом у этих логинов указан определенный статус в обычной таблице.

Это реальный запрос на выборку нужных записей.
select
		[login] = x.z.value('@login', 'varchar(50)') 
		,[profile] = x.z.value('@profile', 'varchar(100)')
	from @xml.nodes('*/DialPlan/CallPlan/Endpoint') x(z)
		LEFT JOIN Control.dbo.users u with(NOLOCK) ON u.user_number = x.z.value('@login', 'varchar(50)')
	WHERE u.user_status IN (1, 6)


Ранее с xml работал только на select, и, в основном, через openxml.
Почитал про метод xml.modify, но, как я понял, им можно только 1 значение поменять.
Не хочется в цикле\курсоре это делать.

Одним запросом возможно? Подскажите, в какую сторону копать?
---
Проходя мимо разложенных граблей, ты теряешь драгоценный опыт. (с)
24 окт 17, 17:08    [20896306]     Ответить | Цитировать Сообщить модератору
 Re: Массовый апдейт xml  [new]
LoopN
Guest
Megabyte
Коллеги, добрый день.

Возникла необходимость массового изменения нод в xml.

Дано:
@xml xml = <root>
...
<Endpoint profile="cnghfn" login="bla1" />
<Endpoint profile="bnjhg" login="bla2" />
<Endpoint profile="7hnghf" login="bla3" />
<Endpoint profile="7hnghf" login="bla4" />
<Endpoint profile="bnjhg" login="bla5" />
<Endpoint profile="7hnghf" login="bla6" />
<Endpoint profile="7hnghf" login="bla7" />
...
<root/>

Цель, надо изменить атрибут profile у тех нодов Endpoint , у которых profile = "7hnghf" и при этом у этих логинов указан определенный статус в обычной таблице.

Это реальный запрос на выборку нужных записей.
select
		[login] = x.z.value('@login', 'varchar(50)') 
		,[profile] = x.z.value('@profile', 'varchar(100)')
	from @xml.nodes('*/DialPlan/CallPlan/Endpoint') x(z)
		LEFT JOIN Control.dbo.users u with(NOLOCK) ON u.user_number = x.z.value('@login', 'varchar(50)')
	WHERE u.user_status IN (1, 6)


Ранее с xml работал только на select, и, в основном, через openxml.
Почитал про метод xml.modify, но, как я понял, им можно только 1 значение поменять.
Не хочется в цикле\курсоре это делать.

Одним запросом возможно? Подскажите, в какую сторону копать?
---
Проходя мимо разложенных граблей, ты теряешь драгоценный опыт. (с)

только циклом или курсором.
24 окт 17, 17:26    [20896375]     Ответить | Цитировать Сообщить модератору
 Re: Массовый апдейт xml  [new]
Minamoto
Member

Откуда: Москва
Сообщений: 1162
Megabyte, 20756442 - такого ответа вам хватит, или подробнее расписать?
24 окт 17, 17:53    [20896458]     Ответить | Цитировать Сообщить модератору
 Re: Массовый апдейт xml  [new]
Megabyte
Member

Откуда: ближайшее заМКАДье
Сообщений: 4885
Minamoto
Megabyte, 20756442 - такого ответа вам хватит, или подробнее расписать?

В целом идея понятна.

Я только пока не уверен или не понял, подойдет ли она для моего варианта.
Дело в том, что нода Endpoint иногда может иметь подноды:
<Endpoint ...">
 <State>
     <SubState name="..."/>
    </State>
    <Address url="..."/>
   </Endpoint>

Не знаю, повлияет ли это на использование вашего варианта.

Решил пока сделать через курсор, но остался вопрос про метод modify.
Каким образом в нем указать, что мне нужно изменить ноду с таким-то значением атрибута?
SET @DialPlan.modify('  
		replace value of (.../Endpoint/@profile)[1] //узел, как я понял, должен быть всегда 1 
      )  
	')  
- нужно изменить, допустим, в ноде, где login = 'bla4'!
24 окт 17, 18:09    [20896489]     Ответить | Цитировать Сообщить модератору
 Re: Массовый апдейт xml  [new]
felix_ff
Member

Откуда: Moscow
Сообщений: 1172
Megabyte,

replace value of (.../Endpoint[@login="blablabla"]/@profile)[1] 
24 окт 17, 18:52    [20896569]     Ответить | Цитировать Сообщить модератору
 Re: Массовый апдейт xml  [new]
Megabyte
Member

Откуда: ближайшее заМКАДье
Сообщений: 4885
felix_ff , спасибо.
24 окт 17, 18:57    [20896575]     Ответить | Цитировать Сообщить модератору
 Re: Массовый апдейт xml  [new]
felix_ff
Member

Откуда: Moscow
Сообщений: 1172
Megabyte,

ознакомьтесь кстати с ссылочкой, там неплохой пример итеративной обработки

https://social.technet.microsoft.com/wiki/contents/articles/28601.t-sql-tips-search-and-replace-string-from-multiple-nodes-within-a-xml-document.aspx
24 окт 17, 19:00    [20896578]     Ответить | Цитировать Сообщить модератору
 Re: Массовый апдейт xml  [new]
invm
Member

Откуда: Москва
Сообщений: 9122
Megabyte
Одним запросом возможно?
use tempdb;
go

create function dbo.fnModifyProfile
(
 @xml xml,
 @l sysname,
 @old_profile nvarchar(30),
 @new_profile nvarchar(30)
)
returns xml
as
begin
 set @xml.modify('replace value of (/root/Endpoint[@profile = sql:variable("@old_profile") and @login = sql:variable("@l")]/@profile)[1] with sql:variable("@new_profile")');
 return @xml;
end;
go

declare @xml xml = N'<root>
<Endpoint profile="cnghfn" login="bla1" />
<Endpoint profile="bnjhg" login="bla2" />
<Endpoint profile="7hnghf" login="bla3" />
<Endpoint profile="7hnghf" login="bla4" />
<Endpoint profile="bnjhg" login="bla5" />
<Endpoint profile="7hnghf" login="bla6" />
<Endpoint profile="7hnghf" login="bla7" />
</root>';

declare @l table (l sysname)
insert into @l
values
 (N'bla1'), (N'bla2'), (N'bla3'), (N'bla4'), (N'bla5'), (N'bla6'), (N'bla7');

select @xml;

update @l
 set
  @xml = dbo.fnModifyProfile(@xml, l, '7hnghf', '8hnghf');

select @xml;
go

drop function dbo.fnModifyProfile;
go
24 окт 17, 19:07    [20896589]     Ответить | Цитировать Сообщить модератору
 Re: Массовый апдейт xml  [new]
Megabyte
Member

Откуда: ближайшее заМКАДье
Сообщений: 4885
Коллеги, спасибо. Вопрос решен.
25 окт 17, 11:03    [20897885]     Ответить | Цитировать Сообщить модератору
 Re: Массовый апдейт xml  [new]
AlanDenton
Member [скрыт]

Откуда:
Сообщений: 1004
Как вариант - пересоздать XML:

DECLARE @xml XML = '
<root>
    <Endpoint profile="cnghfn" login="bla1" />
    <Endpoint profile="bnjhg" login="bla2" />
    <Endpoint profile="7hnghf" login="bla3" />
    <Endpoint profile="7hnghf" login="bla4" />
    <Endpoint profile="bnjhg" login="bla5" />
    <Endpoint profile="7hnghf" login="bla6" />
    <Endpoint profile="7hnghf" login="bla7" />
</root>'

SELECT [@profile] = REPLACE([profile], '7hnghf', '8hnghf')
     , [@login] = [login]
FROM (
    SELECT [profile] = t.c.value('@profile', 'SYSNAME')
         , [login] = t.c.value('@login', 'SYSNAME')
    FROM @xml.nodes('*/*') t(c)
) t
FOR XML PATH('Endpoint'), ROOT('root')
27 окт 17, 17:15    [20907478]     Ответить | Цитировать Сообщить модератору
Все форумы / Microsoft SQL Server Ответить