【问题标题】:Update XML Stored as varchar in a Table更新在表中存储为 varchar 的 XML
【发布时间】:2019-03-07 06:08:23
【问题描述】:

我有一个名为 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>

我需要通过提供名称属性即更新每个计时器的值。 “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 属性来更新值。怎么做?提前谢谢。

【问题讨论】:

  • 我无法控制表格内容和数据类型。它会自动填充。

标签: sql-server xml sql-server-2008 xpath xquery


【解决方案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 解读为:

  • &lt;Process&gt;开始
  • 深入了解&lt;Timers&gt;,然后再深入了解&lt;Timer&gt;
  • 查找属性名称类似于外部变量的第一个 ([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
    

    不过我不确定你的更新在哪里。

    【讨论】:

    • 感谢您的回答
    猜你喜欢
    • 2017-08-23
    • 2013-05-07
    • 1970-01-01
    • 2012-09-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多