繁体   English   中英

在包含 XML 文件的 TEXT 类型列中查找一个字符串并替换 SQL Server 中的一个值

[英]Find a string with in a TEXT type column that contains an XML file and replace a value in SQL Server

更新:包含 XML 文件的列的数据类型为文本。


更新 2(这帮助我使用 xml 函数而不是使用 charindex 来操作数据):我创建了一个临时表#tmpXML(id int,xmlField XML)。 id 是我的主表的主键,xmlField 是文本类型字段中的 XML 值。 我在临时表的 XML 数据字段上使用了 XML 函数,得到了我需要的所有值,并用这些值更新了我的主表。

我发现这种方法比使用 sql 服务器函数(如 charindex 和 substring)更有效和干净。这就是我接受答案的原因,因为它帮助我使用 xml 函数。 只是想澄清一下。


我有一个名为Settings的列,其中包含带有用户设置的 xml 文件。

例如,我有 3 个用户具有此列的以下列。

第一个用户 ID 1 为 XML:

<owner>
    <product userid="1" productid="3" region="North" country="Usa" ></product>
</owner>

第一个用户 ID 2 为 XML:

<owner>
    <product userid="2" productid="3" selectedView="true" region="North" state="AZ" country="Usa" ></product>
</owner>

第一个用户 ID 3 为 XML:

<owner>
    <product userid="3" productid="3" selectedView="true" region="South" isSelected="true" state="AZ" country="Usa" ></product>
</owner>

如您所见,每个用户的属性在 XML 文件中可以按任何顺序排列。 我必须更新所有用户以拥有 region = "East"。 我尝试使用CharIndexsubstring ,但它变得太混乱了。 关于如何做到这一点的任何想法? 谢谢!

您可以使用.modify() XML function 为此,使用语法的replace value of

UPDATE users
SET Settings.modify('replace value of (owner/product/@region)[1] with "East"');

db<>小提琴

这仅适用于每行一个 XML 文档。

如果您实际上将所有这些节点都放在一个大块中,则需要循环运行它

DECLARE @tries int = 0;
WHILE @@ROWCOUNT > 0 AND @tries < 1000
BEGIN
    UPDATE users
    SET Settings.modify('replace value of (owner/product/@region[. != "East"])[1] with "East"')
    WHERE Settings.exist('owner/product/@region[. != "East"]') = 1;
    SET @tries += 1;
END;

db<>小提琴

在您的 SQL 查询中尝试好的旧 REPLACE ( string_expression, string_pattern, string_replacement )

您可以在 select 案例中使用 case 语句当 colName like '%NORTH%' 然后替换 (colName, NORTH, NEWTEXT When colName like '%SOUTH%' etc

您还可以创建一个存储的 function

请尝试以下解决方案。

Text是 MS SQL 服务器中已弃用的数据类型。 我使用NVARCHAR(MAX)数据类型将其与 XML 数据的自然 XML 数据类型区分开来。

SQL

DECLARE @tbl TABLE (id int primary key, Settings NVARCHAR(MAX));
INSERT @tbl VALUES
(1,'<owner>
    <product userid="1" productid="3" region="North" country="Usa" ></product>
</owner>'),
(2,'<owner>
    <product userid="2" productid="3" selectedView="true" region="North" state="AZ" country="Usa" ></product>
</owner>'),
(3,'<owner>
    <product userid="3" productid="3" selectedView="true" region="South" isSelected="true" state="AZ" country="Usa" ></product>
</owner>');

WITH rs AS
(
    SELECT * 
    FROM @tbl
        CROSS APPLY (SELECT TRY_CAST(Settings AS XML)
            .query('<owner><product>
                {
                    for $x in /owner/product/@*
                    return if(local-name($x) ne "region") then $x
                        else attribute region {"East"}
                }
            </product></owner>')) t(x)
)
UPDATE rs
SET rs.Settings  = TRY_CAST(x AS NVARCHAR(MAX));

-- test
SELECT * FROM @tbl;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM