Параметр хранимой процедуры с запросом XML в MSSQL дает «аргумент должен быть строковым литералом» - PullRequest
1 голос
/ 21 марта 2012

Я пытаюсь запросить таблицу со столбцом, который представляет собой данные XML с функциями запроса и значения. При использовании обычных строковых литералов все нормально, но если я помещу это в хранимую процедуру и попытаюсь использовать переменные, это не сработает.

Полагаю, я не использую правильный тип данных, но после некоторого поиска я не могу понять, какой тип данных нужна функции запроса.

Пример: таблица содержит

| Id | xmldata                         |
| 1  | <data><node>value</node></data> |

сейчас, используя запрос на выборку

select id
from table
where xmldata.query('/data/node').value('.', 'VARCHAR(50)') = 'value'

получает мне данные, которые я хочу. Но если я использую это в хранимой процедуре, использую параметр @xpath varchar(100) и передаю его методу запроса как xmldata.query(@xpath) я получаю ошибку

The argument 1 of the xml data type method "query" must be a string literal.

Полагаю, varchar (100) неверен, но какой тип данных я могу использовать, чтобы MSSQL был счастлив?


Обновление: Хорошо, итак. Очевидно, вы не можете передать параметр методу запроса «просто так», но можно использовать переменную sql: в сочетании с local-name, чтобы обработать его часть. Так, например, это будет работать

declare @xpath VarChar(100)
set @xpath='node'
select objectData.query('/data/*[local-name() = sql:variable("@xpath")]')
                 .value('.', 'varchar(100)') as xmldata
from table

и значение выбирается в столбце xmldata. Но (!) Это требует, чтобы корневой узел был первым значением в функции запроса. Следующее не работает

declare @xpath VarChar(100)
set @xpath='/data/node'
select objectData.query('*[local-name() = sql:variable("@xpath")]')
                 .value('.', 'varchar(100)') as xmldata
from table

обратите внимание, как путь запроса «перемещается» вверх к переменной. Я продолжу свои исследования ..

1 Ответ

3 голосов
/ 21 марта 2012

A literal является противоположностью variable. Сообщение означает, что вы не можете передать переменную в качестве первого аргумента query.

Одним из способов решения этой проблемы является динамический SQL:

declare @sql varchar(max)
set @sql = 'select id from table where xmldata.query(''' + @path + 
    ''').value(''.'', ''VARCHAR(50)'') = ''value'''
exec @sql

Как видите, динамический SQL не приводит к очень читабельному коду. Я бы наверняка исследовал альтернативы.

РЕДАКТИРОВАТЬ: Ваше предложение local-name() работает для имен узлов.

declare @nodename varchar(max)
set @nodename = 'node'
...
where   xmldata.query('//*[local-name()=sql:variable("@nodename")]')
            .value('.', 'varchar(50)') = 'value'

Кажется, для путей нет эквивалента.

...