Метод query используется, когда необходимо выполнить запрос XQuery к XML-документу или фрагменту. Метод возвращает экземпляр типа xml, содержащий результат выполнения запроса. Поддержка развивающегося стандарта запросов для XML-документов соответствует черновикам стандарта, выпущенным консорциумом w3c на протяжении 2002 года [2]. Синтаксис вызова метода следующий:
query ('XQuery'[, noderef]) |
Где:
- XQuery – запрос XQuery к данному экземпляру XML-документа.
- noderef – ссылка на узел, относительно которого выполняется запрос.
Ссылку на узел можно получить с помощью табличной функции xmlnoderefs, возвращающей таблицу с одним полем noderef, записи которой содержат ссылки на выбранные узлы документа. Синтаксис функции следующий:
xmlnoderefs (xmlTypeInstance, 'XQuery', [ noderef ]) |
Где:
- xmlTypeInstance – экземпляр XML-типа.
- XQuery – запрос XQuery.
- noderef – ссылка на узел, относительно которого выполняется запрос.
Ссылка на узел – это просто некоторый внутренний числовой идентификатор, обозначающий узел и действительный только в пределах данного запроса. Например, значения, возвращаемые следующим запросом, вы можете только наблюдать, нигде использовать их не получится:
|
|
declare @xml xmlset @xml = '<fam> <husband income="180">alex</husband> <wife income="161">rosa</wife> <son income="90">dima</son></fam>'select * from xmlnoderefs(@xml, '/fam/*') |
Результат (ссылки на три дочерних узла элемента fam):
noderef--------0x5AC00x5B400x5BC0 |
Использование этой функции может привести к существенному увеличению производительности в тех случаях, когда в запросах используются «почти повторяющиеся» пути. Другое применение заключается в возможности работать с набором узлов в запросе, а не с одним документом или фрагментом xml. Выберем, например, суммарный доход всех членов семьи:
declare @xml xmlset @xml = '<fam> <husband income="180">alex</husband> <wife income="161">rosa</wife> <son income="90">dima</son></fam>'select @xml::value('@income', 'int', noderef) from xmlnoderefs(@xml, '/fam/*') |
Это единственный способ выполнить подобный запрос, так как запрос "в лоб"
select @xml::query('/fam/*/@income') |
не работает, потому что метод query возвращает XML-документ или фрагмент, но никак не атрибуты (сервер выдает ошибку – XQuery: Attribute may not appear outside of an element). Использование метода value:
select @xml::value('/fam/*/@income', 'int') |
также не возможно, поскольку он должен возвращать скалярное значение (сервер выдает ошибку – XQuery: Expression used by 'value()' must return a singleton or empty sequence).
Также можно использовать табличную функцию xmlnoderefs вместе с новым оператором APPLY, который позволяет вызывать произвольную табличную функцию для каждой строки внешней таблицы [3]. Допустим, таблица fams содержит семьи.
create table fams(id int identity primary key, fam xml) |
Необходимо выбрать доход каждого из членов семей:
|
|
select fam::value('@income', 'int', noderef) from fams cross apply xmlnoderefs(fam, '/fam/*') |
Здесь функция xmlnoderefs вызывается для каждой семьи (для каждой строчки таблицы) и возвращает три ссылки на дочерние элементы (fam). Для каждой ссылки, которая обозначает узел XML-элемента (husband, wife или son) вызывается метод value.
ПРИМЕЧАНИЕ По неофициальной информации, функция xmlnoderefs уже устранена во второй бете SQL Server 2005. Ей на смену пришел пятый метод XML-типа – nodes, который, по-видимому, будет возвращать как раз набор узлов, а не малопригодные ссылки на узлы. Проверить это пока не представляется возможным. |