程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 數據庫知識 >> DB2數據庫 >> DB2教程 >> 使用 XQuery 查詢 DB2 XML 數據

使用 XQuery 查詢 DB2 XML 數據

編輯:DB2教程

您可能已經聽說過 DB2 Viper 的新架構,這種架構支持表格和分層數據結構。實際上,前一篇文章已經總結了 DB2 中新的 XML 特性,描述了如何創建數據庫對象和用 XML 數據填充這些數據庫對象,並解釋了如何使用 SQL 和 SQL/XML 操作 XML 數據。本文繼續探索 DB2 XML 功能,這一次將焦點放在 DB2 對 XQuery 的新的支持上。

DB2 將 XQuery 當作最好的語言,允許用戶直接編寫 XQuery 表達式,而不是將 XQueries 封裝或嵌入到 SQL 語句中。而且,DB2 的查詢引擎是在本地處理 XQueries,這意味著它在解析、計算和優化 XQuerIEs 之前不必在幕後將它們翻譯成 SQL。當然,如果您選擇編寫同時包括 XQuery 和 SQL 表達式的 “雙語(bilingual)” 查詢,那麼 DB2 同樣會處理和優化這些查詢。

與 “用 SQL 查詢 DB2 XML 數據” 中對 SQL/XML 的描述一樣,本文也提到了一些常見的查詢任務,並告訴您如何使用 XQuery 來完成這些目標。不過首先我們還是簡要地考慮一下 XQuery 與 SQL 的不同之處。

關於 XQuery

XQuery 在很多關鍵方面都與 SQL 有所不同,這很大程度上是因為這兩種語言是針對兩種具有不同特征的數據模型而設計的。XML 文檔包含層次結構,並且有其固有的順序。而基於 SQL 的數據庫管理系統所支持的表格數據結構是平面的(flat),並且是基於集合的;因此,行之間不存在順序。

這兩種數據模型的不同導致它們各自的查詢語言有很多基本的不同。例如,XQuery 支持路徑表達式,以允許程序員在 XML 的層次結構中導航,而純 SQL(沒有 XML 擴展)則不支持。XQuery 支持有類型的和無類型的數據,而 SQL 數據總是以指定類型定義的。XQuery 沒有 null 值,因為 XML 文檔會忽略缺失的或未知的數據。當然,SQL 使用 null 來表示缺失的或未知的數據值。XQuery 返回一系列的 XML 數據,而 SQL 則返回各種 SQL 數據類型的結果集。

-

這只是 XQuery 和 SQL 之間的基本不同點中的一部分。提供一份詳盡的列表超出了本文的范圍,不過即將發表的 IBM Systems Journal 將更詳細地討論這些語言的不同。現在我們就探索一下 XQuery 語言的一些基本方面,並看看如何使用它來查詢 DB2 Viper 中的 XML 數據。

樣本數據庫

本文中的查詢訪問在 “DB2 Viper 快速入門”(developerWorks,2006 年 4 月)中創建的樣本表。清單 1 給出了樣本數據庫中 “items” 和 “clIEnts” 表的定義:


清單 1. 表定義
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 
) 

圖 1 中顯示了 “items.comments” 列中包含的樣本 XML 數據,而 圖 2 中則顯示了 “clIEnts.contactinfo” 列中包含的樣本 XML 數據。隨後的例子查詢將引用這兩個 XML 文檔中的一個或兩個中的特定元素。


圖 1. 存儲在 “items” 表的 “comments” 列中的樣本 XML 文檔
使用 XQuery 查詢 DB2 XML 數據

圖片看不清楚?請點擊這裡查看原圖(大圖)。



圖 2. 存儲在 “clIEnts” 表的 “contactinfo” 列中的樣本 XML 文檔
使用 XQuery 查詢 DB2 XML 數據

查詢環境

