XML в Oracle SQL. Введение
XML в Oracle — это не просто формат обмена, а целый маленький мир внутри базы.
Здесь можно хранить XML-документы, собирать их из реляционных таблиц, разбирать на колонки,
фильтровать по XPath и XQuery, агрегировать, сериализовать, валидировать и использовать в интеграциях.
Люблю эту тему за контраст: с одной стороны — строгая структура данных, с другой — очень гибкая модель представления.
Если хочется подружить реляционный мир и обменные форматы без лишней боли, XML в Oracle умеет это очень красиво.
Синтаксис
-- хранение
CREATE TABLE xml_docs (
doc_id NUMBER,
payload XMLTYPE
);
-- генерация XML
SELECT XMLELEMENT("root", XMLFOREST(col1 AS "col1", col2 AS "col2"))
FROM dual;
-- разбор XML в строки и столбцы
SELECT x.*
FROM XMLTABLE('/root/item'
PASSING XMLTYPE('<root><item>1</item></root>')
COLUMNS item_val VARCHAR2(30) PATH '.'
) x;Чаще всего в Oracle XML-сценариях используются
SELECT,
CREATE TABLE,
XMLTABLE,
XMLQUERY,
XMLCAST,
XMLELEMENT,
XMLFOREST,
XMLAGG,
XMLSERIALIZE
и тип XMLTYPE.
Где используют
- интеграции между системами и обмен сообщениями
- хранение полу-структурированных документов
- генерация XML-ответов из реляционных таблиц
- разбор XML-файлов и сообщений в таблицы
- построение витрин и API-ответов
- миграции и совместимость со старыми корпоративными форматами
100 примеров
1. Создание таблицы с колонкой XMLTYPE
CREATE TABLE xml_docs (
doc_id NUMBER PRIMARY KEY,
payload XMLTYPE
)2. Вставка простого XML-документа
INSERT INTO xml_docs(doc_id,payload)
VALUES (
1,
XMLTYPE('<order><id>1001</id><status>NEW</status></order>')
)3. Выбор всего XML-документа из таблицы
SELECT doc_id,payload
FROM xml_docs4. Генерация XML через XMLELEMENT
SELECT XMLELEMENT("hello",'world') AS xml_val
FROM dual5. Генерация XML с атрибутом через XMLATTRIBUTES
SELECT XMLELEMENT(
"user",
XMLATTRIBUTES(100 AS "id"),
'Alice'
) AS xml_val
FROM dual6. Создание нескольких тегов через XMLFOREST
SELECT XMLFOREST(
'Alice' AS "name",
'alice@example.com' AS "email"
) AS xml_val
FROM dual7. Комбинация XMLELEMENT и XMLFOREST
SELECT XMLELEMENT(
"customer",
XMLFOREST(
10 AS "customer_id",
'Alice' AS "customer_name"
)
) AS xml_val
FROM dual8. XML для строки пользователя из таблицы
SELECT XMLELEMENT(
"user",
XMLFOREST(
user_id AS "id",
email AS "email"
)
) AS user_xml
FROM users9. XML-список через XMLAGG
SELECT XMLELEMENT(
"users",
XMLAGG(
XMLELEMENT("user", XMLFOREST(user_id AS "id", email AS "email"))
)
) AS users_xml
FROM users10. Сериализация XMLTYPE в CLOB
SELECT XMLSERIALIZE(
CONTENT XMLELEMENT("msg",'ok')
AS CLOB
) AS xml_clob
FROM dual11. Сериализация XML с отступами
SELECT XMLSERIALIZE(
CONTENT XMLELEMENT("msg",XMLFOREST('ok' AS "status"))
AS CLOB INDENT SIZE = 2
) AS xml_pretty
FROM dual12. Извлечение подузла через XMLQUERY
SELECT XMLQUERY(
'/order/status'
PASSING XMLTYPE('<order><id>1001</id><status>NEW</status></order>')
RETURNING CONTENT
) AS status_xml
FROM dual13. Извлечение значения и приведение типа через XMLCAST
SELECT XMLCAST(
XMLQUERY('/order/id/text()'
PASSING XMLTYPE('<order><id>1001</id></order>')
RETURNING CONTENT
) AS NUMBER
) AS order_id
FROM dual14. Проверка существования узла через XMLEXISTS
SELECT CASE
WHEN XMLEXISTS(
'/order/status'
PASSING XMLTYPE('<order><status>NEW</status></order>')
)
THEN 1 ELSE 0
END AS has_status
FROM dual15. Разбор одного узла в колонку через XMLTABLE
SELECT x.order_id
FROM XMLTABLE(
'/order'
PASSING XMLTYPE('<order><id>1001</id></order>')
COLUMNS order_id NUMBER PATH 'id'
) x16. Разбор нескольких колонок через XMLTABLE
SELECT x.order_id,x.status
FROM XMLTABLE(
'/order'
PASSING XMLTYPE('<order><id>1001</id><status>NEW</status></order>')
COLUMNS
order_id NUMBER PATH 'id',
status VARCHAR2(20) PATH 'status'
) x17. Разбор списка элементов item через XMLTABLE
SELECT x.item_id,x.qty
FROM XMLTABLE(
'/order/items/item'
PASSING XMLTYPE(
'<order><items>
<item><id>1</id><qty>2</qty></item>
<item><id>2</id><qty>5</qty></item>
</items></order>'
)
COLUMNS
item_id NUMBER PATH 'id',
qty NUMBER PATH 'qty'
) x18. Разбор атрибута XML в колонку
SELECT x.user_id,x.user_name
FROM XMLTABLE(
'/user'
PASSING XMLTYPE('<user id="10"><name>Alice</name></user>')
COLUMNS
user_id NUMBER PATH '@id',
user_name VARCHAR2(50) PATH 'name'
) x19. Хранение XML в XMLTYPE и чтение id через XMLTABLE
SELECT d.doc_id,x.order_id
FROM xml_docs d,
XMLTABLE(
'/order'
PASSING d.payload
COLUMNS order_id NUMBER PATH 'id'
) x20. Разбор вложенного адреса
SELECT x.city_name,x.zip_code
FROM XMLTABLE(
'/customer/address'
PASSING XMLTYPE('<customer><address><city>Paris</city><zip>75001</zip></address></customer>')
COLUMNS
city_name VARCHAR2(50) PATH 'city',
zip_code VARCHAR2(20) PATH 'zip'
) xЕще 20 примеров
21. Получение XML-фрагмента через XMLQUERY и RETURNING CONTENT
SELECT XMLQUERY(
'/customer/address'
PASSING XMLTYPE('<customer><name>Ann</name><address><city>Paris</city></address></customer>')
RETURNING CONTENT
) AS addr_xml
FROM dual22. Извлечение текстового значения из XML через XMLCAST
SELECT XMLCAST(
XMLQUERY('/customer/name/text()'
PASSING XMLTYPE('<customer><name>Ann</name></customer>')
RETURNING CONTENT
) AS VARCHAR2(50)
) AS customer_name
FROM dual23. Преобразование даты из XML
SELECT XMLCAST(
XMLQUERY('/doc/date/text()'
PASSING XMLTYPE('<doc><date>2026-03-27</date></doc>')
RETURNING CONTENT
) AS DATE
) AS doc_date
FROM dual24. Фильтрация XML по наличию узла amount
SELECT doc_id
FROM xml_docs
WHERE XMLEXISTS('/order/amount' PASSING payload)25. Фильтрация XML по значению статуса
SELECT doc_id
FROM xml_docs
WHERE XMLEXISTS('/order[status="NEW"]' PASSING payload)26. Генерация XML для одного заказа из таблицы
SELECT XMLELEMENT(
"order",
XMLFOREST(
order_id AS "id",
status AS "status",
order_date AS "order_date"
)
) AS order_xml
FROM orders
WHERE order_id = 100127. XML c вложенным customer-блоком
SELECT XMLELEMENT(
"order",
XMLFOREST(
o.order_id AS "id",
o.status AS "status"
),
XMLELEMENT(
"customer",
XMLFOREST(u.user_id AS "id", u.email AS "email")
)
) AS order_xml
FROM orders o
JOIN users u ON u.user_id = o.user_id
WHERE o.order_id = 100128. XML-список строк заказа с XMLAGG
SELECT XMLELEMENT(
"items",
XMLAGG(
XMLELEMENT(
"item",
XMLFOREST(item_id AS "item_id", qty AS "qty")
)
)
) AS items_xml
FROM order_items
WHERE order_id = 100129. Полный заказ с вложенными строками
SELECT XMLELEMENT(
"order",
XMLFOREST(o.order_id AS "id", o.status AS "status"),
XMLELEMENT(
"items",
(
SELECT XMLAGG(
XMLELEMENT(
"item",
XMLFOREST(oi.item_id AS "item_id", oi.qty AS "qty")
)
)
FROM order_items oi
WHERE oi.order_id = o.order_id
)
)
) AS full_order_xml
FROM orders o
WHERE o.order_id = 100130. XMLForest без явного AS для имён колонок
SELECT XMLFOREST(user_id,email) AS user_xml
FROM users
FETCH FIRST 1 ROW ONLY31. Оборачивание XMLForest в root-тег
SELECT XMLELEMENT("root", XMLFOREST(1 AS "id",'ok' AS "status")) AS xml_val
FROM dual32. Сериализация XML как VARCHAR2
SELECT XMLSERIALIZE(
CONTENT XMLELEMENT("ping",'pong')
AS VARCHAR2(100)
) AS xml_txt
FROM dual33. XMLQuery с фильтром по значению атрибута
SELECT XMLQUERY(
'/root/item[@id="2"]'
PASSING XMLTYPE('<root><item id="1"/><item id="2"/></root>')
RETURNING CONTENT
) AS item_xml
FROM dual34. XMLTable для списка кодов статусов
SELECT x.status_code
FROM XMLTABLE(
'/statuses/status'
PASSING XMLTYPE('<statuses><status>NEW</status><status>DONE</status></statuses>')
COLUMNS status_code VARCHAR2(20) PATH '.'
) x35. Разбор нескольких XML-документов через UNION ALL и XMLTABLE
SELECT x.order_id
FROM (
SELECT XMLTYPE('<order><id>1</id></order>') AS payload FROM dual
UNION ALL
SELECT XMLTYPE('<order><id>2</id></order>') FROM dual
) d,
XMLTABLE(
'/order'
PASSING d.payload
COLUMNS order_id NUMBER PATH 'id'
) x36. XMLExists в CASE-логике
SELECT CASE
WHEN XMLEXISTS('/user/email' PASSING XMLTYPE('<user><email>a@b.c</email></user>'))
THEN 'HAS_EMAIL'
ELSE 'NO_EMAIL'
END AS email_flag
FROM dual37. Разбор nested XML внутри XMLTABLE
SELECT x.order_id,x.city_name
FROM XMLTABLE(
'/order'
PASSING XMLTYPE('<order><id>1001</id><shipping><city>Paris</city></shipping></order>')
COLUMNS
order_id NUMBER PATH 'id',
city_name VARCHAR2(50) PATH 'shipping/city'
) x38. Извлечение суммы заказа как NUMBER
SELECT XMLCAST(
XMLQUERY('/order/amount/text()'
PASSING XMLTYPE('<order><amount>150.75</amount></order>')
RETURNING CONTENT
) AS NUMBER
) AS order_amount
FROM dual39. Генерация XML для адреса через вложенные элементы
SELECT XMLELEMENT(
"address",
XMLELEMENT("city",'Paris'),
XMLELEMENT("zip",'75001')
) AS addr_xml
FROM dual40. XML из нескольких строк через XMLAgg и ORDER BY
SELECT XMLELEMENT(
"codes",
XMLAGG(
XMLELEMENT("code",status_code)
ORDER BY status_code
)
) AS codes_xml
FROM statusesЕще 20 примеров
41. Вставка XML, собранного из реляционных данных
INSERT INTO xml_docs(doc_id,payload)
SELECT 2,
XMLELEMENT(
"user",
XMLFOREST(user_id AS "id", email AS "email")
)
FROM users
WHERE user_id = 1042. Обновление XML-документа целиком
UPDATE xml_docs
SET payload = XMLTYPE('<order><id>1001</id><status>DONE</status></order>')
WHERE doc_id = 143. Разбор XML из CLOB через XMLTYPE
SELECT XMLCAST(
XMLQUERY('/root/value/text()'
PASSING XMLTYPE(TO_CLOB('<root><value>42</value></root>'))
RETURNING CONTENT
) AS NUMBER
) AS val_num
FROM dual44. Извлечение email из XML-профиля
SELECT XMLCAST(
XMLQUERY('/profile/email/text()'
PASSING XMLTYPE('<profile><email>alice@example.com</email></profile>')
RETURNING CONTENT
) AS VARCHAR2(200)
) AS email_val
FROM dual45. XMLTable для пар country-code и country-name
SELECT x.country_code,x.country_name
FROM XMLTABLE(
'/countries/country'
PASSING XMLTYPE('<countries><country code="FR">France</country><country code="DE">Germany</country></countries>')
COLUMNS
country_code VARCHAR2(10) PATH '@code',
country_name VARCHAR2(50) PATH '.'
) x46. XMLQuery с несколькими return-элементами
SELECT XMLQUERY(
'for $i in /root/item return <code>{$i/text()}</code>'
PASSING XMLTYPE('<root><item>A</item><item>B</item></root>')
RETURNING CONTENT
) AS codes_xml
FROM dual47. XMLExists для поиска конкретного item
SELECT CASE
WHEN XMLEXISTS('/root/item[text()="B"]'
PASSING XMLTYPE('<root><item>A</item><item>B</item></root>'))
THEN 1 ELSE 0
END AS has_b
FROM dual48. Вывод XML как текст для API-ответа
SELECT XMLSERIALIZE(
CONTENT XMLELEMENT(
"response",
XMLFOREST('ok' AS "status", SYSTIMESTAMP AS "generated_at")
)
AS CLOB
) AS api_xml
FROM dual49. Построение XML-каталога товаров
SELECT XMLELEMENT(
"catalog",
XMLAGG(
XMLELEMENT(
"product",
XMLFOREST(product_id AS "id", product_name AS "name", price AS "price")
)
)
) AS catalog_xml
FROM products50. Построение XML-ленты заказов по дате
SELECT XMLELEMENT(
"orders",
XMLAGG(
XMLELEMENT(
"order",
XMLFOREST(order_id AS "id", order_date AS "dt", status AS "status")
)
ORDER BY order_date DESC
)
) AS orders_xml
FROM orders51. XMLForest с числом и датой
SELECT XMLFOREST(
1001 AS "id",
DATE '2026-03-27' AS "doc_date"
) AS xml_val
FROM dual52. Оборачивание XMLAgg в root и child
SELECT XMLELEMENT(
"rows",
XMLAGG(
XMLELEMENT("row", XMLFOREST(user_id AS "id"))
)
) AS rows_xml
FROM users53. Хранение XML заказа с атрибутом версии
INSERT INTO xml_docs(doc_id,payload)
VALUES (
3,
XMLELEMENT(
"order",
XMLATTRIBUTES('1.0' AS "version"),
XMLFOREST(2001 AS "id",'NEW' AS "status")
)
)54. XMLSerialize DOCUMENT вместо CONTENT
SELECT XMLSERIALIZE(
DOCUMENT XMLTYPE('<root><a>1</a></root>')
AS CLOB
) AS doc_xml
FROM dual55. XMLTable с двумя уровнями вложенности
SELECT x.user_id,x.city_name
FROM XMLTABLE(
'/root/user'
PASSING XMLTYPE('<root><user><id>10</id><addr><city>Rome</city></addr></user></root>')
COLUMNS
user_id NUMBER PATH 'id',
city_name VARCHAR2(50) PATH 'addr/city'
) x56. Превращение XML-списка в реляционные строки и join с таблицей
SELECT u.user_id,u.email,x.ext_id
FROM users u
JOIN XMLTABLE(
'/ids/id'
PASSING XMLTYPE('<ids><id>10</id><id>20</id></ids>')
COLUMNS ext_id NUMBER PATH '.'
) x
ON u.user_id = x.ext_id57. XMLQuery для выборки всех item-элементов
SELECT XMLQUERY(
'/root/item'
PASSING XMLTYPE('<root><item>1</item><item>2</item></root>')
RETURNING CONTENT
) AS items_xml
FROM dual58. XMLCast числа из атрибута
SELECT XMLCAST(
XMLQUERY('/user/@id'
PASSING XMLTYPE('<user id="10"/>')
RETURNING CONTENT
) AS NUMBER
) AS user_id
FROM dual59. Генерация XML-ответа с кодом и сообщением
SELECT XMLELEMENT(
"response",
XMLFOREST(
200 AS "code",
'ok' AS "message"
)
) AS response_xml
FROM dual60. XML из справочника статусов
SELECT XMLELEMENT(
"statuses",
XMLAGG(XMLELEMENT("status",status_code))
) AS statuses_xml
FROM statusesЕще 20 примеров
61. XML для экспорта списка городов
SELECT XMLELEMENT(
"cities",
XMLAGG(
XMLELEMENT("city", XMLFOREST(city_code AS "code", city_name AS "name"))
)
) AS cities_xml
FROM city_dim62. Фильтрация XML-документов по country code
SELECT doc_id
FROM xml_docs
WHERE XMLEXISTS('/order/customer/country[text()="FR"]' PASSING payload)63. XMLTable для тегов продукта
SELECT x.tag_name
FROM XMLTABLE(
'/product/tags/tag'
PASSING XMLTYPE('<product><tags><tag>new</tag><tag>hot</tag></tags></product>')
COLUMNS tag_name VARCHAR2(30) PATH '.'
) x64. XMLQuery с XQuery-конкатенацией
SELECT XMLQUERY(
'string(/user/first) || " " || string(/user/last)'
PASSING XMLTYPE('<user><first>Ann</first><last>Lee</last></user>')
RETURNING CONTENT
) AS full_name_xml
FROM dual65. XMLCast результата XQuery в VARCHAR2
SELECT XMLCAST(
XMLQUERY(
'string(/user/first) || " " || string(/user/last)'
PASSING XMLTYPE('<user><first>Ann</first><last>Lee</last></user>')
RETURNING CONTENT
) AS VARCHAR2(100)
) AS full_name
FROM dual66. XMLSerialize в JSON-подобный transport-текст не нужен, но как CLOB полезен
SELECT XMLSERIALIZE(
CONTENT XMLELEMENT("ping",XMLFOREST('ok' AS "status"))
AS CLOB
) AS payload_txt
FROM dual67. Извлечение набора item-ов и подсчёт строк
SELECT COUNT(*) AS item_cnt
FROM XMLTABLE(
'/order/items/item'
PASSING XMLTYPE('<order><items><item/><item/><item/></items></order>')
COLUMNS dummy VARCHAR2(1) PATH '.'
) x68. XMLAgg для email-списка
SELECT XMLELEMENT(
"emails",
XMLAGG(XMLELEMENT("email",email))
) AS email_xml
FROM users69. XMLForest для документа с числами и флагами
SELECT XMLFOREST(
1 AS "id",
100.5 AS "amount",
1 AS "active_flag"
) AS xml_val
FROM dual70. XMLTable для invoice lines с price
SELECT x.item_code,x.price_amt
FROM XMLTABLE(
'/invoice/lines/line'
PASSING XMLTYPE('<invoice><lines><line><code>A</code><price>10</price></line><line><code>B</code><price>20</price></line></lines></invoice>')
COLUMNS
item_code VARCHAR2(20) PATH 'code',
price_amt NUMBER PATH 'price'
) x71. Поиск XML-документов со статусом DONE
SELECT doc_id
FROM xml_docs
WHERE XMLEXISTS('/order[status="DONE"]' PASSING payload)72. XMLQuery для выбора только адресного города
SELECT XMLQUERY(
'/customer/address/city'
PASSING XMLTYPE('<customer><address><city>Madrid</city></address></customer>')
RETURNING CONTENT
) AS city_xml
FROM dual73. XMLCast булева признака в NUMBER
SELECT XMLCAST(
XMLQUERY('/root/flag/text()'
PASSING XMLTYPE('<root><flag>1</flag></root>')
RETURNING CONTENT
) AS NUMBER
) AS flag_num
FROM dual74. XMLTable с optional-элементом и NULL
SELECT x.phone_val
FROM XMLTABLE(
'/user'
PASSING XMLTYPE('<user><name>Ann</name></user>')
COLUMNS phone_val VARCHAR2(30) PATH 'phone'
) x75. Генерация XML из констант через dual
SELECT XMLELEMENT(
"config",
XMLFOREST('prod' AS "env", 50 AS "page_size")
) AS config_xml
FROM dual76. XML для одного продукта с тегами и ценой
SELECT XMLELEMENT(
"product",
XMLFOREST(p.product_id AS "id", p.product_name AS "name", p.price AS "price"),
XMLELEMENT("tags",
XMLAGG(XMLELEMENT("tag",t.tag_name))
)
) AS product_xml
FROM products p
JOIN product_tags t ON t.product_id = p.product_id
WHERE p.product_id = 1
GROUP BY p.product_id,p.product_name,p.price77. XML-список id через XMLAgg
SELECT XMLELEMENT(
"ids",
XMLAGG(XMLELEMENT("id",user_id))
) AS ids_xml
FROM users78. XMLSerialize XMLTYPE-колонки в текстовом выводе
SELECT doc_id,
XMLSERIALIZE(CONTENT payload AS CLOB) AS payload_txt
FROM xml_docs79. Разбор атрибута currency из XML счета
SELECT x.ccy,x.amount_val
FROM XMLTABLE(
'/invoice'
PASSING XMLTYPE('<invoice currency="EUR"><amount>150</amount></invoice>')
COLUMNS
ccy VARCHAR2(10) PATH '@currency',
amount_val NUMBER PATH 'amount'
) x80. Проверка наличия атрибута id
SELECT CASE
WHEN XMLEXISTS('/user/@id'
PASSING XMLTYPE('<user id="10"/>'))
THEN 1 ELSE 0
END AS has_id
FROM dualЕще 20 примеров
81. EXTRACTVALUE для старого кода (legacy)
SELECT EXTRACTVALUE(
XMLTYPE('<order><id>1001</id></order>'),
'/order/id'
) AS order_id
FROM dual82. XMLType в merge-like staging хранении
CREATE TABLE xml_stage (
batch_id NUMBER,
payload XMLTYPE
)83. Загрузка XML в staging-таблицу
INSERT INTO xml_stage(batch_id,payload)
VALUES (
1,
XMLTYPE('<root><item>A</item></root>')
)84. Разбор XML из staging через XMLTable
SELECT s.batch_id,x.item_val
FROM xml_stage s,
XMLTABLE(
'/root/item'
PASSING s.payload
COLUMNS item_val VARCHAR2(30) PATH '.'
) x85. Преобразование XML-документов в реляционный вид для join
SELECT x.user_id,u.email
FROM xml_stage s,
XMLTABLE(
'/root/user'
PASSING s.payload
COLUMNS user_id NUMBER PATH 'id'
) x
JOIN users u ON u.user_id = x.user_id86. XMLAggregate из справочника городов по стране
SELECT XMLELEMENT(
"country",
XMLATTRIBUTES(country_code AS "code"),
XMLAGG(XMLELEMENT("city",city_name))
) AS country_xml
FROM city_dim
GROUP BY country_code87. Генерация XML ответа для KPI
SELECT XMLELEMENT(
"kpi",
XMLFOREST(
kpi_code AS "code",
plan_val AS "plan",
fact_val AS "fact"
)
) AS kpi_xml
FROM kpi_table88. XML с вложенным массивом email-ов
SELECT XMLELEMENT(
"emails",
XMLAGG(XMLELEMENT("email",email) ORDER BY email)
) AS emails_xml
FROM users89. Поиск документов, где amount больше 100
SELECT doc_id
FROM xml_docs
WHERE XMLEXISTS('/order[number(amount) > 100]' PASSING payload)90. Разбор координат из XML
SELECT x.lat_val,x.lon_val
FROM XMLTABLE(
'/point'
PASSING XMLTYPE('<point><lat>48.85</lat><lon>2.35</lon></point>')
COLUMNS
lat_val NUMBER PATH 'lat',
lon_val NUMBER PATH 'lon'
) x91. XMLQuery c XQuery for-return
SELECT XMLQUERY(
'for $i in /root/item return <value>{data($i)}</value>'
PASSING XMLTYPE('<root><item>10</item><item>20</item></root>')
RETURNING CONTENT
) AS values_xml
FROM dual92. XMLSerialize для выгрузки в файл-слой
SELECT XMLSERIALIZE(
CONTENT XMLELEMENT("export", XMLFOREST(SYSDATE AS "dt"))
AS CLOB INDENT SIZE = 2
) AS export_xml
FROM dual93. XMLForest для параметров приложения
SELECT XMLELEMENT(
"params",
XMLAGG(
XMLELEMENT("param", XMLFOREST(param_code AS "code", param_value AS "value"))
)
) AS params_xml
FROM app_params94. XML c атрибутами и текстовым содержимым
SELECT XMLELEMENT(
"status",
XMLATTRIBUTES('1' AS "code"),
'OK'
) AS status_xml
FROM dual95. Преобразование XML-списка в id и status
SELECT x.id_val,x.status_val
FROM XMLTABLE(
'/rows/row'
PASSING XMLTYPE('<rows><row><id>1</id><status>A</status></row><row><id>2</id><status>B</status></row></rows>')
COLUMNS
id_val NUMBER PATH 'id',
status_val VARCHAR2(10) PATH 'status'
) x96. XMLEXISTS по email-атрибуту
SELECT CASE
WHEN XMLEXISTS('/user[@email="alice@example.com"]'
PASSING XMLTYPE('<user email="alice@example.com"/>'))
THEN 'Y' ELSE 'N'
END AS email_match
FROM dual97. XMLType-колонка с выборкой только текста через XMLCast
SELECT d.doc_id,
XMLCAST(
XMLQUERY('/order/status/text()'
PASSING d.payload
RETURNING CONTENT
) AS VARCHAR2(20)
) AS status_txt
FROM xml_docs d98. Генерация XML-профиля клиента из join
SELECT XMLELEMENT(
"profile",
XMLFOREST(c.customer_id AS "id", c.customer_name AS "name", a.city AS "city")
) AS profile_xml
FROM customers c
LEFT JOIN addresses a ON a.customer_id = c.customer_id99. XML-отчёт по заказам и сумме
SELECT XMLELEMENT(
"report",
XMLAGG(
XMLELEMENT(
"order",
XMLFOREST(order_id AS "id", total_amt AS "amount")
)
)
) AS report_xml
FROM daily_totals100. Финальный пример: полный XML-документ с root, списком rows и pretty-serialize
SELECT XMLSERIALIZE(
CONTENT XMLELEMENT(
"result",
XMLAGG(
XMLELEMENT(
"row",
XMLFOREST(user_id AS "id", email AS "email")
)
ORDER BY user_id
)
)
AS CLOB INDENT SIZE = 2
) AS final_xml
FROM usersЗаключение
XML в Oracle — это очень зрелая история. Здесь можно и хранить документы, и извлекать из них данные,
и собирать аккуратные XML-ответы из обычных таблиц. Особенно приятно, что Oracle даёт не один инструмент,
а целую экосистему: XMLType для хранения, XMLTABLE для разбора,
XMLQUERY и XMLEXISTS для XQuery-логики,
XMLELEMENT, XMLFOREST и XMLAGG для генерации.
Если любишь SQL за выразительность, то XML-сценарии в Oracle умеют очень красиво соединять реляционный и документный мир.
Официальная документация Oracle:
Oracle XML DB — Introduction
XMLTABLE
XMLQUERY
XMLFOREST
XMLAGG
🔜 Следующая статья:
WRITE в Oracle SQL — как использовать буферную запись