XPath parameterization for change () in SQL Server XML processing

As in the header, I am trying to parameterize XPath for the modify () method for an XML data column in SQL Server, but in some problems.

So far I:

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 then generates this error:

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

Now I understand that the change method should not take a string as a path, but is there a way to accomplish this without using dynamic SQL?

Oh, by the way, I use SQL Server 2008 Standard 64-bit, but any queries that I write should be compatible with the 2005 standard.

Thank!

+3
source share
3 answers

In case someone was interested, I came up with a pretty decent solution 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

, xPath, .

+4

, , :

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 - , / , , .

+2

Here is the solution we found for parameterizing both the name of the property to replace and the new value. It needs a specific xpath, and the parameter name can be a sql variable or a 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 path x: //config-entry-metadata/parameter-name ... /../..//value/text()
Parameter name dynamic: The [text() = sql:column("BTC.Name")]
new value is also dynamic:with sql:column("BTC.Value")

0
source

All Articles