XML EXISTS: примеры (SQL)

MS SQL функция XML_EXISTS: практическое применение
Раздел: XML функции, Методы типа данных XML
XML_EXISTS(XQuery): bit

Функция XML_EXISTS в MS SQL

Функция XML_EXISTS в Microsoft SQL Server используется для проверки существования узлов или последовательностей узлов внутри экземпляра XML-документа. Она применяется в основном в предложении WHERE для фильтрации строк на основе содержимого XML-полей.

Функция возвращает логическое значение: 1 (TRUE), если XPath-выражение возвращает непустой результат, и 0 (FALSE) в противном случае. Это позволяет эффективно выполнять запросы к XML-данным без необходимости извлекать их полностью.

Синтаксис функции: XML_EXISTS ( XQuery )

Аргумент:

  • XQuery: Строковое выражение XQuery 1.0. Это выражение выполняется над XML-документом и определяет, какие узлы искать. Выражение может содержать префиксы пространств имен, которые должны быть предварительно объявлены.

Функция работает в контексте XML-столбца или переменной и требует корректного формирования XPath-выражения. Она не поддерживает пользовательские агрегатные функции и ограничена возможностями XQuery в SQL Server.

Примеры использования XML_EXISTS

Создадим тестовую таблицу и данные:

CREATE TABLE Products (
    ID INT PRIMARY KEY,
    ProductData XML
);

INSERT INTO Products VALUES 
(1, '<product><name>Keyboard</name><category>Electronics</category></product>'),
(2, '<product><name>Chair</name><category>Furniture</category></product>'),
(3, '<product><name>Mouse</name><category>Electronics</category></product>');

Пример 1. Проверка существования элемента:

SELECT ID 
FROM Products 
WHERE XML_EXISTS('product/name' PASSING ProductData);
ID
--
1
2
3

Пример 2. Проверка с условием по значению:

SELECT ID 
FROM Products 
WHERE XML_EXISTS('product[category="Electronics"]' PASSING ProductData);
ID
--
1
3

Пример 3. Использование пространств имен:

DECLARE @xml XML = '<root xmlns:a="http://example.com"><a:elem>test</a:elem></root>';

SELECT 
    CASE WHEN XML_EXISTS('declare namespace a="http://example.com"; /root/a:elem' PASSING @xml)
        THEN 1 ELSE 0 
    END AS Result;
Result
------
1

Похожие функции в MS SQL

В MS SQL Server существуют другие функции для работы с XML, каждая со своей спецификой:

  • value() — извлекает скалярное значение из XML. Применяется, когда нужно получить конкретное значение узла как скалярный тип SQL. Менее эффективна для проверки существования, но полезна для извлечения данных.
  • query() — выполняет XQuery и возвращает XML. Используется, когда требуется извлечь фрагмент XML. Не подходит для логических проверок в WHERE.
  • nodes() — разбивает XML на строки результирующего набора. Полезен для преобразования XML в реляционный формат, но сложнее для простых проверок существования.
  • exist() — аналогична XML_EXISTS, но с другим синтаксисом (вызывается как метод XML-типа). Обе функции похожи, но XML_EXISTS может быть удобнее в некоторых сценариях, особенно при использовании с пространствами имен.

XML_EXISTS предпочтительнее использовать в предложении WHERE для фильтрации по существованию узлов, особенно когда не требуется извлекать значения. Для извлечения данных лучше подходят value() или query().

Типичные ошибки

1. Неправильное указание пути XPath:

-- Ошибка: пропущен корневой элемент
SELECT ID FROM Products 
WHERE XML_EXISTS('name' PASSING ProductData);
Сообщение об ошибке: XQuery ... syntax error near 'name'

2. Использование неправильного синтаксиса пространств имен:

DECLARE @xml XML = '<root xmlns="http://example.com"><elem>test</elem></root>';

-- Ошибка: не объявлен namespace
SELECT CASE WHEN XML_EXISTS('/root/elem' PASSING @xml) THEN 1 ELSE 0 END;
Result
------
0 (не найдет элемент из-за default namespace)