本文中的所有查詢都是通過交互方式發出的。這可以通過 DB2 命令行處理器或 DB2 Control Center 的 DB2 Command Editor 來完成。本文中的屏幕圖像和說明主要使用後一種方式。(DB2 Viper 還附帶了一個基於 Eclipse 的 Developer Workbench,它可以幫助程序員以圖形化的方式構造查詢。本文不討論應用程序開發問題和 Developer Workbench。)

要使用 DB2 Command Editor,啟動 Control Center,並選擇 Tools -> Command Editor。這時將出現如 圖 3 所示的窗口。在上面的面板中輸入查詢,單擊左上角的綠色箭頭運行該查詢,然後可以在下面的面板中或者在 “Query Results” 選項卡中查看輸出。


圖 3. DB2 Command Editor,可以從 DB2 Control Center 中啟動
使用 XQuery 查詢 DB2 XML 數據

圖片看不清楚?請點擊這裡查看原圖(大圖)。

XQuery 例子

與在 “用 SQL 查詢 DB2 XML 數據” 中一樣,本文將逐步講解一些常見的業務場景,並展示如何使用 XQuery 來滿足對 XML 數據的請求。本文還探索了需要將 SQL 嵌入在 XQuery 中的更復雜的情景。

XQuery 提供了一些不同類型的表達式,這些表達式可以隨意組合。每個表達式返回一系列的值,這些值又可以作為其他表達式的輸入。最外面的表達式的結果就是查詢的結果。

本文主要討論兩種重要的 XQuery 表達式:“FLWOR” 表達式和路徑表達式。FLWOR 表達式非常像 SQL 中的 SELECT-FROM-WHERE 表達式 —— 它用於對由多項組成的一個列表進行迭代,並且可以選擇返回通過在每一項上進行計算得到的值。而路徑表達式則可以在分層的 XML 元素之間進行導航,並返回在路徑末端找到的元素。

-

與 SQL 中的 SELECT-FROM-WHERE 表達式類似,XQuery FLWOR 表達式可以包含數個以某個關鍵詞開頭的子句。在 FLWOR 表達式中,有以下用於作為子句開頭的關鍵字:

for:對輸入序列進行迭代,依次將一個變量綁定到每個輸入項

let:聲明一個變量並為之賦值,可能是一個包含多項的列表

where:指定過濾查詢結果的標准

order by:指定結果的排序順序

return:定義所返回的結果

XQuery 中的路徑表達式由一系列的 “步(step)” 組成,之間以斜槓隔開。在最簡單的形式中,每一步在 XML 層次中向下導航,以發現由前一步返回的元素的孩子。路徑表達式中的每一步還可以包含一個謂詞,用於過濾該步返回的元素,只保留滿足某種條件的元素。例如,假設變量 $clients 被綁定到包含 <ClIEnt> 元素的 XML 文檔的一個列表,則 4 步路徑表達式 $clients/ClIEnt/Address[state = "CA"]/zip 將返回居住在加利福尼亞的客戶的郵政編碼。

在很多情況下,可以任意使用 FLWOR 表達式或路徑表達式編寫查詢。

使用 DB2 XQuery 作為頂層查詢語言

要在 DB2 Viper 中直接執行 XQuery(而不是將它嵌入在 SQL 語句中),必須以關鍵字 xquery 作為查詢的開頭。這個關鍵字將指示 DB2 調用它的 XQuery 解析器來處理請求。注意,只有在使用 XQuery 作為最外層(頂層)語言的時候才需要這麼做。如果是將 XQuery 表達式嵌入在 SQL 中,則不需要在語句之前加上 xquery 關鍵字。但是,本文使用 XQuery 作為基本語言,因此所有查詢之前都加上 xquery。

當 XQuery 被作為頂層語言時,它需要一個輸入數據的源。XQuery 獲得輸入數據的一種方式是調用一個名為 db2-fn:xmlcolumn 的函數,調用時帶一個參數,表明 DB2 表中 XML 列所在的表名和該列的列名。db2-fn:xmlcolumn 函數返回存儲在給定列中的一系列的 XML 文檔。例如,下面的查詢返回一系列包含客戶聯系方式信息的 XML 文檔:


