2012-03-21 2 views
1

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

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

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

| 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: в сочетании с локальным именем, чтобы отработать ее часть. Так, например, это будет работать

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

Я не знаю, как заменить все выражение XPath переменной (кроме динамического SQL). Вы можете сравнить имя узла с переменной, используя 'local-name()', как вы. Если вам неважно, что такое имя корневого узла, вы можете использовать '// * [local-name() = sql: variable (" @ xpath ")]', чтобы выполнить глубокий поиск для всех узлов, который соответствует '@xpath 'независимо от того, где в XML они расположены. –

+0

@MikaelEriksson: О, ладно .. Я не думал, что двойной '//' работал, но спасибо за подсказку. Думаю, я буду использовать либо это, либо просто не использовать параметры. – Patrick

ответ

3

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

EDIT: Ваше предложение local-name() работает для имен узлов.

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

Не существует эквивалента для путей.

+0

Хм .. ладно.Таким образом, самый простой способ - использовать «статические» xpaths и не использовать переменные? :) – Patrick

+2

Подождите секунду ... похоже, что вы можете [ссылаться на переменные SQL в XPath] (http://msdn.microsoft.com/en-us/library/ms188254.aspx) – Andomar

+0

Да, я нашел http://stackoverflow.com/questions/5965000/sql-xml-xquery-data-query-using-a-variable-in-the-node-selection, который, как представляется, ссылается на это. Просто использование 'sql-variable' не работает, но с забавным выглядящим' * [local-name (.) = 'Он решается. – Patrick