3. Попытка использовать XML_EXISTS без XML-столбца:

-- Ошибка: неправильный тип данных
SELECT XML_EXISTS('/*' PASSING 'not_xml');
Сообщение об ошибке: Argument data type varchar is invalid for argument 2 of xml_exists function.

4. Ошибки производительности при сложных XPath-выражениях на больших XML-документах. Рекомендуется использовать индексы XML.

Изменения в последних версиях

Функция XML EXISTS была введена в SQL Server 2005 вместе с базовой поддержкой XML. В последующих версиях существенных изменений в синтаксис функции не вносилось. Однако, улучшения касались:

  • SQL Server 2008: улучшена производительность XQuery и исправлены ошибки обработки пространств имен.
  • SQL Server 2012: расширены возможности XQuery, включая поддержку FLWOR-выражений, что косвенно повлияло на работу XML_EXISTS.
  • SQL Server 2016 и выше: оптимизация работы с XML в целом, улучшение планов выполнения запросов с XML-предикатами.

В текущих версиях SQL Server (2019, 2022) функция работает стабильно, рекомендуется использовать последние версии для лучшей производительности и безопасности.

Расширенные примеры

Пример 1. Использование с FLWOR-выражением:

Пример sql
DECLARE @xml XML = '<products><product id="1"/><product id="2"/></products>';

SELECT 
    CASE 
        WHEN XML_EXISTS('for $p in /products/product where $p/@id = "1" return $p' PASSING @xml)
        THEN 1 ELSE 0 
    END AS Result;
Result
------
1

Пример 2. Проверка нескольких условий:

Пример sql
SELECT ID
FROM Products
WHERE XML_EXISTS('product[name="Keyboard" and category="Electronics"]' PASSING ProductData);
ID
--
1

Пример 3. Работа с атрибутами:

Пример sql
DECLARE @xml XML = '<product status="active">Keyboard</product>';

SELECT 
    CASE WHEN XML_EXISTS('product[@status="active"]' PASSING @xml)
        THEN 1 ELSE 0 
    END AS Result;
Result
------
1

Пример 4. Использование в сочетании с другими XML-функциями:

Пример sql
SELECT 
    ID,
    ProductData.value('(/product/name)[1]', 'varchar(50)') AS Name
FROM Products
WHERE XML_EXISTS('product[category="Electronics"]' PASSING ProductData)
    AND ProductData.exist('/product[name]') = 1;
ID   Name
---  ---------
1    Keyboard
3    Mouse

Пример 5. Рекурсивный поиск:

Пример sql
DECLARE @xml XML = '<root><a><b><c>target</c></b></a></root>';

SELECT 
    CASE WHEN XML_EXISTS('//c[text()="target"]' PASSING @xml)
        THEN 1 ELSE 0 
    END AS Result;
Result
------
1

Аналоги в других СУБД и языках

В других системах управления базами данных существуют похожие механизмы:

Oracle:

-- Использование XMLExists
SELECT * 
FROM Products 
WHERE XMLExists('$p/product[category="Electronics"]' 
                PASSING ProductData AS "p");

PostgreSQL (с расширением xml2):

SELECT * 
FROM Products 
WHERE xpath_exists('/product[category="Electronics"]', ProductData);

MySQL:

SELECT * 
FROM Products 
WHERE ExtractValue(ProductData, '/product/category') = 'Electronics';

SQLite не имеет встроенной поддержки XQuery, но можно использовать функции JSON, если данные в формате JSON.

Sybase ASE не поддерживает XML_EXISTS, требуется использование других методов работы с XML.

В языках программирования, таких как XPath в .NET (System.Xml.XPath):

// C# пример
bool exists = xmlDocument.SelectSingleNode("/product/category") != null;

Основные отличия MS SQL функции — синтаксис с ключевым словом PASSING и интеграция с движком XQuery SQL Server. В Oracle и PostgreSQL подход похож, но с другими именами функций и особенностями синтаксиса.

MS SQL XML_EXISTS function comments

En
XML EXISTS (XQuery method) Returns a bit that indicates whether a query returns a nonempty sequence