Параметризация XPath для modify () в обработке SQL Server XML - PullRequest
3 голосов
/ 14 июня 2011

Как и предполагает заголовок, я пытаюсь параметризовать XPath для метода modify () для столбца данных XML в SQL Server, но сталкиваюсь с некоторыми проблемами.

Пока у меня есть:

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()]: The target of 'replace' must be at most one node, found 'xs:string ?'

Теперь я понимаю, чтоМетод изменения не должен быть способен принимать строку в качестве пути, но есть ли способ добиться этого с помощью динамического SQL?

О, кстати, я использую SQL Server 2008 Standard 64-немного, но любые запросы, которые я пишу, должны быть совместимы со стандартом 2005 года.

Спасибо!

Ответы [ 3 ]

6 голосов
/ 22 июня 2011

На случай, если кому-то будет интересно, я сам придумаю довольно приличное решение с помощью динамического запроса:

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, который вмой случай полностью контролируется моим кодом и не должен использоваться.

2 голосов
/ 15 июня 2011

Лучшее, что я мог понять, это:

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

Имена узлов - это параметры, но, к сожалению, уровень / количество узлов нет.

0 голосов
/ 11 февраля 2013

Вот решение, которое мы нашли для параметризации как заменяемого имени свойства, так и нового значения.Требуется определенный 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")

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...