Обновление XML, хранящегося как varchar в таблице - PullRequest
1 голос
/ 07 марта 2019

У меня есть таблица с именем 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 для обновления значения. Как это можно сделать? Заранее спасибо.

Ответы [ 2 ]

1 голос
/ 07 марта 2019

Вы можете добавить значение фильтра атрибута к предикату в 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, и вы не можете обновить приведенный столбец.Я бы предложил написать промежуточную таблицу, выполнить обновление и записать ее обратно:

A таблица макетов :

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, вам действительно следует сделать это ...

0 голосов
/ 07 марта 2019

Примеры, которые я нахожу, делают это немного по-другому

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

Я не уверен насчет части вашего обновления, гдехотя.

...