如何根据 SQL 中的现有值更新 XML 属性?
How to update XML attributes based on existing values in SQL?
我在应用程序中有很多 XML 文档存储在 SQL 服务器数据库中。这是一个例子:
<para id="19" revDate="2022-05-04T04:00:00Z">
<emphasis>
<emphasis color="Blue">test</emphasis>
<emphasis color="Red">test</emphasis>
</emphasis>
<emphasis>
<emphasis color="Green">test</emphasis>
</emphasis>
</para>
我想替换所有 emphasis 和 entry 元素的 color 属性值与相应的十六进制颜色代码。这就是我想要得到的:
<para id="19" revDate="2022-05-04T04:00:00Z">
<emphasis>
<emphasis color="0000FF">test</emphasis>
<emphasis color="FF0000">test</emphasis>
</emphasis>
<emphasis>
<emphasis color="008000">test</emphasis>
</emphasis>
</para>
所以我需要某种 switch/case。注意:属性可以有任何十六进制值(不仅仅是红色、绿色、蓝色):
DECLARE @ColorTextValue VARCHAR(20) = 'Blue'
DECLARE @ColorHexValue VARCHAR(6)
SET @ColorHexValue = CASE @ColorTextValue
WHEN 'Blue' THEN '0000FF'
WHEN 'Red' THEN 'FF0000'
WHEN 'Green' THEN '008000'
END
我现在有以下脚本:
DECLARE @tbl TABLE (XmlData XML);
INSERT INTO @tbl VALUES
('<para id="19" revDate="2022-05-04T04:00:00Z">
<emphasis>
<emphasis color="Blue">test</emphasis>
<emphasis color="Red">test</emphasis>
</emphasis>
<emphasis>
<emphasis color="Green">test</emphasis>
</emphasis>
</para>'
);
UPDATE
[XmlDocument]
SET
[XmlData].modify('replace value of (//*[self::emphasis or self::entry]/@color)[1] with "hexCodeHere"')
FROM
@tbl AS [XmlDocument]
WHERE
[XmlDocument].[XmlData].exist('//*[self::emphasis or self::entry][@color]') = 1
SELECT * FROM @tbl
如您所见,它只有一个硬编码的 HexCode。如何在此语句中添加某种开关以动态计算十六进制代码?
此外,它不可能更新所有属性。它只更新第一项
请尝试以下解决方案。
它在 CTE 中创建一个计算列 ColorHexValue。
下一步是用 ColorHexValue 列值更新 XML 列 color 属性。
SQL
-- DDL and sample data population, start
DECLARE @tbl TABLE (ID INT IDENTITY PRIMARY KEY, xmldata XML);
INSERT INTO @tbl (xmldata) VALUES
(N'<para id="19" revDate="2022-05-04T04:00:00Z">
<emphasis>
<emphasis color="Blue">test</emphasis>
</emphasis>
</para>'),
(N'<para id="19" revDate="2022-05-04T04:00:00Z">
<emphasis>
<emphasis color="Green">test</emphasis>
</emphasis>
</para>');
-- DDL and sample data population, end
-- just to see
SELECT *
FROM @tbl
CROSS APPLY (SELECT CASE xmldata.value('(/para/emphasis/emphasis/@color)[1]', 'VARCHAR(10)')
WHEN 'Blue' THEN '0000ff'
WHEN 'Red' THEN 'ff0000'
WHEN 'Green' THEN '008000'
END) t(ColorHexValue);
-- real deal
;WITH rs AS
(
SELECT *
FROM @tbl
CROSS APPLY (SELECT CASE xmldata.value('(/para/emphasis/emphasis/@color)[1]', 'VARCHAR(10)')
WHEN 'Blue' THEN '0000ff'
WHEN 'Red' THEN 'ff0000'
WHEN 'Green' THEN '008000'
END) t(ColorHexValue)
)
UPDATE rs
SET xmldata.modify('replace value of (/para/emphasis/emphasis/@color)[1] with sql:column("ColorHexValue")');
-- test
SELECT * FROM @tbl;
SQL#2
-- DDL and sample data population, start
DECLARE @tbl TABLE (ID INT IDENTITY PRIMARY KEY, xmldata XML);
INSERT INTO @tbl (xmldata) VALUES
(N'<para id="19" revDate="2022-05-04T04:00:00Z">
<emphasis>
<emphasis color="Blue">test</emphasis>
<emphasis color="Red">test</emphasis>
</emphasis>
<emphasis>
<emphasis color="Green">test</emphasis>
</emphasis>
</para>'),
(N'<para id="19" revDate="2022-05-04T04:00:00Z">
<emphasis>
<emphasis color="Green">test</emphasis>
</emphasis>
</para>');
-- DDL and sample data population, end
-- before
SELECT * FROM @tbl
WHERE xmldata.exist('//emphasis/@color[. = ("Blue","Red","Green")]') = 1;
DECLARE @tries INT = 0;
WHILE @@ROWCOUNT > 0 AND @tries < 100
BEGIN
UPDATE @tbl
SET xmldata.modify('replace value of (/para/emphasis/emphasis/@color[. = ("Blue","Red","Green")])[1]
with (
let $c := (/para/emphasis/emphasis/@color[. = ("Blue","Red","Green")])[1]
return
if ($c = "Blue") then "0000ff"
else if ($c = "Red") then "ff0000"
else if ($c = "Green") then "008000"
else ("unknown color")
)')
WHERE xmldata.exist('/para/emphasis/emphasis/@color[. = ("Blue","Red","Green")]') = 1;
SET @tries += 1;
END;
-- after
SELECT * FROM @tbl;
我在应用程序中有很多 XML 文档存储在 SQL 服务器数据库中。这是一个例子:
<para id="19" revDate="2022-05-04T04:00:00Z">
<emphasis>
<emphasis color="Blue">test</emphasis>
<emphasis color="Red">test</emphasis>
</emphasis>
<emphasis>
<emphasis color="Green">test</emphasis>
</emphasis>
</para>
我想替换所有 emphasis 和 entry 元素的 color 属性值与相应的十六进制颜色代码。这就是我想要得到的:
<para id="19" revDate="2022-05-04T04:00:00Z">
<emphasis>
<emphasis color="0000FF">test</emphasis>
<emphasis color="FF0000">test</emphasis>
</emphasis>
<emphasis>
<emphasis color="008000">test</emphasis>
</emphasis>
</para>
所以我需要某种 switch/case。注意:属性可以有任何十六进制值(不仅仅是红色、绿色、蓝色):
DECLARE @ColorTextValue VARCHAR(20) = 'Blue'
DECLARE @ColorHexValue VARCHAR(6)
SET @ColorHexValue = CASE @ColorTextValue
WHEN 'Blue' THEN '0000FF'
WHEN 'Red' THEN 'FF0000'
WHEN 'Green' THEN '008000'
END
我现在有以下脚本:
DECLARE @tbl TABLE (XmlData XML);
INSERT INTO @tbl VALUES
('<para id="19" revDate="2022-05-04T04:00:00Z">
<emphasis>
<emphasis color="Blue">test</emphasis>
<emphasis color="Red">test</emphasis>
</emphasis>
<emphasis>
<emphasis color="Green">test</emphasis>
</emphasis>
</para>'
);
UPDATE
[XmlDocument]
SET
[XmlData].modify('replace value of (//*[self::emphasis or self::entry]/@color)[1] with "hexCodeHere"')
FROM
@tbl AS [XmlDocument]
WHERE
[XmlDocument].[XmlData].exist('//*[self::emphasis or self::entry][@color]') = 1
SELECT * FROM @tbl
如您所见,它只有一个硬编码的 HexCode。如何在此语句中添加某种开关以动态计算十六进制代码? 此外,它不可能更新所有属性。它只更新第一项
请尝试以下解决方案。
它在 CTE 中创建一个计算列 ColorHexValue。
下一步是用 ColorHexValue 列值更新 XML 列 color 属性。
SQL
-- DDL and sample data population, start
DECLARE @tbl TABLE (ID INT IDENTITY PRIMARY KEY, xmldata XML);
INSERT INTO @tbl (xmldata) VALUES
(N'<para id="19" revDate="2022-05-04T04:00:00Z">
<emphasis>
<emphasis color="Blue">test</emphasis>
</emphasis>
</para>'),
(N'<para id="19" revDate="2022-05-04T04:00:00Z">
<emphasis>
<emphasis color="Green">test</emphasis>
</emphasis>
</para>');
-- DDL and sample data population, end
-- just to see
SELECT *
FROM @tbl
CROSS APPLY (SELECT CASE xmldata.value('(/para/emphasis/emphasis/@color)[1]', 'VARCHAR(10)')
WHEN 'Blue' THEN '0000ff'
WHEN 'Red' THEN 'ff0000'
WHEN 'Green' THEN '008000'
END) t(ColorHexValue);
-- real deal
;WITH rs AS
(
SELECT *
FROM @tbl
CROSS APPLY (SELECT CASE xmldata.value('(/para/emphasis/emphasis/@color)[1]', 'VARCHAR(10)')
WHEN 'Blue' THEN '0000ff'
WHEN 'Red' THEN 'ff0000'
WHEN 'Green' THEN '008000'
END) t(ColorHexValue)
)
UPDATE rs
SET xmldata.modify('replace value of (/para/emphasis/emphasis/@color)[1] with sql:column("ColorHexValue")');
-- test
SELECT * FROM @tbl;
SQL#2
-- DDL and sample data population, start
DECLARE @tbl TABLE (ID INT IDENTITY PRIMARY KEY, xmldata XML);
INSERT INTO @tbl (xmldata) VALUES
(N'<para id="19" revDate="2022-05-04T04:00:00Z">
<emphasis>
<emphasis color="Blue">test</emphasis>
<emphasis color="Red">test</emphasis>
</emphasis>
<emphasis>
<emphasis color="Green">test</emphasis>
</emphasis>
</para>'),
(N'<para id="19" revDate="2022-05-04T04:00:00Z">
<emphasis>
<emphasis color="Green">test</emphasis>
</emphasis>
</para>');
-- DDL and sample data population, end
-- before
SELECT * FROM @tbl
WHERE xmldata.exist('//emphasis/@color[. = ("Blue","Red","Green")]') = 1;
DECLARE @tries INT = 0;
WHILE @@ROWCOUNT > 0 AND @tries < 100
BEGIN
UPDATE @tbl
SET xmldata.modify('replace value of (/para/emphasis/emphasis/@color[. = ("Blue","Red","Green")])[1]
with (
let $c := (/para/emphasis/emphasis/@color[. = ("Blue","Red","Green")])[1]
return
if ($c = "Blue") then "0000ff"
else if ($c = "Red") then "ff0000"
else if ($c = "Green") then "008000"
else ("unknown color")
)')
WHERE xmldata.exist('/para/emphasis/emphasis/@color[. = ("Blue","Red","Green")]') = 1;
SET @tries += 1;
END;
-- after
SELECT * FROM @tbl;