Метод nodes() (тип данных xml)

Применимо к:SQL Server База данных SQL Azure Управляемый экземпляр SQL Azure

Метод nodes() незаменим в тех случаях, когда экземпляр типа данных xml необходимо разделить на реляционные данные. Он позволяет идентифицировать узлы, которые будут ставиться в соответствие новой строке.

У каждого экземпляра типа данных xml имеется неявно заданный узел контекста. Для сохраняемого в столбце или переменной экземпляра XML таким узлом является узел документов. Узел документа является неявным узлом, который находится на верхнем уровне каждого экземпляра типа данных xml.

Метод nodes() возвращает набор строк, содержащий логические копии исходных экземпляров XML. В таких логических копиях контекстным узлом каждого экземпляра строки устанавливается один из узлов, идентифицируемых выражением запроса. Таким образом последующие запросы могут перемещаться относительно этих контекстных узлов.

Из этих наборов строк могут извлекаться несколько значений. Например, метод value() может быть применен к набору строк, возвращенному методом nodes(), для извлечения нескольких значений из исходного экземпляра XML. Метод value(), примененный к экземпляру XML, возвращает только одно значение.

Синтаксис

nodes (XQuery) as Table(Column)  

Примечание.

Сведения о синтаксисе Transact-SQL для SQL Server 2014 (12.x) и более ранних версиях см . в документации по предыдущим версиям.

Аргументы

XQuery
Строковый литерал, выражение XQuery. Если выражение запроса конструирует узлы, эти сконструированные узлы представлены в результирующем наборе строк. Если результатом выражения запроса является пустая последовательность, набор строк также будет пустым. Если статическим результатом выражения запроса является последовательность, которая вместо узлов содержит атомарные значения, возникает статическая ошибка.

Таблица(столбец)
Имя таблицы и имя столбца для результирующего набора строк.

Замечания

В качестве примера предположим, что имеется следующая таблица:

T (ProductModelID INT, Instructions XML)  

В таблице хранится следующее руководство по изготовлению. Здесь показан только фрагмент этого документа. Обратите внимание, что в документе указываются три места производства.

<root>  
  <Location LocationID="10"...>  
     <step>...</step>  
     <step>...</step>  
      ...  
  </Location>  
  <Location LocationID="20" ...>  
       ...  
  </Location>  
  <Location LocationID="30" ...>  
       ...  
  </Location>  
</root>  

Вызов метода nodes() с выражением запроса /root/Location возвращает набор из трех строк, каждая из которых содержит логическую копию исходного XML-документа с контекстным элементом, присвоенным одному из узлов <Location>:

Product  
ModelID      Instructions  
----------------------------------  
1      <root><Location LocationID="10" ... />  
             <Location LocationID="20" ... />  
             <Location LocationID="30" .../></root>  
1      <root><Location LocationID="10" ... />  
             <Location LocationID="20" ... />  
             <Location LocationID="30" .../></root>  
1      <root><Location LocationID="10" ... />  
             <Location LocationID="20" ... />  
             <Location LocationID="30" .../></root>  

Затем для набора строк можно выполнять запросы при помощи методов типа данных xml. Следующий запрос извлекает поддерево элемента контекста для каждой сформированной строки:

SELECT T2.Loc.query('.')  
FROM T  
CROSS APPLY Instructions.nodes('/root/Location') AS T2(Loc)   

Вот результат:

ProductModelID  Instructions  
----------------------------------  
1        <Location LocationID="10" ... />  
1        <Location LocationID="20" ... />  
1        <Location LocationID="30" .../>  

Возвращаемый набор строк сохраняет информацию о типе. Методы типа данных xml (query(), value(), exist() и nodes()) могут применяться к результату, возвращенному методом nodes(). Однако вы не можете использовать метод modify(), чтобы изменить экземпляр XML.

Кроме того, контекстный узел в наборе строк не может быть материализован. Это означает, что вы не можете использовать его в инструкции SELECT. Однако он может использоваться в выражениях IS NULL и COUNT(*).

Сценарии применения метода nodes() и инструкции OPENXML (Transact-SQL) совпадают. Таким образом обеспечивается представление набора строк XML. Однако при применении метода nodes() в таблице, содержащей несколько строк XML-документов, необязательно использовать курсоры.

Набор строк, возвращаемый методом nodes(), является неименованным набором строк. Поэтому он должен быть явно именован с помощью механизма псевдонимов.

Функция nodes() не может быть применена непосредственно к результатам определенной пользователем функции. Чтобы использовать функцию nodes() с результатом скалярной функции, определенной пользователем, вы можете:

  • назначить переменной результат функции, определенной пользователем;
  • воспользоваться производной таблицей и присвоить псевдоним столбца возвращаемому значению определенной пользователем функции, после чего применить инструкцию CROSS APPLY, чтобы выбрать данные из псевдонима.

В следующем примере показан один из способов использования инструкции CROSS APPLY для выборки из результата пользовательской функции.

USE AdventureWorks;  
GO  
  
CREATE FUNCTION XTest()  
RETURNS XML  
AS  
BEGIN  
RETURN '<document/>';  
END;  
GO  
  
SELECT A2.B.query('.')  
FROM  
(SELECT dbo.XTest()) AS A1(X)   
CROSS APPLY X.nodes('.') A2(B);  
GO  
  
DROP FUNCTION XTest;  
GO  

Примеры

Применение метода nodes() к переменной типа данных xml

В этом примере рассматривается XML-документ с <Root> элементом верхнего уровня и тремя <row> дочерними элементами. Запрос использует метод nodes() для задания контекстных узлов, по одному для каждого элемента <row>. Метод nodes() возвращает набор из трех строк. Каждая строка имеет логическую копию исходного XML, с контекстными узлами, идентифицирующими разные элементы <row> исходного документа.