清單 2. 返回客戶聯系方式數據的簡單 XQuery
xquery db2-fn:XMLcolumn('CLIENTS.CONTACTINFO') 

您可能還記得,在我們的數據庫模式中(參見 “樣本數據庫” 小節),我們將那些 XML 文檔存儲在 “clIEnts” 表的 “contactinfo” 列中。注意,這裡的列名和表名是大寫的。這是因為表名和列名在被寫入到 DB2 的內部編目之前通常要換成大寫形式。由於 XQuery 是大小寫敏感的,因此小寫的表名和列名不能與 DB2 編目中的大寫名稱相匹配。

檢索特定的 XML 元素

首先我們來看一個基本的任務。假設您要檢索所有提供了有關傳真信息的客戶的傳真號。清單 3 給出了編寫該查詢的一種方式:


清單 3. 檢索客戶傳真數據的 FLWOR 表達式
xquery 
for $y in db2-fn:XMLcolumn('CLIENTS.CONTACTINFO')/ClIEnt/fax 
return $y 

第一行指示 DB2 調用它的 XQuery 解析器。接下來的一行指示 DB2 對包含在 CLIENTS.CONTACTINFO 列中的 ClIEnt 元素的 fax 子元素進行迭代。每個 fax 元素被依次與變量 $y 綁定。第三行指出在每次迭代中返回 $y 的值。結果為一系列的 XML 元素,如 清單 4 所示:


清單 4. 上述查詢的示例輸出
<fax>4081112222</fax> 
<fax>5559998888</fax>   

隨便提一下,這裡的輸出還將包含與本文關系不大的一些信息:XML 版本和編碼數據,例如 <?xml version="1.0" encoding="Windows-1252" ?>,以及 XML 名稱空間信息,例如 <fax xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">。為了使輸出更簡單,本文省略了這些信息。然而,對於很多 XML 應用程序來說這些信息可能很重要。如果使用 DB2 命令行處理器來運行查詢,那麼可以使用 -d 選項來省略 XML 聲明信息,還可以使用 -i 選項以一種美觀的方式打印結果。

清單 3 中顯示的查詢也可以用一種更簡單的三步路徑表達式來表達,如 清單 5 所示:


清單 5. 檢索客戶傳真數據的路徑表達式
xquery 
db2-fn:XMLcolumn('CLIENTS.CONTACTINFO')/ClIEnt/fax 

路徑表達式的第一步調用 db2-fn:xmlcolumn 函數從 CLIENTS 表的 CONTACTINFO 列獲得一個 XML 文檔的列表。第二步返回這些文檔中的所有 Client 元素,第三步則返回嵌入在這些 ClIEnt 元素中的 fax 元素。

如果您無興趣通過查詢獲得 XML 片段,而只想要符合條件的 XML 元素值的文本表示,那麼可以在 return 子句中調用 text() 函數,如 清單 6 所示:


清單 6. 兩個用於檢索客戶傳真數據的文本表示的查詢
xquery 
for $y in db2-fn:XMLcolumn('CLIENTS.CONTACTINFO')/ClIEnt/fax 
return $y/text() 
(or) 
xquery 
db2-fn:XMLcolumn('CLIENTS.CONTACTINFO')/ClIEnt/fax/text() 

上述查詢的輸出如 清單 7 所示:


清單 7. 上述查詢的示例輸出
4081112222 
5559998888 

這些示例查詢的結果都相當簡單,因為 fax 元素是基於基本數據類型的。當然,元素也可能基於復雜的數據類型 —— 即包含子元素(或嵌套層次結構)。例如客戶聯系方式信息中的 Address 元素就是這樣。根據 “DB2 Viper 快速入門”(developerWorks,2006 年 4 月)中定義的模式,該元素包含街道地址、門牌號、所在城市、州、國家以及郵政編碼。考慮 清單 8 中的 XQuery 將返回什麼結果:


