'local-name ()' требует одиночного (или пустой последовательности) T- SQL Xquery - PullRequest
3 голосов
/ 25 января 2020

Это вариант / комбинация этих двух вопросов, но я думаю, что я сделал, как они описали:

Есть ли способ получить имя узла в запросе SQL Server 2016 T- SQL?

Я хочу сделать это:

select 
    trcid,
    trcXML.value(
        'local-name(//*[local-name()="after"][1]/*[1])',  
        'varchar(32)'
    ) as XmlTableName,
    trcXml, 
    trcGUID, 
    trcCorrID 
from trace 
order by trcId desc

Я включил явно [1] после каждого элемента в иерархии.

Ошибка: XQuery [trace.tr cXML .value ()]: для local-name () требуется одиночный (или пустая последовательность) найденный операнд типа 'element(*,xdt:untyped) *'

Пример данных:

<s1:DB2Request xmlns:s1="XYZDB2">
  <s1:sync>
    <s1:after identityInsert="false">
      <s1:PG204AT5>
        <s1:ISA06>1975111</s1:ISA06>
           etc... 
      </s1:PG204AT5>
    </s1:after>
  </s1:sync>
</s1:DB2Request>

Мне нужно имя таблицы (это «update-gram» BizTalk), которое находится между элементами «after» и ISA06, в этом случае: PG204AT5.

Протестировано на xpathtester.com: local-name(//*[local-name()="after"][1]/* [1]) - по какой-то причине при сохранении XPATH изменяется: http://www.xpathtester.com/xpath/2bd602d8fc7aee0484de14bf93f71ef2

Ответы [ 3 ]

2 голосов
/ 25 января 2020

Помните, что серверный движок SQL, в отличие от большинства реализаций XQuery, выполняет "пессимистическую c stati c печать" - он предполагает, что если что-то может go не так, то оно будет go неправильно.

Выражение //*[local-name()="after"][1]/* [1] может возвращать более одного элемента - например, оно будет делать это с этим вводом

<x>
  <y>
    <after>
       <z/>
    </after>
  </y>
  <y>
    <after>
       <z/>
    </after>
  </y>
</x>

, поэтому компилятор XQuery выводит тип stati c element () *, который не соответствует требованию.

Вероятно, достаточно просто набрать (//*[local-name()="after"]/*)[1].

Лично я всегда думал, что пессимисти c stati c печатать было действительно плохой выбор дизайна, но некоторые из ранних разработчиков XQuery, включая Microsoft, были очень заинтересованы в этом.

2 голосов
/ 26 января 2020

Или даже более простое решение, задавая явно имя первого дочернего узла элемента <s1:after>.

SQL

-- DDL and sample data population, start
DECLARE @tbl TABLE(xmldata XML);
INSERT INTO @tbl(xmldata)
VALUES(N'<s1:DB2Request xmlns:s1="XYZDB2">
  <s1:sync>
    <s1:after identityInsert="false">
      <s1:PG204AT5>
        <s1:ISA06>1975111</s1:ISA06>
           <somethingsomething/>
      </s1:PG204AT5>
    </s1:after>
  </s1:sync>
</s1:DB2Request>');
-- DDL and sample data population, end

;WITH XMLNAMESPACES (DEFAULT 'XYZDB2')
SELECT xmldata.value('local-name((/DB2Request/sync/after/child::node())[1])','VARCHAR(50)') as XmlTableName
FROM @tbl;

Output

+--------------+
| XmlTableName |
+--------------+
| PG204AT5     |
+--------------+
2 голосов
/ 25 января 2020

Еще один набор скобок дает вам необходимый синглтон:

DECLARE @t TABLE(s XML);
INSERT INTO @t(s)VALUES(N'<s1:DB2Request xmlns:s1="XYZDB2">
  <s1:sync>
    <s1:after identityInsert="false">
      <s1:PG204AT5>
        <s1:ISA06>1975111</s1:ISA06>
           <somethingsomething/>
      </s1:PG204AT5>
    </s1:after>
  </s1:sync>
</s1:DB2Request>');

select 
    s.value(
        'local-name((//*[local-name()="after"][1]/*)[1])',  
        'varchar(32)'
    ) as XmlTableName
from @t;

Результат:

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