Запрос возвращает контекстный узел из каждой строки:

DECLARE @x XML   
SET @x='<Root>  
    <row id="1"><name>Larry</name><oflw>some text</oflw></row>  
    <row id="2"><name>moe</name></row>  
    <row id="3" />  
</Root>'  
SELECT T.c.query('.') AS result  
FROM   @x.nodes('/Root/row') T(c)  
GO  

В следующем примере метод запроса возвращает элемент контекста и его содержимое:

<row id="1"><name>Larry</name><oflw>some text</oflw></row>  
<row id="2"><name>moe</name></row>  
<row id="3"/>  

Вследствие применения родительского метода доступа на контекстных узлах возвращается элемент <Root> для всех трех узлов:

SELECT T.c.query('..') AS result  
FROM   @x.nodes('/Root/row') T(c)  
GO  

Вот результат:

<Root>  
    <row id="1"><name>Larry</name><oflw>some text</oflw></row>  
    <row id="2"><name>moe</name></row>  
    <row id="3" />  
</Root>  
<Root>  
    <row id="1"><name>Larry</name><oflw>some text</oflw></row>  
    <row id="2"><name>moe</name></row>  
    <row id="3" />  
</Root>  
<Root>  
    <row id="1"><name>Larry</name><oflw>some text</oflw></row>  
    <row id="2"><name>moe</name></row>  
    <row id="3" />  
</Root>  

Задание метода nodes() для столбца типа данных xml

В этом примере использованы инструкции по производству велосипедов, которые хранятся в столбце Instructions типа xml в таблице ProductModel.

В следующем примере метод nodes() применяется к столбцу Instructions типа xml в таблице ProductModel.

Метод nodes() задает элементы <Location> как контекстные узлы, указывая путь /MI:root/MI:Location. Конечный набор строк включает в себя логические копии исходного документа, по одной для каждого узла<Location> в документе, с контекстным узлом, заданным для элемента <Location>. В качестве результата функция nodes() выдает набор контекстных узлов <Location>.

Метод query(), применяемый к этому набору строк, запрашивает self::node и возвращает элемент <Location> для каждой строки.

В этом примере запрос задает каждый элемент <Location> как контекстный узел в производственной инструкции конкретной модели продукта. Вы можете использовать эти контекстные узлы, чтобы извлечь такие значения:

  • Найти идентификаторы расположения в каждом элементе <Location>

  • Извлечь этапы производства (дочерние элементы <step>) в каждом элементе <Location>

Этот запрос возвращает контекстный элемент, у которого в методе '.' используется сокращенный синтаксис self::node() для query().

Обратите внимание на следующее:

  • Метод nodes() применяется к столбцу Instructions и возвращает набор строк T (C). Этот набор строк содержит логические копии исходного руководства по изготовлению с /root/Location в качестве контекстного элемента.

  • Инструкция CROSS APPLY применяет метод nodes() к каждой строке в таблице ProductModel и возвращает только строки, образующие результирующий набор.

    SELECT C.query('.') as result  
    FROM Production.ProductModel  
    CROSS APPLY Instructions.nodes('  
    declare namespace MI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions";  
    /MI:root/MI:Location') as T(C)  
    WHERE ProductModelID=7  
    

    Частичный результат:

    <MI:Location LocationID="10"  ...>  
       <MI:step ... />  
          ...  
    </MI:Location>  
    <MI:Location LocationID="20"  ... >  
        <MI:step ... />  
          ...  
    </MI:Location>  
    ...  
    

Применение метода nodes() к набору строк, возвращенному другим методом nodes()

В следующем коде из столбца Instructions таблицы ProductModel запрашиваются XML-документы, составляющие руководство по изготовлению. Запрос возвращает набор строк, содержащий идентификатор производственной модели, места производства и шаги производства.

Обратите внимание на следующее:

  • Метод nodes() применяется к столбцу Instructions и возвращает набор строк T1 (Locations), Этот набор строк содержит логические копии исходного руководства по изготовлению с /root/Location в качестве контекстного элемента.

  • Метод nodes() применяется к набору строк T1 (Locations) и возвращает набор строк T2 (steps). Этот набор строк содержит логические копии исходного руководства по изготовлению с /root/Location/step в качестве контекстного элемента.

SELECT ProductModelID, Locations.value('./@LocationID','int') AS LocID,  
steps.query('.') AS Step         
FROM Production.ProductModel         
CROSS APPLY Instructions.nodes('         
declare namespace MI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions";         
/MI:root/MI:Location') AS T1(Locations)         
CROSS APPLY T1.Locations.nodes('         
declare namespace MI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions";         
./MI:step ') AS T2(steps)         
WHERE ProductModelID=7         
GO         

Вот результат:

ProductModelID LocID Step         
----------------------------         
7      10   <step ... />         
7      10   <step ... />         
...         
7      20   <step ... />         
7      20   <step ... />         
7      20   <step ... />         
...         

В запросе префикс MI объявляется два раза. Вместо этого можно воспользоваться WITH XMLNAMESPACES, чтобы объявить этот префикс один раз и использовать его в запросе:

WITH XMLNAMESPACES (  
   'https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions' AS MI)  
  
SELECT ProductModelID, Locations.value('./@LocationID','int') AS LocID,  
steps.query('.') AS Step         
FROM Production.ProductModel         
CROSS APPLY Instructions.nodes('         
/MI:root/MI:Location') AS T1(Locations)         
CROSS APPLY T1.Locations.nodes('         
./MI:step ') as T2(steps)         
WHERE ProductModelID=7         
GO    

См. также

Добавление пространств имен в запросы с WITH XMLNAMESPACES
Создание экземпляров данных XML
Методы для типа данных XML