清單 8. 檢索復雜 XML 類型的 FLWOR 表達式
xquery 
for $y in db2-fn:XMLcolumn('CLIENTS.CONTACTINFO')/ClIEnt/Address 
return $y 

如果您猜到返回的結果是包含 Address 元素及其所有子元素的一系列的 XML 片段,那就對了。清單 9 給出了一個例子:


清單 9. 上述查詢的示例輸出
<Address> 
 <street>5401 Julio Ave.</street> 
 <city>San Jose</city> 
 <state>CA</state> 
 <zip>95116</zip> 
</Address> 
. . . 
<Address> 
 <street>1204 Meridian Ave.</street> 
 <apt>4A</apt> 
 <city>San Jose</city> 
 <state>CA</state> 
 <zip>95124</zip> 
</Address>  

注意: 為了易於閱讀,這裡的示例輸出作了格式上的調整。DB2 Command Editor 是在一行中顯示每個客戶地址記錄的。

過濾 XML 元素值

您可以修改上述 XQuery 例子,縮小選擇范圍。例如,我們來看看如何返回居住在郵政編碼為 95116 的地區的所有客戶的郵遞地址。

與您想像的一樣,通過 XQuery where 子句可以根據 XML 文檔中 zip 元素的值來過濾結果。清單 10 說明了如何在 清單 8 中的 FLWOR 表達式中添加一個 where 子句,以獲得您感興趣的地址信息:


清單 10. 帶有 “where” 子句的 FLWOR 表達式
xquery 
for $y in db2-fn:XMLcolumn('CLIENTS.CONTACTINFO')/ClIEnt/Address 
where $y/zip="95116" 
return $y 

這裡添加的 where 子句很容易理解。for 子句依次將變量 $y 綁定到每個地址。where 子句包含一個小型的路徑表達式,該表達式從每個地址向下定位到其內嵌的 zip 元素。只有當這個 zip 元素等於 95116 時,where 子句才為 true(相應的地址被保留)。

通過在路徑表達式中添加一個謂詞也可以得到相同的結果,如 清單 11 所示:


清單 11. 帶附加過濾謂詞的路徑表達式
xquery 
db2-fn:XMLcolumn('CLIENTS.CONTACTINFO')/ClIEnt/Address[zip="95116"] 

當然,您可以根據郵政編碼的值進行過濾,返回與街道地址無關的元素。而且,還可以在單個查詢中根據多個 XML 元素值進行過濾。下面的查詢返回居住在紐約市具有特定郵政編碼(10011)的地區或聖何塞(San Jose)任何地方的客戶的電子郵件信息。


清單 12. 在 FLWOR 表達式中根據多個 XML 元素值過濾
xquery 
for $y in db2-fn:XMLcolumn('CLIENTS.CONTACTINFO')/ClIEnt 
where $y/Address/zip="10011" or $y/Address/city="San Jose" 
return $y/email 

注意,我們更改了 for 子句,從而將變量 $y 綁定到 Client 元素,而不是綁定到 Address 元素。這樣一來便可以根據 ClIEnt 元素的一部分子樹(Address)過濾該元素,而返回另一部分子樹(email)。where 子句和 return 子句中的路徑表達式必須相對被綁定到變量(這裡是 $y)的元素來編寫。

通過路徑表達式可以更簡單地表達相同的查詢:


清單 13. 使用路徑表達式根據多個 XML 元素值進行過濾
xquery 
db2-fn:XMLcolumn('CLIENTS.CONTACTINFO')/ClIEnt[Address/zip="10011"  
or Address/city="San Jose"]/email; 

仔細觀察該查詢的兩種不同形式,其中比較隱蔽的一點是,與 SQL 程序員的預期相比,返回的結果在兩個方面存在不同之處:

返回的結果中不包含那些符合條件但是沒有提供電子郵件地址的客戶的 XML 數據。換句話說,如果有 1000 個客戶居住在聖河塞或郵政編碼為 10011 的地區,其中有 700 個客戶提供了電子郵件地址,那麼返回的將是這 700 個電子郵件地址。這是由於前面提到的 XQuery 與 SQL 之間存在的基本差異 —— XQuery 不使用 null。

