简体   繁体   English

根据来自 XML 类型列的匹配项更新 XML 节点值

[英]Update XML node value based on a match from XML type column

I have a SQL table with a XML column.我有一个带有 XML 列的 SQL 表。

Table structure is表结构是

CREATE TABLE [dbo].[UserSettings](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [UserID] [int] NOT NULL,    
    [UserName] [varchar](100) NULL, 
    [Setting] [xml] NULL,   
    [CreateDate] [datetime] NOT NULL
)

The Setting xml column looks like this:设置 xml 列如下所示:

<UserSettings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <UserID>1</UserID>
  <Reports>
        <string>Report - 1</string>
        <string>Report - 2</string>
        <string>Report - 3</string>
        <string>Report - 4</string>
  </Reports>
</UserSettings>

I want to update Report - 1 to Report - One, Report - 2 to Report - Two in <Reports>我想将<Reports> Report - 1 更新为 Report - One,将 Report - 2 更新为 Report - Two

And also, if there is a value Report - 4 then I want to remove it from <Reports>而且,如果有一个值 Report - 4 那么我想从<Reports>删除它

So my end result for in the column should look like this:所以我在专栏中的最终结果应该是这样的:

<UserSettings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <UserID>1</UserID>
  <Reports>
        <string>Report - One</string>
        <string>Report - Two</string>
        <string>Report - Three</string>     
  </Reports>
</UserSettings>

EDIT: I have tried the REPLACE approach.编辑:我尝试过 REPLACE 方法。 I am not sure if that is the most effective way to do this.我不确定这是否是最有效的方法。

update UserSettings
set Setting=REPLACE(convert(varchar(max),Setting),'<string>Report - 1</string>','<string>Report - One</string>')
where convert(varchar(max),Setting) like '%<string>Report - 1</string>%'

EDIT: I read about modify() method but the sequence of report could be in any order.编辑:我阅读了modify() 方法,但报告的顺序可以是任何顺序。 I couldn't get my query to work with it.我无法让我的查询使用它。

simple way is to use Replace as string, however this method is not useful if you don't want to replace that value everywhere ( for example outside of <Reports> tag)简单的方法是使用 Replace as string,但是如果您不想在任何地方替换该值(例如在<Reports>标记之外),则此方法没有用

-- to update report 1 to 3 ( I just did it for 1):
update UserSettings
set Setting = replace(cast(Setting as nvarchar(max)) , '<string>Report - 1</string>','<string>Report - one</string>')

-- to remove report 4 
update UserSettings
set Setting = replace(cast(Setting as nvarchar(max)) , '<string>Report - 4</string>','')

You can try a different approach.您可以尝试不同的方法。

Instead of find-and-replace, iemodify, it is possible to compose XML on the fly via XQuery and its FLWOR expression.代替查找和替换,即修改,可以通过 XQuery 及其 FLWOR 表达式动态组合 XML。

SQL SQL

-- DDL and sample data population, start
DECLARE @UserSettings TABLE (
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [UserID] [int] NOT NULL,    
    [UserName] [varchar](100) NULL, 
    [Setting] [xml] NULL,   
    [CreateDate] [datetime] NOT NULL
);
INSERT INTO @UserSettings (UserID, UserName, Setting, CreateDate)
VALUES
(0, 'John', N'<UserSettings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <UserID>1</UserID>
    <Reports>
        <string>Report - 1</string>
        <string>Report - 2</string>
        <string>Report - 3</string>
        <string>Report - 4</string>
    </Reports>
</UserSettings>', 
    GETDATE()
);
-- DDL and sample data population, end

UPDATE @UserSettings
SET Setting = Setting.query('<UserSettings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xmlns:xsd="http://www.w3.org/2001/XMLSchema">
{
    for $x in /UserSettings/*[local-name()!="Reports"]
    return $x,
        element Reports {
            for $y in ("One","Two","Three")
            return <string>{concat("Report - ", $y)}</string>
        }
}
</UserSettings>');

-- test
SELECT * FROM @UserSettings;

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

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