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

來源:互聯網
上載者:User

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

在 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 樣本產生相同的輸出。

 

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

 

查詢 Oracle XML DB 資訊庫中的 XML 資料

為訪問 Oracle XML DB 資訊庫中儲存的 XML 資料,Oracle XQuery 引入了 fn:doc 和 fn:collection XQuery 函數。使用 fn:doc,您可以查詢 XML 資訊庫中儲存的單個 XML 文檔,而 fn:collection 使您可以訪問同一資訊庫檔案夾中儲存的多個 XML 文檔。

正如本文之前(參閱使用關係資料構建 XML部分)介紹的樣本所示範,使用 fn:doc 非常簡單直接。它擷取表示資訊庫檔案資源 (URI) 的字串並返回該 URI 指向的文檔。要瞭解 fn:collection XQuery 函數的作用,同一檔案夾中至少應有兩個資訊庫檔案。如果已經運行了列表 1 中的代碼,則已經建立了 /public/employees 資訊庫檔案夾並在其中儲存了 employees.xml 檔案。因此,您將需要在該檔案夾中至少再建立一個 XML 檔案,然後才能試用 fn:collection。列表 2 中的 PL/SQL 代碼基於 SCOTT/TIGER 示範資料庫模式的 dept 和 emp 表格儲存體的關係資料構建 XML,然後將產生的 XML 文檔作為 acc_dept.xml 儲存到 /public/employees 資訊庫檔案夾。要運行列表 2 中的 PL/SQL 過程,請確保以 SCOTT/TIGER 的身份登入。

列表 2:基於關係資料構建 XML 並將其儲存到 XML 資訊庫

DECLARE
XMLdoc XMLType;
BEGIN
SELECT XMLQuery(
'for $j in ora:view("SCOTT", "dept")/ROW
where $j/DEPTNO = 10
return (
{$j/DEPTNO,
$j/DNAME}
 {
for $i in ora:view("SCOTT", "emp")/ROW
where $i/DEPTNO = $j/DEPTNO
return (
{$i/EMPNO,
$i/ENAME,
$i/SAL}
)}
)'
RETURNING CONTENT) INTO XMLdoc FROM DUAL;
IF(DBMS_XDB.CREATERESOURCE('/public/employees/acc_dept.xml', XMLdoc)) THEN
DBMS_OUTPUT.PUT_LINE('Resource is created');
ELSE
DBMS_OUTPUT.PUT_LINE('Cannot create resource');
END IF;
COMMIT;
END;
/

此時,/public/employees 資訊庫檔案夾應包含兩個檔案:acc_dept.xml(由列表 2 中的 PL/SQL 代碼產生)和 employees.xml 檔案(由列表 1 中的代碼產生)。由於這些 XML 文檔儲存在同一資訊庫檔案夾中,因此可以使用 fn:collection 函數訪問兩個 XML 文檔中儲存的員工資訊。然而,儘管這些 XML 文檔均包含員工 XML 元素(這些元素實際上具有相同結構),但 XML 文檔本身的結構迥然不同。在 employees.xml 中,文檔根項目為 EMPLOYEES,而 acc_dept.xml 將 DEPARTMENT 用作根項目。要解決此問題,可以通過 XQuery 使用 XPath // 構造,從而導航到 XML 文檔中的某個節點,而不必指定該節點的確切路徑。以下樣本示範了如何在 XQuery 運算式中使用 XPath // 構造:

SELECT XMLQuery(
'for $i in fn:collection("/public/employees")//EMPLOYEE
where $i/SAL >= 5000
order by $i/ENAME
return;
$i'
RETURNING CONTENT) FROM DUAL;

該構造應產生以下輸出:

102
De Haan
17000
7839
KING
5000
100
King
24000
101
Kochhar
17000

您可以看到,以上輸出包含從 employees.xml 和 acc_dept.xml 中擷取的員工 XML 元素,這些元素表示薪酬大於或等於 5,000 美元的員工。

XML 分解為關係資料

如果應用程式處理關係資料而非 XML,而您需要訪問的資料以 XML 格式儲存,則將 XML 分解為關係資料可能會非常有用。繼續進行上一部分的樣本,您可以使用 SQL 函數 XMLTable 將員工 XML 元素分解為虛擬表的單個列,如下所示:

SELECT emps.empno,emps.ename, emps.sal FROM
XMLTable(
'for $i in fn:collection("/public/employees")//EMPLOYEE
where $i/SAL >= 5000
return;
$i'
COLUMNS empno NUMBER PATH '/EMPLOYEE/EMPNO',
ename VARCHAR2(30) PATH '/EMPLOYEE/ENAME',
sal NUMBER PATH '/EMPLOYEE/SAL') emps;

該查詢將產生以下輸出:

EMPNO ENAME SAL
----- -------------- ----------
7839 KING 5000
100 King 24000
101 Kochhar 17000
102 De Haan 17000

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.