您無法知道哪些電子郵件地址來自同一個 XML 文檔。換句話說,如果有 700 個居住在聖河塞或郵政編碼為 10011 的地區的客戶,並且每個客戶提供了兩個電子郵件地址,那麼返回的結果是 1400 個 email 元素組成的列表。您得到的不是 一個包含 700 個記錄、每個記錄由兩個電子郵件地址組成的序列。

這兩點在某些情況下是可以的,在另外一些情況下又可能不可取。例如,如果需要通過電子郵件將一個通知發送給每個符合條件的有記錄的帳戶,那麼很容易在應用程序中對 XML 格式的客戶電子郵件地址列表進行迭代。然而,如果對每個客戶只發送一次通知,包括那些沒有提供街道地址的客戶,那麼上述 XQuery 就不能滿足要求了。

有多種方法來修改這個查詢,使返回的結果以某種方式表示缺失的信息,並且在有多個電子郵件地址來自相同客戶記錄(即相同的 XML 文檔)的情況下作出說明。讓我們簡要地探索一下其中一種方法。不過,如果只是要檢索一個列表,其中對於每個符合條件的客戶包含一個電子郵件地址,那麼只需對之前查詢中的 return 子句略作修改:


清單 14. 只檢索每個客戶的第一個 email 元素
xquery 
for $y in db2-fn:XMLcolumn('CLIENTS.CONTACTINFO')/ClIEnt 
where $y/Address/zip="10011" or $y/Address/city="San Jose" 
return $y/email[1] 

該查詢導致 DB2 返回它在每個符合條件的 XML 文檔(客戶聯系方式記錄)中找到的第一個電子郵件元素。如果對於一個符合條件的客戶,DB2 沒有找到電子郵件地址,那麼對於這個客戶就不返回任何信息。

轉換 XML 輸出

XQuery 的一個強大的方面是可以將 XML 輸出從一種格式轉換成另一種格式。例如,可以使用 XQuery 檢索所有或部分存儲的 XML 文檔,並將輸出轉換成 HTML,以便在 Web 浏覽器中顯示。下面 清單 15 中的查詢檢索客戶的地址,按照郵政編碼對結果排序,並將輸出轉換成 XML 元素,作為一個無序的 HTML 列表中的一部分: 清單 15. 查詢 DB2 XML 數據並以 Html 格式返回結果
xquery 
<ul> { 
for $y in db2-fn:XMLcolumn('CLIENTS.CONTACTINFO')/ClIEnt/Address 
order by $y/zip 
return <li>{$y}</li> 
} </ul> 

該查詢首先以 xquery 關鍵字開頭,告訴 DB2 解析器 XQuery 是頂層語言。第二行將表示無序列表的 Html 標記(<ul>)包括在結果中。它還包含本查詢中使用的一對花括號中的左括號。花括號指示 DB2 計算和處理其中的表達式,而不是將其當作文字字符串。

第三行對客戶地址進行迭代,依次將變量 $y 綁定到每個 address 元素。第四行包括一個新的 order by 子句,指出結果必須按照客戶郵政編碼(綁定到 $y 的每個 address 元素的 zip 子元素)升序排列。return 子句表明 Address 元素在返回之前要用 HTML 列表 item 標記括起來。最後一行結束查詢,並結束 Html 無序列表標記。

輸出將類似 清單 16 所示:


清單 16. 上述查詢的示例 Html 輸出
<ul> 
 <li> 
   <Address> 
     <street>9407 Los Gatos Blvd.</street> 
     <city>Los Gatos</city> 
     <state>CA</state> 
     <zip>95032</zip> 
   </Address> 
 </li> 
 <li> 
   <Address> 
     <street>4209 El Camino Real</street> 
     <city>Mountain VIEw</city> 
     <state>CA</state> 
    <zip>95033</zip> 
   </Address> 
 </li> 
. . . 
</ul> 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved