Oracle XQuery查詢、構建與轉換XML(1)
發表時間:2024-02-22 來源:明輝站整理相關軟件相關文章人氣:
[摘要]在 Oracle 數據庫 10g 第 2 版中,Oracle 引入了一個與該數據庫集成的全功能自帶 XQuery 引擎,該引擎可用于完成與開發支持 XML 的應用程序相關的各種任務。XQuery 是一種用于處理 XML 數據模型的查詢語言,它實際上可操作任何類型的可用 XML 表達的數據。盡管 O...
在 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 示例生成相同的輸出。