在 SQL Server XML 处理中参数化 XPath 以便修改()

发布于 2024-11-15 13:00:58 字数 882 浏览 0 评论 0原文

正如标题所示,我尝试参数化 SQL Server 中 XML 数据列的 edit() 方法的 XPath,但遇到了一些问题。

到目前为止,我有:

DECLARE @newVal varchar(50)
DECLARE @xmlQuery varchar(50)
SELECT @newVal = 'features'
SELECT @xmlQuery = 'settings/resources/type/text()'

UPDATE  [dbo].[Users]
SET     [SettingsXml].modify('
    replace value of (sql:variable("@xmlQuery"))[1]
    with sql:variable("@newVal")')
WHERE   UserId = 1

具有以下 XML 结构:

<settings>
    ...
    <resources>
        <type> ... </type>
        ...
    </resources>
    ...
</settings>

然后生成此错误:

XQuery [dbo.Users.NewSettingsXml.modify()]: 'replace' 的目标最多只能是一个节点,找到 'xs :string ?'

现在我意识到修改方法一定不能接受字符串作为路径,但是有没有办法使用动态 SQL 来完成这个缺点呢?

哦,顺便说一下,我使用的是 SQL Server 2008 Standard 64 位,但我编写的任何查询都需要兼容回 2005 Standard。

谢谢!

Just like the title suggests, I'm trying to parameterize the XPath for a modify() method for an XML data column in SQL Server, but running into some problems.

So far I have:

DECLARE @newVal varchar(50)
DECLARE @xmlQuery varchar(50)
SELECT @newVal = 'features'
SELECT @xmlQuery = 'settings/resources/type/text()'

UPDATE  [dbo].[Users]
SET     [SettingsXml].modify('
    replace value of (sql:variable("@xmlQuery"))[1]
    with sql:variable("@newVal")')
WHERE   UserId = 1

with the following XML Structure:

<settings>
    ...
    <resources>
        <type> ... </type>
        ...
    </resources>
    ...
</settings>

which is then generating this error:

XQuery [dbo.Users.NewSettingsXml.modify()]: The target of 'replace' must be at most one node, found 'xs:string ?'

Now I realize that the modify method must not be capable of accepting a string as a path, but is there a way to accomplish this short of using dynamic SQL?

Oh, by the way, I'm using SQL Server 2008 Standard 64-bit, but any queries I write need to be compatible back to 2005 Standard.

Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

貪欢 2024-11-22 13:00:58

如果有人感兴趣,我自己使用动态查询想出了一个相当不错的解决方案:

DECLARE @newVal nvarchar(max)
DECLARE @xmlQuery nvarchar(max)
DECLARE @id int

SET @newVal = 'foo'
SET @xmlQuery = '/root/node/leaf/text()'
SET @id = 1

DECLARE @query nvarchar(max)

SET @query = '
    UPDATE  [Table]
    SET     [XmlColumn].modify(''
        replace value of (' + @xmlQuery + '))[1]
        with sql:variable("@newVal")'')
    WHERE Id = @id'

EXEC sp_executesql @query,
                   N'@newVal nvarchar(max) @id int',
                   @newVal, @id

使用这个,动态查询的唯一不安全部分是 xPath,在我的情况下,它完全由我的代码控制,所以应该不被利用。

In case anyone was interested, I came up with a pretty decent solution myself using a dynamic query:

DECLARE @newVal nvarchar(max)
DECLARE @xmlQuery nvarchar(max)
DECLARE @id int

SET @newVal = 'foo'
SET @xmlQuery = '/root/node/leaf/text()'
SET @id = 1

DECLARE @query nvarchar(max)

SET @query = '
    UPDATE  [Table]
    SET     [XmlColumn].modify(''
        replace value of (' + @xmlQuery + '))[1]
        with sql:variable("@newVal")'')
    WHERE Id = @id'

EXEC sp_executesql @query,
                   N'@newVal nvarchar(max) @id int',
                   @newVal, @id

Using this, the only unsafe part of the dynamic query is the xPath, which, in my case, is controlled entirely by my code and so shouldn't be exploitable.

如歌彻婉言 2024-11-22 13:00:58

我能想到的最好的办法是:

declare @Q1 varchar(50)
declare @Q2 varchar(50)
declare @Q3 varchar(50)
set @Q1 = 'settings'
set @Q2 = 'resources'
set @Q3 = 'type'

UPDATE  [dbo].[Users]
SET     [SettingsXml].modify('
    replace value of (for $n1 in /*,
                          $n2 in $n1/*,
                          $n3 in $n2/*
                      where $n1[local-name(.) = sql:variable("@Q1")] and
                            $n2[local-name(.) = sql:variable("@Q2")] and
                            $n3[local-name(.) = sql:variable("@Q3")]
                      return $n3/text())[1]
    with sql:variable("@newVal")')
WHERE   UserId = 1

节点名称是参数,但遗憾的是节点的级别/数量不是。

The best I could figure out was this:

declare @Q1 varchar(50)
declare @Q2 varchar(50)
declare @Q3 varchar(50)
set @Q1 = 'settings'
set @Q2 = 'resources'
set @Q3 = 'type'

UPDATE  [dbo].[Users]
SET     [SettingsXml].modify('
    replace value of (for $n1 in /*,
                          $n2 in $n1/*,
                          $n3 in $n2/*
                      where $n1[local-name(.) = sql:variable("@Q1")] and
                            $n2[local-name(.) = sql:variable("@Q2")] and
                            $n3[local-name(.) = sql:variable("@Q3")]
                      return $n3/text())[1]
    with sql:variable("@newVal")')
WHERE   UserId = 1

Node names are parameters but the level/number of nodes is sadly not.

梦幻的味道 2024-11-22 13:00:58

这是我们找到的用于参数化要替换的属性名称和新值的解决方案。它需要一个特定的xpath,参数名称可以是sql变量或表列。

SET Bundle.modify
(
  'replace value of(//config-entry-metadata/parameter-name[text() = sql:column("BTC.Name")]/../..//value/text())[1] with sql:column("BTC.Value") '
)

这是硬编码的 x 路径: //config-entry-metadata/parameter-name ... /../..//value/text()
参数名称是动态的:[text() = sql:column("BTC.Name")]
新值也是动态的:with sql:column("BTC.Value")

Here is the solution we found for parameterizing both the property name to be replaced and the new value. It needs a specific xpath, and the parameter name can be an sql variable or table column.

SET Bundle.modify
(
  'replace value of(//config-entry-metadata/parameter-name[text() = sql:column("BTC.Name")]/../..//value/text())[1] with sql:column("BTC.Value") '
)

This is the hard coded x path: //config-entry-metadata/parameter-name ... /../..//value/text()
The name of the parameter is dynamic: [text() = sql:column("BTC.Name")]
The new value is also dynamic: with sql:column("BTC.Value")

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文