Oracle XQuery查詢、構建和轉換XML(1)(轉)

Rounders發表於2007-08-09

Oracle XQuery查詢、構建和轉換XML(1)

[@more@]

在 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 示例生成相同的輸出。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/9417382/viewspace-937336/,如需轉載,請註明出處,否則將追究法律責任。

相關文章