DB2 9 (Viper) 引入 原生 XML 數據類型,將 XML 以層次化格式存儲於列中。熟悉 SQL 的開發者可直接使用 SQL/XML (ISO 標準) 函數查詢、轉換、發布 XML,無需學習全新語言。
CREATE TABLE items (
id INT PRIMARY KEY NOT NULL,
brandname VARCHAR(30),
itemname VARCHAR(30),
sku INT,
srp DECIMAL(7,2),
comments XML
);
CREATE TABLE clients (
id INT PRIMARY KEY NOT NULL,
name VARCHAR(50),
status VARCHAR(10),
contactinfo XML
);
SELECT * FROM clients 可取整個 XML 文檔XMLEXISTS、XMLQUERY、XMLTABLE 等 SQL/XML 函數| 函數 | 用途 | 典型子句 |
|---|---|---|
| XMLEXISTS | WHERE 中按 XPath 條件過濾行 | XMLEXISTS('$c/Client/Address[zip="95116"]' PASSING contactinfo AS "c") |
| XMLQUERY | SELECT 列表中投影 XML 片段/值 | XMLQUERY('$c/Client/email[1]' PASSING contactinfo AS "c") |
| XMLTABLE | 將 XML 節點映射為關系結果集列 | COLUMNS cid INT PATH 'CommentID', msg VARCHAR(100) PATH 'Message' |
| XMLELEMENT | 關系數據構造 XML 元素 | XMLELEMENT(NAME "item", XMLELEMENT(NAME "id", id), ...) |
| XMLAGG | 聚合多行 XML 片段為序列 | XMLAGG(XMLELEMENT(...)) ORDER BY name |
| XMLFOREST | 快速構造多個同級元素 | XMLFOREST(name AS "fullName", status AS "status") |
SELECT name FROM clients
WHERE XMLEXISTS('$c/Client/Address[zip="95116"]'
PASSING clients.contactinfo AS "c");
陷阱:XMLEXISTS('$c/Client/Address/zip="95116"') 語法合法但不會過濾,必須用謂詞 [zip="95116"]。
SELECT XMLQUERY('$c/Client/email[1]' PASSING contactinfo AS "c")
FROM clients WHERE status = 'Gold';
排除無 email 客戶:
SELECT XMLQUERY('$c/Client/email[1]' PASSING contactinfo AS "c")
FROM clients
WHERE status = 'Gold'
AND XMLEXISTS('$c/Client/email' PASSING contactinfo AS "c");
SELECT t.CommentID, i.itemname, t.CustomerID, t.Message
FROM items i,
XMLTABLE('$c/Comments/Comment' PASSING i.comments AS "c"
COLUMNS
CommentID INTEGER PATH 'CommentID',
CustomerID INTEGER PATH 'CustomerID',
Message VARCHAR(100) PATH 'Message') AS t;
結果集為純關系表格,列名自動大寫。
CREATE VIEW commentView(itemID, itemname, commentID, message, mustRespond) AS
SELECT i.id, i.itemname, t.CommentID, t.Message, t.ResponseRequested
FROM items i,
XMLTABLE('$c/Comments/Comment' PASSING i.comments AS "c"
COLUMNS
CommentID INTEGER PATH 'CommentID',
Message VARCHAR(100) PATH 'Message',
ResponseRequested VARCHAR(100) PATH 'ResponseRequested') AS t;
性能警示:視圖上的 XML 列無索引支持,查詢時需結合關系列謂詞(如 i.id)先過濾,再應用 XML 謂詞,否則全表掃描 XML 文檔。
SELECT c.name, c.status
FROM items i, clients c
WHERE XMLEXISTS('$cm/Comments/Comment[CustomerID=$cid]'
PASSING i.comments AS "cm", c.id AS "cid");
SELECT name,
XMLQUERY('for $e in $c/Client/email[1]/text() return <p>{$e}</p>'
PASSING contactinfo AS "c")
FROM clients WHERE status = 'Gold';
SELECT XMLELEMENT(NAME "item",
XMLELEMENT(NAME "id", id),
XMLELEMENT(NAME "brand", brandname),
XMLELEMENT(NAME "sku", sku))
FROM items WHERE srp < 100;
輸出:<item><id>4272</id><brand>Classy</brand><sku>981140</sku></item>
SELECT XMLELEMENT(NAME "customerList",
XMLAGG(
XMLELEMENT(NAME "customer",
XMLFOREST(name AS "fullName", status AS "status")
)
ORDER BY name
)
)
FROM clients GROUP BY status;
生成三個 <customerList> 元素,分別包含 Gold/Silver/Standard 客戶。
UPDATE clients SET contactinfo = XMLPARSE(DOCUMENT
'<Client>
<Address><street>5401 Julio Ave.</street><city>San Jose</city><state>CA</state><zip>95116</zip></Address>
<phone><work>4084633000</work><home>4081111111</home><cell>4082222222</cell></phone>
<fax>4087776666</fax>
<email>newemail@someplace.com</email>
</Client>')
WHERE id = 3227;
關鍵:僅更新 email 而省略 Address/phone 會導致舊數據丟失,且後續 XPath 查詢失效(層次結構變化)。
視圖列(來自 XMLTable)不可更新。
DELETE FROM clients
WHERE XMLEXISTS('$c/Client/Address[zip="95116"]'
PASSING contactinfo AS "c");
生產環境必須創建 XML 索引加速路徑表達式,本文為入門教程不展開,請參考《DB2 pureXML 索引技術》文檔。
SQL/XML 讓關系開發者以熟悉語法無縫處理 XML,結合 XMLTable、XMLELEMENT、XMLAGG 等函數可實現雙向轉換。後續文章將介紹 XQuery 原生查詢與 Java 應用開發。