Java API for XML Processing (DOM Interface, SAX Interface) a
Java Architecture for XML Binding jsou dobře známé technologie běžně používané
pro práci s XML dokumenty v Java světě. Každá z nich má své výhody a
nevýhody a z toho vyplývá vhodnost jejich použití pro konkrétní aplikace. Například
SAX Parser se hodí pro sekvenční zpracování celých velkých a klidně i
nevalidních dokumentů s minimálními nároky na paměť. JAXB zase umí XML schéma,
může přistupovat do dokumentu náhodně, je možné dokument měnit a
z objektového modelu zpět generovat do XML a to vše prakticky bez nutnosti
znát XML. O tom už bylo jinde napsáno dost.
Žádná z těchto technologií ale neumí elegantně řešit
přechod mezi světem relační databáze a světem XML, vždy je nutno pro tento účel
realizovat nějaké procedurální zpracování.
Pokud je úkolem aplikace jen rozebírání XML dokumentu a ukládání dat
z něj získaných do relační databáze nebo naopak generování XML dokumentů
z relačních dat, existuje zajímá alternativa v rozšíření jazyka SQL o
XML operace – SQL/XML. A jelikož se jedná o SQL, tak vše je výhradně
deklarativní.
SQL/XML je definováno ve standardu ANSI.SQL ve verzi SQL-2006
a jako takové je implementováno v řadě databázových systémů aktuálních
verzí (Oracle, MS SQL Server, PostgreSQL, IBM DB2, …). Jen je potřeba dát pozor
na to, že implementace standardu ANSI.SQL v databázových systémech různých
výrobců nejsou úplně totožné, standard nenařizuje vše a každý si vykládá
standard po svém.
Oracle implementoval SQL/XML poprvé do své databáze verze 10g, plnohodnotně do verze 11g.
Dále uvedu
dva základní příklady použití SQL/XML v databázi Oracle. Zdaleka se nejedná o
úplný výčet možností SQL/XML, podrobněji viz. dokumentace Oracle: https://docs.oracle.com/en/database/oracle/oracle-database/18/adxdb/index.html
Generování XML z relačních dat
Následující příklad vygeneruje XML dokument SQL dotazem do
relačních dat.
SELECT
XMLElement("Stredisko",
XMLAttributes(d.Department_id AS
"CisloStrediska"),
XMLForest(d.department_name AS
"NazevStrediska"),
XMLElement("Adresa",
XMLForest(street_address AS
"Ulice",
city AS "Mesto",
postal_code AS
"PSC",
country_name AS
"Stat")),
XMLElement("SeznamZamestnancu",
(SELECT
XMLAgg(XMLElement("Zamestnanec",
XMLAttributes(e.employee_id
AS "CisloZamestnance"),
XMLForest(e.first_name AS "Jmeno",
e.last_name AS
"Prijmeni",
e.email AS
"eMail",
e.phone_number AS
"Telefon",
e.hire_date AS
"PracovniPomerOd",
j.job_title AS
"Pozice",
e.salary AS
"Plat",
m.first_name || '
' ||
m.last_name AS
"Nadrizeny")))
FROM hr.employees e, hr.employees
m, hr.jobs j
WHERE e.department_id =
d.department_id
AND j.job_id = e.job_id
AND m.employee_id = e.manager_id)))
AS XML
FROM hr.departments
d, hr.countries c, hr.locations l
WHERE
department_name = 'Executive'
AND d.location_id = l.location_id
AND l.country_id = c.country_id;
Výsledkem dotazu je datový typ XMLTYPE s následujícím
obsahem.
<Stredisko IdStrediska="90">
<JmenoStrediska>Executive</JmenoStrediska>
<Adresa>
<Ulice>2004 Charade
Rd</Ulice>
<Mesto>Seattle</Mesto>
<PSC>98199</PSC>
<Stat>United States
of America</Stat>
</Adresa>
<SeznamZamestnancu>
<Zamestnanec
CisloZamestnance="101">
<Jmeno>Neena</Jmeno>
<Prijmeni>Kochhar</Prijmeni>
<eMail>NKOCHHAR</eMail>
<Telefon>515.123.4568</Telefon>
<PracovniPomerOd>1989-09-21</PracovniPomerOd>
<Pozice>Administration Vice
President</Pozice>
<Plat>17000</Plat>
<Nadrizeny>Steven
King</Nadrizeny>
</Zamestnanec>
<Zamestnanec
CisloZamestnance="102">
<Jmeno>Lex</Jmeno>
<Prijmeni>De Haan</Prijmeni>
<eMail>LDEHAAN</eMail>
<Telefon>515.123.4569</Telefon>
<PracovniPomerOd>1993-01-13</PracovniPomerOd>
<Pozice>Administration Vice President</Pozice>
<Plat>17000</Plat>
<Nadrizeny>Steven
King</Nadrizeny>
</Zamestnanec>
</SeznamZamestnancu>
</Stredisko>
SQL dotaz z XML dokumentu
V následujícím příkladu je
pro jednoduchost dotaz prováděn nad XML přímo vloženým do SQL dotazu pomocí
konstruktoru typu XMLTYPE(). Při reálném použití tam bude spíš proměnná nebo DB
sloupec s typem XMLTYPE nebo konstruktor XMLTYPE() jehož parametr bude proměnná
nebo DB sloupec nějakého textového typu (VARCHAR2, CLOB) nebo BLOB. Dotaz
vytěží data z XML dokumentu. Dokument obsahuje oddělení, jejich zaměstnance a
pro každého zaměstnance nepovinný seznam telefonních čísel. Jedná se tedy o tři
joinované dotazy. Join se zde neprovádí přes PK/FK, protože ve vzorovém XML je
vazba zařízena přes vnoření elementů. Join se v takovém případě neprovádí přes
SQL JOIN, ale klauzulí PASSING v operátoru XMLTABLE, tak že do podřízeného
dotazu se předá celý XML fragment obsahující vnořená data.
SELECT oddeleni.cislo_oddeleni,
oddeleni.nazev_oddeleni,
oddeleni.id,
zamestnanec.osobni_cislo,
zamestnanec.prijmeni,
zamestnanec.profese,
zamestnanec.id,
telefon.telefonni_cislo
FROM XMLTABLE(XMLNAMESPACES(DEFAULT
'cz:cca:testxmldb:1.0'),'/Document/department'
PASSING XMLTYPE(
'<?xml version="1.0" encoding="utf-8"?>
<Document
xmlns="cz:cca:testxmldb:1.0">
<department
deptno="10" dname="ACCOUNTIG">
<employees>
<employee
empno="7369" ename="SMITH" job="CLERK"
hiredate="17-DEC-1980">
<phones>
<phone>123456789</phone>
<phone>666777888</phone>
</phones>
</employee>
<employee
empno="7876" ename="ADAMS" job="CLERK"
hiredate="23-MAY-1987">
<phones>
<phone>000000000</phone>
</phones>
</employee>
<employee
empno="7900" ename="JAMES" job="CLERK"
hiredate="03-DEC-1981"/>
<employee
empno="7934" ename="MILLER" job="CLERK"
hiredate="23-JAN-1982"/>
<employee
empno="7698" ename="BLAKE" job="MANAGER"
hiredate="01-MAY-1981"/>
</employees>
</department>
<department
deptno="20" dname="SALES">
<employees>
<employee
empno="7521" ename="WARD" job="SALESMAN"
hiredate="22-FEB-1981"/>
<employee
empno="7566" ename="JONES" job="MANAGER"
hiredate="02-APR-1981"/>
<employee
empno="7654" ename="MARTIN" job="SALESMAN"
hiredate="28-SEP-1981"/>
<employee
empno="7499" ename="ALLEN" job="SALESMAN"
hiredate="20-FEB-1981"/>
<employee
empno="7902" ename="FORD" job="ANALYST"
hiredate="03-DEC-1981">
<phones>
<phone>987654321</phone>
<phone>111222333</phone>
</phones>
</employee>
<employee
empno="7844" ename="TURNER" job="SALESMAN"
hiredate="08-SEP-1981"/>
</employees>
</department>
</Document>')
COLUMNS cislo_oddeleni
NUMBER PATH '@deptno',
nazev_oddeleni
VARCHAR2(50) PATH '@dname',
zamestnanci XMLTYPE
PATH 'employees',
id FOR ORDINALITY)
oddeleni,
XMLTABLE(XMLNAMESPACES(DEFAULT
'cz:cca:testxmldb:1.0'),
'/employees/employee' PASSING oddeleni.zamestnanci COLUMNS
osobni_cislo NUMBER
PATH '@empno',
prijmeni
VARCHAR2(50) PATH '@ename',
profese VARCHAR2(50)
PATH '@job',
telefony XMLTYPE
PATH 'phones',
id FOR ORDINALITY)
zamestnanec,
XMLTABLE(XMLNAMESPACES(DEFAULT 'cz:cca:testxmldb:1.0'),
'phones/phone'
PASSING zamestnanec.telefony COLUMNS
telefonni_cislo VARCHAR2(50) PATH
'.',
id FOR
ORDINALITY)(+) telefon;
CISLO_ODDELENI NAZEV_ODDELENI ID
OSOBNI_CISLO PRIJMENI PROFESE ID TELEFONNI_CISLO
-------------- --------------- ---- ------------ ---------- --------- --
---------------
10 ACCOUNTIG 1 7369 SMITH CLERK
1 12345678
10 ACCOUNTIG 1 7369 SMITH CLERK
1 66677788
10 ACCOUNTIG 1 7876 ADAMS CLERK
2 00000000
10 ACCOUNTIG 1 7900 JAMES CLERK
3
10 ACCOUNTIG 1 7934 MILLER CLERK
4
10 ACCOUNTIG 1 7698 BLAKE MANAGER
5
20 SALES 2 7521 WARD SALESMAN 1
20 SALES 2 7566 JONES MANAGER
2
20 SALES 2 7654 MARTIN SALESMAN
3
20 SALES 2 7499 ALLEN SALESMAN
4
20 SALES 2 7902 FORD ANALYST
5 98765432
20 SALES 2 7902 FORD ANALYST 5 11122233
20 SALES 2 7844 TURNER SALESMAN
6
13 rows selected.
Autor: Luděk Kratochvíl
CCA Group a.s.
ludek.kratochvil@cca.cz
Žádné komentáře:
Okomentovat