#sql-server #xml #sql-server-2008 #xpath #xquery
#sql-сервер #xml #sql-server-2008 #xpath #xquery
Вопрос:
У меня есть таблица с именем Schemes, в которой XML
структурированный файл хранится как VARCHAR
в столбце.XML-файл выглядит следующим образом,
<Process>
<Timers>
<Timer Name="SendNotificationStaffLevel1" Type="Interval" Value="25m"
NotOverrideIfExists="true" />
<Timer Name="SendNotificationSecretaryLevel1" Type="Interval" Value="600m"
NotOverrideIfExists="true" />
<Timer Name="ReAssigningRequestToSecretaryLevel1" Type="Interval"
Value="605m" NotOverrideIfExists="true" />
<Timer Name="SendNotificationStaffLevel2" Type="Interval" Value="5m"
NotOverrideIfExists="true" />
<Timer Name="SendNotificationSecretaryLevel2" Type="Interval" Value="10m"
NotOverrideIfExists="true" />
<Timer Name="ReAssigningRequestToSecretaryLevel2" Type="Interval"
Value="12m" NotOverrideIfExists="true" />
<Timer Name="DeactivateUrlOfFileResubmission" Type="Interval" Value="15m"
NotOverrideIfExists="true" />
</Timers>
</process>
Мне нужно обновить значение каждого таймера, указав атрибут name, а именно. «SendNotificationStaffLevel1» в качестве параметра для хранимой процедуры.
Я попытался
update YourTable set
XMLText.modify('replace value of (/Process/Timers/Timer/@Value)[1] with "40m"')
where XMLText.value('(/Process/Timers/Timer/@Value)[1]', 'varchar') = 25m
Но мне нужно указать атрибут name для обновления значения.Как это можно сделать?Заранее спасибо.
Комментарии:
1. У меня нет контроля над содержимым таблицы и типами данных. Он заполняется автоматически.
Ответ №1:
Вы можете добавить значение фильтра атрибута к предикату в Xpath
, как здесь:
DECLARE @xml XML=
'<Process>
<Timers>
<Timer Name="SendNotificationStaffLevel1" Type="Interval" Value="25m" NotOverrideIfExists="true" />
<Timer Name="SendNotificationSecretaryLevel1" Type="Interval" Value="600m" NotOverrideIfExists="true" />
<Timer Name="ReAssigningRequestToSecretaryLevel1" Type="Interval" Value="605m" NotOverrideIfExists="true" />
<Timer Name="SendNotificationStaffLevel2" Type="Interval" Value="5m" NotOverrideIfExists="true" />
<Timer Name="SendNotificationSecretaryLevel2" Type="Interval" Value="10m" NotOverrideIfExists="true" />
<Timer Name="ReAssigningRequestToSecretaryLevel2" Type="Interval" Value="12m" NotOverrideIfExists="true" />
<Timer Name="DeactivateUrlOfFileResubmission" Type="Interval" Value="15m" NotOverrideIfExists="true" />
</Timers>
</Process>';
DECLARE @Name VARCHAR(100)='SendNotificationStaffLevel1';
SET @xml.modify('replace value of (/Process/Timers/Timer[@Name=sql:variable("@Name")]/@Value)[1] with "40m"');
SELECT @xml;
Вы можете прочитать Xpath
как:
- Начните с
<Process>
- Погрузитесь глубже в
<Timers>
, затем в<Timer>
- Найдите первое (
[1]
) событие, в котором имя атрибута похоже на внешнюю переменную - Измените атрибут
@Value
С помощью табличных данных
Вы можете легко адаптировать вышеописанное для работы со столбцом таблицы, но:
Если XML сохранен как VARCHAR(x)
, вы должны обмануть его. .modify()
требуется собственный тип XML, и вы не можете обновить приведенный столбец. Я бы предложил написать промежуточную таблицу, выполнить обновление там и записать его обратно:
Макетная таблица:
DECLARE @mockup TABLE(ID INT IDENTITY, YourXmlAsString VARCHAR(MAX));
INSERT INTO @mockup VALUES
('<Process>
<Timers>
<Timer Name="SendNotificationStaffLevel1" Type="Interval" Value="25m" NotOverrideIfExists="true" />
<Timer Name="SendNotificationSecretaryLevel1" Type="Interval" Value="600m" NotOverrideIfExists="true" />
<Timer Name="ReAssigningRequestToSecretaryLevel1" Type="Interval" Value="605m" NotOverrideIfExists="true" />
<Timer Name="SendNotificationStaffLevel2" Type="Interval" Value="5m" NotOverrideIfExists="true" />
<Timer Name="SendNotificationSecretaryLevel2" Type="Interval" Value="10m" NotOverrideIfExists="true" />
<Timer Name="ReAssigningRequestToSecretaryLevel2" Type="Interval" Value="12m" NotOverrideIfExists="true" />
<Timer Name="DeactivateUrlOfFileResubmission" Type="Interval" Value="15m" NotOverrideIfExists="true" />
</Timers>
</Process>');
—Запишите приведенный столбец во временную таблицу
SELECT ID
,YourXmlAsString --<-- You don't need this actually
,CAST(YourXmlAsString AS XML) YourXmlAsXml
INTO #tmpTable
FROM @mockup ;
—Выполните обновление
DECLARE @Name VARCHAR(100)='SendNotificationStaffLevel1';
UPDATE #tmpTable
SET YourXmlAsXml .modify('replace value of (/Process/Timers/Timer[@Name=sql:variable("@Name")]/@Value)[1] with "40m"');
—Обновите исходную таблицу
UPDATE t
SET YourXmlAsString=CAST(tmp.YourXmlAsXml AS VARCHAR(MAX))
FROM #tmpTable tmp
INNER JOIN @mockup t ON tmp.ID=t.ID;
—Проверьте результат
SELECT * FROM @mockup;
Подсказка:
Если есть какая-либо возможность изменить тип столбца на XML, вам действительно следует это сделать…
Ответ №2:
Примеры, которые я нахожу, делают это немного по-другому
UPDATE HR_XML
SET Salaries.modify('replace value of
(/Salaries/Marketing/Employee[@ID=("2")]/Salary/text())[1] with ("60000")')
GO
Для вашего случая это было бы, я думаю
update YourTable set
XMLText.modify('replace value of
(/Process/Timers/Timer[@Name=("SendNotificationSecretaryLevel2")]/@Value)[1] with "40m"')
GO
Однако я не уверен в части where вашего обновления.
Комментарии:
1. Спасибо за ваш ответ