在 Oracle 數據庫 10g 第 2 版中,Oracle 引入了一個與該數據庫集成的全功能自帶 XQuery 引擎,該引擎可用於完成與開發支持 XML 的應用程序相關的各種任務。XQuery 是一種用於處理 XML 數據模型的查詢語言,它實際上可操作任何類型的可用 XML 表達的數據。盡管 Oracle XQuery 實施使您可以使用數據庫數據和外部數據源,但在處理數據庫中存儲的結構化數據方面,Oracle XML DB 通常可以顯著提高性能。
本文提供的示例不僅演示了在什麼場合下以及如何使用 XQuery 查詢、構建和轉換 XML,而且還演示了如何監控和分析 XQuery 表達式的性能執行,從而找到更高效的方法來處理同一工作負載。
基於關系數據構建 XML
在需要的情況下(例如,向 Web 服務發送結果),您可能要基於關系數據構建 XML。要在 Oracle 數據庫 10g 第 2 版之前的版本中完成此任務,通常需要使用 SQL/XML 生成函數,如 XMLElement、XMLForest 和 XMLAgg()。在 Oracle 數據庫 10 g 第 2 版中,XQuery 將比這些函數更為高效。具體而言,在 XQuery 表達式內部使用 ora:vIEw XQuery 函數,您可以查詢現有的關系表或視圖以及即時構建 XML,從而不必通過關系數據顯式創建 XML 視圖。列表 1 中的 PL/SQL 代碼演示了如何使用 ora:vIEw 基於示例數據庫模式 HR 的默認員工關系表中存儲的數據構建 XML 文檔。
列表 1:使用 ora:vIEw 基於關系數據創建 XML
BEGIN
IF(DBMS_XDB.CREATEFOLDER('/public/employees')) THEN
DBMS_OUTPUT.PUT_LINE('Folder is created');
ELSE
DBMS_OUTPUT.PUT_LINE('Cannot create folder');
END IF;
COMMIT;
END;
/
DECLARE
XMLdoc XMLType;
BEGIN
SELECT XMLQuery(
'for $j in 1
return (
{
for $i in ora:vIEw("HR", "employees")/ROW
where $i/EMPLOYEE_ID <= 102
return (
{xs:string($i/EMPLOYEE_ID)}
{xs:string($i/LAST_NAME)}
{xs:integer($i/SALARY)}
)} )'
RETURNING CONTENT) INTO XMLdoc FROM DUAL;
IF(DBMS_XDB.CREATERESOURCE('/public/employees/employees.xml', XMLdoc)) THEN
DBMS_OUTPUT.PUT_LINE('Resource is created');
ELSE
DBMS_OUTPUT.PUT_LINE('Cannot create resource');
END IF;
COMMIT;
END;
/
在列表 1 中的第一個 PL/SQL 過程中,您只是在 XML 信息庫中創建了一個新文件夾。在該信息庫文件夾中,您隨後將存儲此處顯示的第二個 PL/SQL 過程中創建的 XML 文檔。第二個 PL/SQL 過程首先發出 SELECT 語句,該語句使用 XMLQuery SQL 函數基於關系數據構建 XML。對於 XQuery 表達式(XMLQuery 在此處將其用作參數)而言,請注意嵌套的 FLWOR 表達式中使用的 ora:view XQuery 函數。在該示例中,ora:vIEw 獲取兩個輸入參數,即“HR”和“employees”,它們指示該函數查詢屬於 HR 數據庫模式的員工表。因此,ora:vIEw 將返回一個表示 HR.employees 表行的員工 XML 文檔序列。但為了節省結果文檔中的空間,只將前三個員工記錄傳遞給結果序列。這是通過在 FLWOR 表達式的 where 子句中指定 $i/EMPLOYEE_ID <= 102 而實現的。請注意 FLWOR 表達式的 return 子句中使用的 xs:string() 和 xs:integer() XQuery 類型表達式。實際上,此處使用的這兩個 XQuery 表達式不僅將 XML 節點值轉換為相應的類型,而且還將提取這些節點值。隨後,生成的員工 XML 文檔作為 employees.xml 保存到之前在列表 1 中另一個 PL/SQL 過程中創建的 /public/employees XML 信息庫文件夾。要確保此操作已完成,可執行以下查詢:
SELECT XMLQuery('for $i in fn:doc("/public/employees/employees.XML")
return;
$i'
RETURNING CONTENT) AS RESULT FROM DUAL;
該查詢應生成以下輸出:
100 King 24000 101 Kochhar 17000 102 De Haan 17000
在以上 XQuery 中,fn:doc XQuery 函數用於訪問 Oracle XML DB 信息庫中存儲的單個 XML 文檔。但如果要處理一些具有相同或相似結構的 XML 文檔(存儲在同一 XML 信息庫文件夾中),應該怎麼做?這種情況下,另一個用於處理 XML 信息庫資源的 XQuery 函數(即 fn:collection)可能會派上用場。本文稍後將介紹幾個有關如何使用 fn:collection XQuery 函數的示例。
查詢 XMLType 數據
XQuery 使您可以操作基於 XML 模式以及非基於模式的數據。以下示例演示了如何使用 XMLTable 函數從 OE 演示數據庫模式中查詢基於 PurchaSEOrder XML 模式的 XMLType 表。
SELECT ttab.COLUMN_VALUE AS OrderTotal FROM purchaSEOrder,
XMLTable(
'for $i in /PurchaSEOrder
where $i/User = "EABEL"
return;'
{$i/Reference}
{fn:sum(for $j in $i/LineItems/LineItem/Part
return ($j/@Quantity*$j/@UnitPrice))}
PASSING OBJECT_VALUE
) ttab;
在以上示例中,您在 XMLTable 函數的 PASSING 子句中使用 OBJECT_VALUE 虛擬列將 purchaSEOrder 表作為上下文項傳遞給此處使用的 XQuery 表達式。XQuery 表達式計算用戶 EABEL 請求的每個購買訂單的總計,並為處理的每個訂單生成一個 OrderTotal XML 元素。要訪問生成的 XML,請使用 SELECT 列表中的 COLUMN_VALUE 虛擬列。最終的輸出應如下所示:
ORDERTOTAL
-------------------------------------------------------------EABEL-20021009123338324PDT 1328.05 EABEL-20021009123335791PDT 2067.15 EABEL-20021009123336251PDT 289.6 EABEL-20021009123336382PDT 928.92
要獲得相同的最終結果,可以改用 XMLQuery 函數。但如果將上一個示例中使用的 XQuery 表達式參數傳遞給 XMLQuery(如下所示):
SELECT XMLQuery('for $i in /PurchaSEOrder
where $i/User eq "EABEL"
return'
{$i/Reference}
{fn:sum(for $j in $i/LineItems/LineItem/Part
return ($j/@Quantity*$j/@UnitPrice))}
PASSING OBJECT_VALUE
RETURNING CONTENT)
FROM purchaSEOrder;則 XQuery 表達式返回的空序列將與 purchaseorder 表聯接,從而包含在查詢總結果集中。實際上,這意味著輸出將不僅包含為用戶 EABEL 請求的訂單生成的 OrderTotal 元素,而且還包含為 purchaseorder 表中存儲的所有其他訂單生成的空行(默認情況下,purchaSEOrder 表包含 132 行)。從結果集中排除空行的方法之一是在 SELECT 語句的 WHERE 子句中使用 existsNode SQL 函數,而不是在 XQuery 表達式中使用 WHERE 子句,如下所示:
SELECT XMLQuery('for $i in /PurchaSEOrder
return'
{$i/Reference}
{fn:sum(for $j in $i/LineItems/LineItem/Part
return ($j/@Quantity*$j/@UnitPrice))}
PASSING OBJECT_VALUE
RETURNING CONTENT) AS ordertotal
FROM purchaSEOrder
WHERE existsNode(OBJECT_VALUE, '/PurchaSEOrder[User = "EABEL"]') = 1;以上查詢與本部分開頭的 XMLTable 示例生成相同的輸出。