Есть ли способ передать переменную как одиночную при запросе XML? - PullRequest
0 голосов
/ 26 апреля 2019

В первый раз я работаю с XML и, похоже, у меня возникают проблемы при передаче переменной в одноэлементный XML-запрос. Ошибка, которая отображается при выполнении запроса: «Аргумент 1 метода типа данных XML« значение »должен быть строковым литералом»

Я установил для переменной тип данных varchar. Что мне здесь не хватает?

----Inside LOOP----
SELECT @count = @count + 1

select 
a.XMLData.value('(//FlightInfo/TailNumber/text())['''+ @count +''']', 'varchar(100)') TaiNumber
from
XMLwithOpenXML a

Есть ли более простой способ пройти через узлы XML, чтобы исправить те узлы, которые содержат неверные / отсутствующие данные?

Я пытаюсь обойти узлы "TailNumber", а затем использую какое-то соединение или оператор where, чтобы обновить значение узла с правильным TailNumber

1 Ответ

0 голосов
/ 26 апреля 2019

AFAIK, SQL Server по-прежнему не поддерживает функцию position() в качестве выходных данных, только в качестве критерия фильтрации. Таким образом, нет простого способа нумеровать узлы в их естественном порядке. Все решения, которые я видел, вычисляют положение каждого узла, подсчитывая все предыдущие узлы, создавая, по сути, полукартовое, которое убивает все надежды на производительность при XML приличного размера.

Однако вы можете использовать довольно грязный трюк, который я использовал около 8 лет назад. Вы можете сгенерировать монотонную последовательность чисел и использовать их для поиска узлов в соответствующих позициях. Код ниже иллюстрирует подход:

-- Sample data
declare @t table (
  Id int identity(1,1) primary key,
  XMLData xml not null
);

insert into @t (XMLData)
values (N'<r>
  <Item>First Value</Item>
  <Item>Second</Item>
</r>'),
(N'<r>
  <Item>Another One</Item>
  <Item>123456</Item>
  <Item>The last</Item>
</r>');

declare @NodeCount int;

-- Get the largest amount of nodes among the rows of interest
select @NodeCount = max(t.XMLData.value('count(/r/Item)', 'int'))
from @t t;

select t.Id, n.RN, i.c.value('./text()[1]', 'varchar(100)') as [NodeValue]
from @t t
  cross join (
    -- Generate a number sequence for each /r/Item node in every row
    select top (@NodeCount) row_number() over(order by (select null)) as [RN]
    from sys.all_objects
  ) n
  -- Get N-th node
  cross apply t.XMLData.nodes('/r/Item[position() = sql:column("n.RN")]') i(c)
order by t.Id, n.RN;

Только будьте осторожны при запуске таблицы с несколькими миллионами строк и / или большими BLOB-объектами. В этом примере он работает довольно аккуратно, но я не представляю, насколько он будет эффективен в реальных случаях. Если ваш XML большой или у вас много строк для запроса, лучшим решением может быть предварительная обработка XML путем добавления номеров узлов в качестве атрибутов с использованием языка, отличного от SQL. Например, функция CLR могла бы быть намного лучше для этого.


P.S. Тем не менее, должно быть быстрее, чем цикл ...

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