共用方式為


XML 最佳作法

SQL Server 2005 針對 XML 資料處理提供了廣泛的支援。XML 值可用原生方式儲存在 xml 資料類型資料行中,依照 XML 結構描述的集合來設定類型,或維持不具類型。您可以對 XML 資料行建立索引。此外,還可以使用 XQuery 和 XML DML 支援細項資料操作。XML DML 是用於資料修改的一項延伸。

SQL Server 2000 及 SQLXML Web 版本提供強大的 XML 資料管理功能。這些功能的主要目的是要在關聯式資料與 XML 資料之間進行對應。可使用註解式 XSD (AXSD) 來定義關聯式資料的 XML 檢視,提供以 XML 為中心的方式,支援 XML 資料上的大量載入資料、查詢及更新功能。Transact-SQL 延伸模組則提供以 SQL 為中心的方式,使用 FOR XML 來將關聯式查詢結果對應到 XML,以及使用 OPENXML 從 XML 來產生關聯式檢視。SQL Server 2005 中已提供這些支援。除了新增的原生 XML 支援以外,SQL Server 2005 還提供功能強大的平台,可針對半結構及無結構的資料管理來開發豐富的應用程式。

本主題提供在 SQL Server 2005 中將 XML 資料模型化及使用的指導方針。其分為下列各節:

  • 資料模型化
    將 XML 資料儲存在 SQL Server 2005 中的方法有很多種,您可以使用原生的 xml 資料類型,以及細分在資料表中的 XML。本主題提供適當決策的指導方針,以便將您的 XML 資料模型化。同時也涵蓋編製 XML 資料索引、升級屬性,以及設定 XML 執行個體的類型。
  • 使用
    本節討論與使用相關的主題,例如將 XML 資料載入伺服器,以及查詢編譯中的類型推斷。本節也會說明及辨別關係緊密的功能,並建議這些功能的適當用法。這些都將一一舉例說明。

資料模型化

本節概述為什麼您要在 SQL Server 2005 中使用 XML 的理由。本節亦提供指導方針,教您在原生 XML 儲存與 XML 檢視技術之間做選擇,並提供資料模型化的建議。

關聯式或 XML 資料模型

如果您的資料使用已知的結構描述來高度結構化,則關聯式模型對資料儲存來說應該是最好的。SQL Server 提供了必要的功能及您可能會用到的工具。另一方面,如果結構是半結構化或是無結構,或是情況不明,您就必須考慮將這類資料模型化。

如果您想要一個與平台沒有關聯的模型,以使用結構化及語意化的標記來確保資料的可攜性,則 XML 會是個很好的選擇。此外,若符合下列的部份屬性,XML 也會是很適當的選項:

  • 您的資料很少,或是您不知道資料的結構,或是資料的結構未來可能會有重大變更。
  • 您的資料代表內含項目階層,而不是實體之間的參考,而且可能是遞迴式的。
  • 順序是資料固有的。
  • 您想要依據資料結構來查詢資料,或是更新部份資料。

若沒有符合上述任一情況,則您應使用關聯式資料模型。例如,若資料為 XML 格式,但您的應用程式只是使用資料庫來儲存及擷取資料,您就只需要 [n]varchar(max) 資料行。將資料儲存在 XML 資料行中還有其他好處,包括:可由引擎來判斷資料結構是否良好,以及資料是否有效;可支援細項查詢及更新 XML 資料。

將 XML 資料儲存在 SQL Server 2005 中的理由

以下是一些在 SQL Server 2005 中使用原生 XML 功能,而不在檔案系統中管理 XML 資料的理由:

  • 您想要以有效率及交易性的方式來共用、查詢及修改 XML 資料。細項資料存取權對您的應用程式很重要。例如,您想要在 XML 文件中擷取某幾段,或是您想要插入新的區段,而不要置換整份文件。
  • 您有關聯式資料及 XML 資料,而且您希望應用程式中的關聯式及 XML 資料之間具有互通性。
  • 您需要語言支援,以進行跨網域應用程式的查詢及資料修改。
  • 您希望伺服器能保證資料的結構良好,並依據 XML 結構描述來選擇驗證您的資料。
  • 您想要檢索 XML 資料,以求查詢處理的效率及良好的可調適性,並使用第一級的查詢最佳化工具。
  • 您想要有 XML 資料的 SOAP、ADO.NET 及 OLE DB 存取權。
  • 您想要利用資料庫伺服器的管理功能來管理您的 XML 資料。例如,您想要備份、復原及複寫資料。

如果沒有符合上述任一情況,可能比較適合將您的資料儲存成非 XML 的大型物件類型,例如:[n]varchar(max)varbinary(max)

XML 儲存選項

SQL Server 2005 中的 XML 儲存選項如下:

  • 原生儲存為 xml 資料類型
    以內部表示法來儲存資料,以保存資料的 XML 內容。這包括內含項目階層、文件順序,以及元素和屬性值。特別是會保存 XML 資料的 InfoSet 內容。如需有關 InfoSet 的詳細資訊,請瀏覽 http://www.w3.org/TR/xml-infoset。InfoSet 內容可能會與文字版 XML 不同,因為沒有保留下列資訊:不重要的空格、屬性的順序、 命名空間前置詞及 XML 宣告。
    針對具類型的 xml 資料類型 (與 XML 結構描述繫結的 xml 資料類型),後置結構描述驗證 InfoSet (PSVI) 會將類型資訊加入 InfoSet 中,而且會以內部表示法來編碼。這樣可以大幅增加剖析的速度。如需詳細資訊,請參閱 http://www.w3.org/TR/xmlschema-1http://www.w3.org/TR/xmlschema-2 的 W3C XML Schema 規格。
  • XML 與關聯式儲存之間的對應
    藉由使用註解式結構描述 (AXSD),XML 會被分解成一或多個資料表中的資料行。如此可以讓資料的精確度保持在關聯式層級。這樣一來,雖然會忽略元素之間的順序,但會保留階層結構。結構描述不能遞迴。
  • 大型物件儲存體:[n]varchar(max)varbinary(max)
    會儲存相同的資料副本。針對特殊目的應用程式 (如:法律文件),這是很有用的。大部份的應用程式都不需要完全相同的副本,且可以滿足於 XML 內容 (InfoSet 精確度)。

一般而言,您可能必須組合使用這些方法。例如,您想要將 XML 資料儲存在 xml 資料類型資料行中,並將其屬性升級為關聯式資料行。或者,您想要使用對應技術來將非遞迴的部份儲存在非 XML 資料行中,並且只將遞迴的部份儲存在 xml 資料類型資料行中。

XML 技術的選項

XML 技術的選項有原生 XML 和 XML 檢視,通常需視下列因素而定:

  • 儲存選項
    您的 XML 資料可能比較適合大型物件儲存體 (例如,產品手冊),或是比較適合儲存在關聯式資料行中 (例如,轉換成 XML 的線性項目)。每個儲存選項保留的文件精確度各不相同。
  • 查詢功能
    根據查詢的本質,以及您查詢 XML 資料的程度,您可能會發現其中一個儲存選項比另一個更合適。在這兩種儲存選項中,支援 XML 資料細項查詢 (例如:XML 節點的述詞評估) 的程度各不相同。
  • 檢索 XML 資料
    您可能會想要檢索 XML 資料,以加速 XML 查詢的效能。索引選項會依儲存選項而有所不同;您必須做出適當的選擇,以使您的工作負載最佳化。
  • 資料修改功能
    有些工作負載需要修改 XML 資料的細項。例如,可能需要在文件中加入新的區段,但在其他工作負載中 (例如:Web 內容) 則不需要。對您的應用程式而言,資料修改的語言支援可能是很重要的。
  • 結構描述支援
    您用來描述 XML 資料的結構描述可能是也可能不是 XML 結構描述文件。與結構描述繫結之 XML 的支援取決於 XML 技術。

不同的選擇也會有不同的效能特質。

原生 XML 儲存

您可以將 XML 資料儲存在伺服器的 xml 資料類型資料行中。若符合下列情況,則適用此選項:

  • 您想要直接將 XML 資料儲存在伺服器,同時也要保持文件順序和文件結構。
  • 您可能有也可能沒有 XML 資料的結構描述。
  • 您想要查詢及修改 XML 資料。
  • 您想要檢索 XML 資料,以加速查詢處理。
  • 您的應用程式需要系統目錄檢視來管理 XML 資料及 XML 結構描述。

當您的 XML 文件有一個結構範圍,或是您的 XML 文件符合相異或複雜的結構描述,而這些結構描述難以對應到關聯式結構時,原生 XML 儲存是很有用的。

範例:使用 xml 資料類型來將 XML 資料模型化

假設有一個 XML 格式的產品手冊,其中每個主題各成一章,每一章中有好幾節。每一節中還可包含小節。這麼一來,<節> 就是遞迴元素。產品手冊包含大量的混合內容、圖表和技術資料;資料是半結構化的。使用者可能會想要在內容中搜尋感興趣的主題,例如,在有關「檢索」的那一章中搜尋有關「叢集索引」的那一節,並查詢技術數量。

那麼您的 XML 文件所適合的儲存模式就是 xml 資料類型資料行。這樣可以保持 XML 資料的 InfoSet 內容。檢索 XML 資料行對於查詢效能是很有益的。

範例:保留與 XML 資料完全相同的副本

舉例來說,假設政府規定您要保留與您的 XML 文件完全相同的原文副本。例如,這些可能是簽署的文件、法律文件或股票交易訂單。您可能會想要將您的文件儲存在 [n]varchar(max) 資料行中。

若要查詢,請在執行階段將資料轉換成 xml 資料類型,並對其執行 Xquery。執行階段的轉換作業可能會很耗費資源,尤其是當文件很大時。若您經常查詢,您可以另外將文件儲存在 xml 資料類型資料行中,當您從 [n]varchar(max) 資料行傳回完全相同的文件副本時,再加以檢索。

XML 資料行可能是以 [n]varchar(max) 資料行為基礎的計算資料行。但是您不能在計算的 XML 資料行上建立 XML 索引,也不能在 [n]varchar(max)varbinary(max) 資料行上建立 XML 索引。

XML 檢視技術

在您的 XML 結構描述與資料庫中的資料表之間定義對應,即可建立永續性資料的「XML 檢視」。藉由 XML 檢視,可使用 XML 大量載入功能來擴展基礎資料表。您可以使用 XPath 1.0 版來查詢 XML 檢視;該查詢會在資料表上轉換成 SQL 查詢。同樣地,更新內容也會傳播至那些資料表。

在下列狀況下,這項技術非常有用:

  • 您想要有一個以 XML 為中心的程式設計模型,透過現有的關聯式資料來使用 XML 檢視。
  • 您有一個用於 XML 資料的結構描述 (XSD、XDR),是由外部協力廠商提供的。
  • 在您的資料中,順序並不重要,或者您的查詢資料表資料不是遞迴式的,或者事先已知道可達到的最大遞迴深度。
  • 您想要使用 XPath 1.0 透過 XML 檢視來查詢及修改資料。
  • 您想要使用 XML 檢視來大量載入 XML 資料,並將其分解在基礎資料表中。

範例包括在資料交換及 Web 服務中公開為 XML 的關聯式資料,以及含有固定結構描述的 XML 資料。如需詳細資訊,請參閱 MSDN Online Library

範例:使用註解式 XML 結構描述 (AXSD) 來將資料模型化

舉例來說,假設您要將現有的關聯式資料 (例如:客戶、訂單及線性項目) 處理成 XML。在關聯式資料上使用 AXSD,以定義 XML 檢視。XML 檢視可讓您將 XML 資料大量載入至資料表中,並使用 XML 檢視來查詢及更新關聯式資料。如果您必須在不干擾 SQL 應用程式工作的情況下,與其他應用程式交換含有 XML 標記的資料,這種模型會很有用。

混合模型

關聯式與 xml 資料類型資料行的組合最常適用於資料的模型化。XML 資料中有些值可以儲存在關聯式資料行中,其餘的值 (或是整個 XML 值) 則可儲存在 XML 資料行中。這樣可能會產生較佳的效能,因為對於以關聯式資料行及鎖定特性來建立的索引,您會有比較大的控制權。

至於要將哪些值儲存在關聯式資料行中,則需視您的工作負載而定。例如,若您是依據路徑運算式 /Customer/@CustId 來擷取所有的 XML 值,那麼將 CustId 屬性值升級至關聯式資料行中並加以檢索,可能會產生較快的查詢效能。另一方面,如果 XML 資料是廣泛且毫不多餘地分解在關聯式資料行中,則重組的成本可能會很大。

例如,針對高度結構化的 XML 資料,資料表的內容都已轉換成 XML;您可以將所有值對應到關聯式資料行,可能還會用到 XML 檢視技術。

使用 xml 資料類型的資料模型化

本節討論有關原生 XML 儲存的資料模型化主題。其中包括檢索 XML 資料、屬性升級及具類型的 xml 資料類型。

相同或相異的資料表

xml 資料類型資料行可以建立在含有其他關聯式資料行的資料表中,或是建立在與主資料表有外部索引鍵關聯性的另一份資料表中。

若有下列其中一種情況時,請將 xml 資料類型資料行建立在同一份資料表中:

  • 您的應用程式在 XML 資料行上執行資料擷取,而且不需要 XML 資料行的 XML 索引。
  • 您想要在 xml 資料類型資料行上建立 XML 索引,且主資料表的主索引鍵與其叢集索引鍵相同。如需詳細資訊,請參閱<檢索 xml 資料類型資料行>。

若有下列情況時,請將 xml 資料類型資料行建立在不同的資料表中:

  • 您想要在 xml 資料類型資料行上建立 XML 索引,但是主資料表的主索引鍵與其叢集索引鍵不同,或者主資料表沒有主索引鍵,或者主資料表是堆積 (沒有叢集索引鍵)。如果主資料表已存在,就可能會有這種情形。
  • 您不想因為資料表中有 XML 資料行存在,而讓資料表掃描的速度慢下來。無論是以 in-row 或 out-of-row 方式儲存,都會用到空間。

XML 資料的資料粒度

儲存在 XML 資料行中之 XML 資料的資料粒度對於鎖定動作是很重要的,姑且不論這一點,它對於更新也是很重要的。對於 XML 和非 XML 資料,SQL Server 都是使用相同的鎖定機制。因此,資料列層級的鎖定會導致資料列中所有的 XML 執行個體被鎖定。若資料粒度大,則鎖定大型 XML 執行個體來進行更新時,將會導致在多使用者情況下的輸送量降低。另一方面,嚴重的分解也會失去物件封裝,並增加重組成本。

在滿足資料模型化需求與鎖定和更新特性之間取得平衡,對於良好的設計是很重要的。然而,在 SQL Server 2005 中,實際儲存的 XML 執行個體大小就沒那麼重要了。

例如,對 XML 執行個體進行更新時,是使用對部份二進位大型物件 (BLOB) 和部份索引更新的新支援,其中會將目前已儲存的 XML 執行個體與其更新版本做比較。部份二進位大型物件 (BLOB) 更新作業會在這二個 XML 執行個體之間執行差異比較,並且只更新差異的部份。部份索引更新作業只會修改那些必須在 XML 索引中變更的資料列。

不具類型、具類型及受條件約束的 xml 資料類型

SQL Server 2005 的 xml 資料類型實作 ISO SQL-2003 標準 xml 資料類型。因此,它可以在不具類型的 XML 資料行中儲存結構良好的 XML 1.0 版文件,也可以儲存含有文字節點和絕對數量之最上層元素的所謂 XML 內容片段。系統會確認資料的結構良好、不需要將資料行繫結到 XML 結構描述,並拒絕在某種程度上結構不良的資料。就不具類型的 XML 變數和參數而言,也是如此。

如果您有用 XML 結構描述來描述您的 XML 資料,您可以使結構描述與 XML 資料行產生關聯,以產生具類型的 XML。XML 結構描述可用來驗證資料;在編譯查詢和資料修改陳述式期間,執行比不具類型 XML 更為精確的類型檢查;並可讓儲存和查詢處理最佳化。

在下列情況下,請使用不具類型的 xml 資料類型:

  • 您沒有 XML 資料的結構描述。
  • 您有結構描述,但您不想讓伺服器驗證資料。當應用程式在將資料儲存於伺服器之前執行用戶端驗證時,或是根據結構描述暫時儲存無效的 XML 資料時,或是在伺服器上使用不受支援的結構描述元件 (例如:key/keyref) 時,有時會有這種情形。

在下列情況下,請使用具類型的 xml 資料類型:

  • 您有 XML 資料的結構描述,而且想要讓伺服器根據該 XML 結構描述來驗證 XML 資料。
  • 您想要依據類型資訊來利用儲存及查詢最佳化作業。
  • 您想要在編譯查詢期間進一步利用類型資訊。

具類型的 XML 資料行、參數及變數可儲存 XML 文件或內容。但是您必須在宣告時,用旗標來指定您是要儲存文件或內容。此外,您也必須提供 XML 結構描述的集合。如果每個 XML 執行個體都只有一個最上層元素,請指定 DOCUMENT。否則請使用 CONTENT。查詢編譯器會在查詢編譯期間,在類型檢查中使用 DOCUMENT 旗標,以推斷單一最上層元素。

除了設定 XML 資料行的類型,您也可以在具類型或不具類型的 xml 資料類型資料行上使用關聯式 (資料行或資料列) 條件約束。在下列情況下,請使用條件約束:

  • 您的商務規則無法以 XML 結構描述來表達。例如,花店的送貨地址必須在該店的方圓 50 英哩內。這一點可以在 XML 資料行上寫成條件約束。條件約束可能會牽涉到 xml 資料類型方法。
  • 您的條件約束牽涉到資料表中的其他 XML 或非 XML 資料行。有一個例子,就是強制 XML 執行個體中的「客戶識別碼」(/Customer/@CustId) 要符合關聯式 CustomerID 資料行中的值。

文件類型定義 (DTD)

xml 資料類型資料行、變數及參數可以用 XML 結構描述來設定類型,但不能用 DTD。但是內嵌 DTD 可用於不具類型和具類型的 XML 來提供預設值,並將實體參考置換成展開的表單。

您可以用協力廠商工具來將 DTD 轉換成 XML 結構描述文件,並將 XML 結構描述載入資料庫。

檢索 xml 資料類型資料行

XML 索引可建立在 xml 資料類型資料行上。它會在資料行中檢索整個 XML 執行個體的所有標記、值和路徑,以增進查詢效能。在下列情況下,您的應用程式可從 XML 索引獲益:

  • 在您的工作負載中,經常會查詢 XML 資料行。必須將資料修改期間的 XML 索引維護成本納入考量。
  • 您的 XML 值相對較大,而所擷取的部份相對較小。建立索引可避免在執行階段剖析整份資料,並有助於索引查閱,增進查詢處理的效率。

XML 資料行上的第一個索引是主要 XML 索引。若使用此索引,可在 XML 資料行上建立三種類型的次要 XML 索引,以加速一般類別的查詢,請見下節說明。

主要 XML 索引

這會在 XML 資料行中檢索 XML 執行個體中的所有標記、值和路徑。基底資料表 (出現 XML 資料行的資料表) 在資料表的主索引鍵上必須要有一個叢集索引。主索引鍵可用來使索引資料列與基底資料表中的資料列產生相互關聯。完整的 XML 執行個體會從 XML 資料行 (例如:SELECT *) 中擷取出來。查詢會使用主要 XML 索引,並使用索引本身來傳回純量值或 XML 子樹。

範例:建立主要 XML 索引

在大部份的範例中,都是使用資料表 T (pk INT PRIMARY KEY, xCol XML) 和不具類型的 XML 資料行。這些都可以用一種直接的方法來擴充成具類型的 XML。如需具類型 XML 的用法詳細資訊,請參閱<XML 資料類型>。為求簡單明瞭,我們針對 XML 資料執行個體來說明查詢,如下所示:

<book genre="security" publicationdate="2002" ISBN="0-7356-1588-2">
   <title>Writing Secure Code</title>
   <author>
      <first-name>Michael</first-name>
      <last-name>Howard</last-name>
   </author>
   <author>
      <first-name>David</first-name>
      <last-name>LeBlanc</last-name>
   </author>
   <price>39.99</price>
</book>

下列陳述式會在資料表 T 的 XML 資料行 xCol 上建立一個名為 idx_xCol 的 XML 索引:

CREATE PRIMARY XML INDEX idx_xCol on T (xCol)

次要 XML 索引

建立好主要 XML 索引之後,您可能會想要建立次要 XML 索引來加速工作負載中不同類別的查詢。三種次要 XML 索引類型:PATH、PROPERTY 和 VALUE,分別有助於依路徑查詢、自訂屬性管理案例和依值查詢。PATH 索引會依資料行中所有 XML 執行個體的文件順序,在每個 XML 節點的 (路徑、值) 配對上建立 B+ 樹狀目錄。PROPERTY 索引會在每個 XML 執行個體中的 (PK、路徑、值) 配對上,建立 B+ 樹狀目錄叢集,其中 PK 是基底資料表的主索引鍵。最後,VALUE 索引會依 XML 資料行中所有 XML 執行個體的文件順序,在每個節點的 (值、路徑) 配對上建立 B+ 樹狀目錄。

以下是建立一或多個上述索引的一些指導方針:

  • 如果您的工作負載在 XML 資料行上大量使用路徑運算式,PATH 次要 XML 索引就可能會加速您的工作負載。最常見的情況,就是在 Transact-SQL 的 WHERE 子句中,於 XML 資料行上使用 exist() 方法。
  • 如果您的工作負載使用路徑運算式,從個別的 XML 執行個體中擷取多個值,則在 PROPERTY 索引中將路徑叢集在每個 XML 執行個體中,可能會有所幫助。當物件的屬性被提取,且已知其主索引鍵值時,此案例通常會發生在屬性包案例中。
  • 如果您的工作負載需要查詢 XML 執行個體中的值,但您不知道含有那些值的元素或屬性名稱,您可能會想要建立 VALUE 索引。這通常會發生在下階座標軸查閱,例如 //author[last-name="Howard"],其中 <author> 元素可出現在階層中的任何層級。這也會發生在萬用字元查詢中,例如 /book [@* = "novel"],此查詢是要尋找屬性中具有 "novel" 值的 <book> 元素。
範例:依路徑查閱

舉例來說,假設您的工作負載中常有下列查詢:

SELECT pk, xCol
FROM   T
WHERE  xCol.exist ('/book/@genre[.="novel"]') = 1

路徑運算式 /book/@genre 及 "novel" 值對應於 PATH 索引的索引鍵欄位。如此一來,PATH 類型的次要 XML 索引將有助於此工作負載:

CREATE XML INDEX idx_xCol_Path on T (xCol)
   USING XML INDEX idx_xCol FOR PATH
範例:提取物件的屬性

試想下列查詢要從資料表 T 中的每個資料列擷取一本書的分類、書名及 ISBN 等屬性:

SELECT xCol.value ('(/book/@genre)[1]', 'varchar(50)'),
    xCol.value ('(/book/title/text())[1]', 'varchar(50)'),
    xCol.value ('(/book/@ISBN)[1]', 'varchar(50)')
FROM    T

在這種情況下,屬性索引是很有用的,其建立方式如下:

CREATE XML INDEX idx_xCol_Property on T (xCol)
   USING XML INDEX idx_xCol FOR PROPERTY
範例:依值查閱

在下列查詢中,descendant-or-self 座標軸 (//) 指定了部份的路徑,所以使用 VALUE 索引將有助於依 ISBN 值來查閱的動作:

SELECT xCol
FROM    T
WHERE    xCol.exist ('//book/@ISBN[. = "0-7356-1588-2"]') = 1

VALUE 索引的建立方式如下:

CREATE XML INDEX idx_xCol_Value on T (xCol)
   USING XML INDEX idx_xCol FOR VALUE

XML 資料行全文檢索

您可以在 XML 資料行上建立全文檢索,以檢索 XML 值的內容,但忽略 XML 標記。屬性值並沒有被全文檢索,因為它被視為標記的部份,而元素標記則是用來當作 token 界限。在可能的情況下,您可以用下列方法來將全文檢索搜尋與 XML 索引合併:

  • 首先,使用 SQL 全文檢索搜尋來篩選出感興趣的 XML 值。
  • 接著,查詢那些在 XML 資料行上使用 XML 索引的 XML 值。
範例:將全文檢索搜尋與 XML 查詢合併

在 XML 資料行上建立全文檢索之後,下列查詢會確認 XML 值在書名中有包含 "custom" 這個字:

SELECT * 
FROM   T 
WHERE  CONTAINS(xCol,'custom') 
AND    xCol.exist('/book/title/text()[contains(.,"custom")]') =1

contains() 方法使用全文檢索來進一步設定在文件中任何地方含有 "custom" 這個字的 XML 值。exist() 子句可確定 "custom" 這個字有出現在書名中。

使用 contains() 和 XQuery contains() 的全文檢索搜尋具有不同的語意。後者是子字串相符項,前者則是使用詞幹的 token 相符項。因此,如果該搜尋是要尋找書名中有 "run" 的字串,相符項中將會包含 "run"、"runs" 和 "running",因為全文檢索 contains() 和 Xquery contains() 都滿足了。然而,該查詢與書名中的 "customizable" 這個字不符,因為全文檢索 contains() 失敗,但滿足了 Xquery contains()。一般而言,若只要子字串相符,則應移除全文檢索 contains() 子句。

此外,全文檢索搜尋會使用詞幹,但 XQuery contains() 是逐字比對的相符項。下一個範例將舉例說明之間的差異。

範例:使用詞幹在 XML 值上進行全文檢索搜尋

在上個範例中執行的 XQuery contains() 檢查通常是無法排除的。請考量這項查詢:

SELECT * 
FROM   T 
WHERE  CONTAINS(xCol,'run') 

文件中的 "ran" 之所以能夠符合搜尋條件,是因為使用詞幹,而且沒有使用 XQuery 來檢查搜尋內容。

當您使用已全文檢索的 AXSD 來將 XML 分解在關聯式資料行中,在 XML 檢視上出現的 XPath 查詢就不會在基礎資料表上執行全文檢索搜尋。

升級屬性

如果查詢主要只是針對少數的元素和屬性值來執行,您可能會想要將那些量升級至關聯式資料行。若已擷取整個 XML 執行個體,但您只是要針對小部份的 XML 資料來發出查詢要求時,這是很有幫助的。您不需要在 XML 資料行上建立 XML 索引,即可檢索升級的資料行。您必須撰寫查詢來使用升級的資料行。意即,查詢最佳化工具不再將 XML 資料行查詢的目標放在升級的資料行。

升級的資料行可以是同一資料表中的已計算資料行,也可以是資料表中由使用者維護的另一個資料行。當單一值從每個 XML 執行個體升級起來時,這就足夠了。然而,若為多重值的屬性,您就必須為屬性建立個別的資料表,請見下節說明。

以 xml 資料類型為基礎的計算的資料行

若要建立計算的資料行,您可以使用使用者自訂函數來叫用 xml 資料類型方法。計算的資料行類型可以是任何 SQL 類型,包括 XML。下列範例會加以說明。

範例:以 xml 資料類型方法為基礎的計算的資料行

針對書籍的 ISBN 號碼來建立使用者自訂函數:

CREATE FUNCTION udf_get_book_ISBN (@xData xml)
RETURNS varchar(20)
BEGIN
   DECLARE @ISBN   varchar(20)
   SELECT @ISBN = @xData.value('/book[1]/@ISBN', 'varchar(20)')
   RETURN @ISBN 
END

將計算的資料行加入 ISBN 的資料表中:

ALTER TABLE      T
ADD   ISBN AS dbo.udf_get_book_ISBN(xCol)

可以用一般的方式來檢索計算的資料行。

範例:查詢以 xml 資料類型方法為基礎的計算的資料行

若要取得 ISBN 為 0-7356-1588-2 的 <book>,請:

SELECT xCol
FROM   T
WHERE  xCol.exist('/book/@ISBN[. = "0-7356-1588-2"]') = 1

您可以改寫對 XML 資料行的查詢,以使用計算的資料行,如下所示:

SELECT xCol
FROM   T
WHERE  ISBN = '0-7356-1588-2'

您可以建立使用者自訂函數,以使用該使用者自訂函數來傳回 xml 資料類型和計算的資料行。然而,您不能在計算的 XML 資料行上建立 XML 索引。

建立屬性資料表

您可能會想要將某些多重值的屬性從 XML 資料升級至一或多個資料表中、在那些資料表上建立索引,然後再讓您的查詢目標使用那些資料表。一般案例中都是由少數的屬性來涵蓋大部份的查詢工作負載。您可以執行下列工作:

  • 建立一或多個資料表來保存多重值的屬性。您會發現,每個資料表各儲存一個屬性,並且在屬性資料表中複製基底資料表的主索引鍵,再向後聯結基底資料表,這麼做是很方便的。
  • 如果您要維持屬性的相對順序,就必須為相對順序導入另一個資料行。
  • 在 XML 資料行上建立觸發程序,以維護屬性資料表。在觸發程序中執行下列其中之一:
    • 使用 xml 資料類型方法 (例如:nodes()value()) 來插入及刪除屬性資料表的資料列。
    • 在 Common Language Runtime (CLR) 中建立資料流資料表值的函數,以插入及刪除屬性資料表的資料列。
    • 撰寫查詢來讓 SQL 存取屬性資料表,並讓 XML 存取基底資料表中的 XML 資料表,再使用其主索引鍵來聯結這二個資料表。
範例:建立屬性資料表

舉例來說,假設您要升級作者的名字。書籍的作者可能不只一個,所以名字是多重值的屬性。每個名字都是儲存在屬性資料表的不同資料列中。在屬性資料表中會複製基底資料表的主索引鍵,以供向後聯結。

create table tblPropAuthor (propPK int, propAuthor varchar(max))
範例:建立使用者自訂函數,以從 XML 執行個體產生資料列集。

下列資料表值函數 udf_XML2Table 可接受主索引鍵值和 XML 執行個體。它會擷取 <book> 元素中所有作者的名字,並傳回主索引鍵的資料列集 (名字配對)。

create function udf_XML2Table (@pk int, @xCol xml)
returns @ret_Table table (propPK int, propAuthor varchar(max))
with schemabinding
as
begin
      insert into @ret_Table 
      select @pk, nref.value('.', 'varchar(max)')
      from   @xCol.nodes('/book/author/first-name') R(nref)
      return
end
範例:建立觸發程序來擴展屬性資料表

插入觸發程序會在屬性資料表中插入資料列:

create trigger trg_docs_INS on T for insert
as
      declare @wantedXML xml
      declare @FK int
      select @wantedXML = xCol from inserted
      select @FK = PK from inserted

   insert into tblPropAuthor
   select * from dbo.udf_XML2Table(@FK, @wantedXML)

刪除觸發程序會依據已刪除之資料列的主索引鍵值,從屬性資料表中刪除資料列:

create trigger trg_docs_DEL on T for delete
as
   declare @FK int
   select @FK = PK from deleted
   delete tblPropAuthor where propPK = @FK

更新觸發程序會對應已更新的 XML 執行個體,來刪除屬性資料表中的現有資料列,並且在屬性資料表中插入新的資料列:

create trigger trg_docs_UPD
on T
for update
as
if update(xCol) or update(pk)
begin
      declare @FK int
      declare @wantedXML xml
      select @FK = PK from deleted
      delete tblPropAuthor where propPK = @FK

   select @wantedXML = xCol from inserted
   select @FK = pk from inserted

   insert into tblPropAuthor 
      select * from dbo.udf_XML2Table(@FK, @wantedXML)
end
範例:尋找作者名字為 "David" 的 XML 執行個體

查詢可以在 XML 資料行上構成。或者,可以在屬性資料表中搜尋 "David" 這個名字,然後執行向後聯結基底資料表,以傳回 XML 執行個體。例如:

SELECT xCol 
FROM     T JOIN tblPropAuthor ON T.pk = tblPropAuthor.propPK
WHERE    tblPropAuthor.propAuthor = 'David'
範例:使用 CLR 資料流資料表值函數的解決方案

這個解決方案包含下列步驟:

  1. 定義 CLR 類別 SqlReaderBase,在 XML 執行個體上套用路徑運算式,以實作 ISqlReader 並產生資料流資料表值輸出。
  2. 建立組件及 Transact-SQL 使用者自訂函數,以啟動 CLR 類別。
  3. 使用使用者自訂函數來定義插入、更新及刪除觸發程序,以維護屬性資料表。

若要執行此作業,您要先建立資料流 CLR 函數。xml 資料類型在 ADO.NET 中公開為 Managed 類別 SqlXml,並支援 CreateReader() 方法來傳回 XmlReader。

ms187508.note(zh-tw,SQL.90).gif附註:
本節中的範例程式碼使用 XPathDocument 及 XPathNavigator。它們會強制您將所有 XML 文件載入記憶體。如果您在應用程式中使用類似的程式碼來處理好幾個大型 XML 文件,此程式碼是無法調整的。反之,您要讓記憶體配置維持少量,並且儘可能使用資料流介面。如需效能的詳細資訊,請參閱<Architecture of CLR Integration>。
public class c_streaming_xml_tvf {
   public static ISqlReader streaming_xml_tvf 
(SqlXml xmlDoc, string pathExpression) {
      return (new TestSqlReaderBase (xmlDoc, pathExpression));
   }
}

// Class that implements ISqlReader
public class TestSqlReaderBase : ISqlReader {
XPathNodeIterator m_iterator;         
   public SqlChars FirstName;
// Metadata for current resultset
private SqlMetaData[] m_rgSqlMetaData;      

   public TestSqlReaderBase (SqlXml xmlDoc, string pathExpression) {   
      // Variables for XPath navigation
      XPathDocument xDoc;
      XPathNavigator xNav;
      XPathExpression xPath;
   
      // Set sql metadata
      m_rgSqlMetaData = new SqlMetaData[1];
      m_rgSqlMetaData[0] = new SqlMetaData ("FirstName",  
SqlDbType.NVarChar,50);   
   
      //Set up the Navigator
      if (!xmlDoc.IsNull)
          xDoc = new XPathDocument (xmlDoc.CreateReader());
      else
          xDoc = new XPathDocument ();
      xNav = xDoc.CreateNavigator();
      xPath = xNav.Compile (pathExpression);
      m_iterator = xNav.Select(xPath);
   }
   public bool Read() {
      bool moreRows = true;
      if (moreRows = m_iterator.MoveNext())
         FirstName = new SqlChars (m_iterator.Current.Value);
      return moreRows;
   }
}

接著,請建立組件以及對應於 CLR 函數 streaming_xml_tvf 的 Transact-SQL 使用者自訂函數 SQL_streaming_xml_tvf (未顯示)。使用者自訂函數可用來定義資料表值函數 CLR_udf_XML2Table,以產生資料列集:

create function CLR_udf_XML2Table (@pk int, @xCol xml)
returns @ret_Table table (FK int, FirstName varchar(max))
with schemabinding
as
begin
      insert into @ret_Table 
   select @pk, FirstName 
   FROM   SQL_streaming_xml_tvf (@xCol, '/book/author/first-name')
      return
end

最後,請依照範例「建立觸發程序來擴展屬性資料表」的說明來定義觸發程序,但請將 udf_XML2Table 置換成 CLR_udf_XML2Table 函數。插入觸發程序如下列範例中所示:

create trigger CLR_trg_docs_INS on T for insert
as
   declare @wantedXML xml
   declare @FK int
   select @wantedXML = xCol from inserted
   select @FK = PK from inserted

   insert into tblPropAuthor
      select *
   from    dbo.CLR_udf_XML2Table(@FK, @wantedXML)

刪除觸發程序與非 CLR 版本相同。然而,更新觸發程序只有將函數 udf_XML2Table() 置換成 CLR_udf_XML2Table()。

XML 結構描述集合

XML 結構描述集合是由關聯式結構描述來限制範圍的中繼資料實體。其包含一或多個 XML 結構描述,可能是相關的 (例如透過 <xs:import>),也可能是不相關的。XML 結構描述集合中的個別 XML 結構描述是使用其目標命名空間來識別的。

XML 結構描述集合是使用 CREATE XML SCHEMA COLLECTION (Transact-SQL) 語法,並提供一或多個 XML 結構描述來建立的。若要將更多的 XML 結構描述元件加入現有的 XML 結構描述,以及將更多的結構描述加入 XML 結構描述集合,可以使用 ALTER XML SCHEMA COLLECTION (Transact-SQL) 語法。若要像保護 SQL 物件那樣來保護 XML 結構描述集合,則可使用 SQL Server 2005 中的安全性模式。

多類型資料行

XML 結構描述集合 C 會依據多重 XML 結構描述,來設定 XML 資料行 xCol 的類型。此外,DOCUMENT 和 CONTENT 旗標分別可以指定 XML 樹狀結構或片段是否可以儲存在資料行 xCol 中。

若為 DOCUMENT,每個 XML 執行個體會指定執行個體中最上層元素的目標命名空間,而 XML 執行個體會據此設定類型以及進行驗證。另一方面,若為 CONTENT,則每個最上層元素都能各自指定 C 中的任何一個目標命名空間。而 XML 執行個體會依據執行個體中出現的所有目標命名空間來進行驗證及設定類型。

結構描述的演化

XML 結構描述集合是用來設定 XML 資料行、變數及參數的類型,它提供了 XML 結構描述演化的機制。舉例來說,假設您將含有目標命名空間 BOOK-V1 的 XML 結構描述加入 XML 結構描述集合 C。則使用 C 來設定類型的 XML 資料行 xCol,便可以儲存符合 BOOK-V1 結構描述的 XML 資料。

再假設有一個應用程式想要以新的結構描述元件來擴充 XML 結構描述,例如:複雜類型的定義和最上層元素宣告。這些新結構描述元件可以加入到 BOOK-V1 結構描述,而且不需要重新驗證資料行 xCol 中的現有 XML 資料。

假設該應用程式之後想要提供新版本的 XML 結構描述,並選取目標命名空間 BOOK-V2。此 XML 結構描述可以新增到 C。XML 資料行可以儲存 BOOK-V1 和 BOOK-V2 的執行個體,並且在符合這些命名空間的 XML 執行個體上執行查詢及資料修改。

載入 XML 資料

將 XML 資料從 SQL Server 2000 傳送到 SQL Server 2005

將 XML 資料傳送到 SQL Server 2005 的方法有好幾種。例如:

  • 如果您將資料放在 SQL Server 2000 資料庫的 [n]text 或 image 資料行中,則可使用 SQL Server 2005 Integration Services (SSIS) 來將資料表匯入 SQL Server 2005 資料庫。使用 ALTER TABLE 陳述式來將資料行類型變更成 XML。
  • 您可以使用 bcp out 從 SQL Server 2000 大量複製資料,然後再使用 bcp in 將資料大量插入 SQL Server 2005 資料庫。
  • 如果您將資料放在 SQL Server 2000 資料庫的關聯式資料行中,請建立一個含有 [n]text 資料行的新資料表,並可選擇加入主索引鍵資料行來放置資料列識別碼。使用用戶端程式設計來擷取在伺服器上以 FOR XML 產生的 XML,並將它寫入 [n]text 資料行。然後使用先前提到的技巧,將資料傳送至 SQL Server 2005 資料庫。您可以選擇直接將 XML 寫入 SQL Server 2005 資料庫中的 XML 資料行。
範例:將資料行類型變更成 XML

假設您要將 [n]textimage 資料行的類型 (資料表 R 中的 XYZ) 變更成不具類型的 XML。下列陳述式會執行此類型變更:

ALTER TABLE R ALTER COLUMN XYZ XML
  • 若有必要,可以指定 XML 結構描述集合,使目標成為具類型的 XML。

大量載入 XML 資料

您可以使用 SQL Server 的大量載入功能 (例如:bcp) 來將 XML 資料大量載入伺服器。OPENROWSET 可讓您將資料從檔案載入至 XML 資料行中。下列範例將說明這一點。

範例:從檔案載入 XML

此範例顯示如何在資料表 T 中插入資料列。XML 資料行的值從檔案 C:\MyFile\xmlfile.xml 載入成 CLOB,並且在整數資料行中提供值 10。

INSERT INTO T
SELECT 10, xCol
FROM    (SELECT *    
    FROM OPENROWSET (BULK 'C:\MyFile\xmlfile.xml', SINGLE_CLOB) 
 AS xCol) AS R(xCol)

文字編碼方式

SQL Server 2005 以 Unicode (UTF-16) 來儲存 XML 資料。從伺服器擷取出來的 XML 資料會成為 UTF-16 編碼。如果您要使用不同的編碼,則必須對所擷取的資料執行必要的轉碼作業。有時 XML 資料會是不同的編碼。若有這種情形,您在載入資料時要特別小心。例如:

  • 如果您的文字 XML 是 Unicode (UCS-2, UTF-16) 編碼,則可將它指派至 XML 資料行、變數或參數,都不會有任何問題。
  • 如果因為來源字碼頁的關係,編碼不是 Unicode 而且是隱含的,則資料庫中的字串字碼頁應與您要載入的字碼指標相同或相容。若有必要,請使用 COLLATE。如果沒有這類的伺服器字碼頁存在,則必須加入含有正確編碼的明確 XML 宣告。
  • 若要使用明確的編碼,請使用 varbinary() 類型 (與字碼頁沒有互動) 或使用適當字碼頁的字串類型。然後再將資料指派給 XML 資料行、變數或參數。
範例:明確地指定編碼方式

假設您將 XML 文件 vcdoc 儲存成沒有明確 XML 宣告的 varchar(max)。下列陳述式會加入具有編碼 "iso8859-1" 的 XML 宣告、串連 XML 文件、將結果轉換成 varbinary(max),位元組表示法因而保存下來,最後再轉換成 XML。這樣可以讓 XML 處理器依據所指定的編碼 "iso8859-1" 來剖析資料,並針對字串值來產生對應的 UTF-16 表示法。

SELECT CAST( 
CAST (('<?xml version="1.0" encoding="iso8859-1"?>'+ vcdoc) AS VARBINARY (MAX)) 
 AS XML)

XQuery 及類型推斷

內嵌在 Transact-SQL 中的 XQuery 是查詢 xml 資料類型時所支援的語言。該語言是由 World Wide Web Consortium (W3C) 所開發,Microsoft 所有的主要資料庫廠商也都參與其中。其包含 XPath 2.0 版來作為導覽語言。xml 資料類型中也有修改資料所需的語言建構。如需 SQL Server 中所支援之 XQuery 建構、函數及運算子的詳細資訊,請參閱<對 XML 資料類型進行 XQuery 函數>。

錯誤模型

句法不正確的 Xquery 運算式及 XML DML 陳述式會傳回編譯錯誤。編譯階段會檢查 XQuery 運算式及 DML 陳述式的靜態類型正確性,並針對具類型的 XML 的類型推斷來使用 XML 結構描述。如果因為類型安全違規,而導致運算式在執行階段失敗,就會引發靜態類型錯誤。靜態錯誤的範例包括:加入字串至整數,以及針對具類型的資料來查詢不存在的節點。

XQuery 執行階段錯誤會轉換成空的序列,這一點有違 W3C 標準。依據引動過程內容,這些序列可能會以空的 XML 或 NULL 傳播至查詢結果。

雖然執行階段轉換錯誤會被轉換成空的序列,但明確地轉換為正確的類型可讓使用者解決靜態錯誤。

下列各節將進一步說明類型檢查。

單一性檢查

如果編譯器無法判斷是否能在執行階段保證單一性,則需要單一性的尋找步驟、函數參數及運算子將會傳回錯誤。這個問題經常發生在不具類型的資料上。例如,查閱屬性時需要單一父元素。選擇單一父節點的序數即已足夠。評估 node()-value() 組合來擷取屬性值時,可能不需要序數規格。下一個範例將會加以說明。

範例:已知的單一性

在此範例中,nodes() 方法會針對每一個 <book> 元素各產生一個資料列。在 <book> 節點上評估的 value() 方法會擷取 @genre 的值,而且作為一個屬性,它是單一的。

SELECT nref.value('@genre', 'varchar(max)') LastName
FROM   T CROSS APPLY xCol.nodes('//book') AS R(nref)

XML 結構描述可用來檢查具類型之 XML 的類型。如果在 XML 結構描述中將節點指定為單一性,編譯器就會使用該資訊,而且不會發生錯誤。否則,就需要有選擇單一節點的序數。尤其是,使用 descendant-or-self 座標軸 (//) (例如在 /book//title 中) 時,會放鬆 <title> 元素的單一基數推斷,即使 XML 結構描述指定要這樣。因此,您應將它改寫成 (/book//title)[1]。

在執行類型檢查時,應隨時注意 //first-name[1] 與 (//first-name)[1] 之間的差異,這是很重要的。前者會傳回 <first-name> 節點的序列,其中每個節點都是同層級中最左邊的 <first-name> 節點。後者會傳回 XML 執行個體中,文件順序中的第一個單一 <first-name> 節點。

範例:使用 value()

下面這個在不具類型 XML 資料行上執行的查詢會導致靜態的編譯錯誤。這是因為 value() 預期以單一節點來作為第一個引數,而編譯器無法判斷在執行階段是否只會出現一個 <last-name> 節點:

SELECT xCol.value('//author/last-name', 'nvarchar(50)') LastName
FROM   T

您可以考慮下面這個解決方案:

SELECT xCol.value('//author/last-name[1]', 'nvarchar(50)') LastName
FROM   T

然而,這個解決方案並不能解決錯誤,因為每個 XML 執行個體中可能都會出現多個 <author> 節點。下列改寫方案可以奏效:

SELECT xCol.value('(//author/last-name/text())[1]', 'nvarchar(50)') LastName
FROM   T

此查詢會傳回每個 XML 執行個體中第一個 <last-name> 元素的值。

父軸

如果無法判斷節點的類型,則該節點會變成 anyType。這並不會隱含地轉換成任何其他類型。在導覽期間使用父軸 (例如:xCol.query('/book/@genre/../price')) 時,這種情況最為明顯。父節點類型會被判定為 anyType。在 XML 結構描述中,也有可能會將元素定義成 anyType。在這二種情況中,若經常流失較為精確的類型資訊,將會導致靜態類型錯誤,並且需要明確地將不可部份完成值轉換成其特定類型。

Data()、text() 及 string() 存取子

XQuery 有一個函數 fn:data() 可從節點擷取純量、具類型的值,有一個節點測試 text() 可傳回文字節點,還有一個函數 fn:string() 可傳回節點的字串值。它們的用法很容易混淆。以下是在 SQL Server 2005 中正確使用它們的指導方針。XML 執行個體 <age>12</age> 是用來舉例說明的。

  • 不具類型的 XML:路徑運算式 /age/text() 會傳回文字節點 "12"。函數 fn:data(/age) 會傳回字串值 "12",而 fn:string(/age) 也是。
  • 具類型的 XML:針對任何簡單的具類型的 <age> 元素,運算式 /age/text() 都會傳回靜態錯誤。另一方面,fn:data(/age) 會傳回整數 12。fn:string(/age) 會產生字串 "12"。

聯集類型的函數及運算子

因為類型檢查的關係,處理聯集類型要很小心。下列範例將舉例說明兩個問題。

範例:聯集類型的函數

請針對聯集類型的 <r> 來考量元素定義:

<xs:element name="r">
<xs:simpleType>
   <xs:union memberTypes="xs:int xs:float xs:double"/>
</xs:simpleType>
</xs:element>

在 XQuery 內容中,"average" 函數 fn:avg (//r) 會傳回靜態錯誤,因為 XQuery 編譯器無法在 fn:avg() 的引數中為 <r> 元素加入不同類型的值 (xs:int、xs:float 或 xs:double)。若要解決這個問題,請將函數引動過程改寫成 fn:avg(for $r in //r return $r cast as xs:double ?)。

範例:聯集類型的運算子

加法運算 ('+') 需要精確的運算元類型。因此,運算式 (//r)[1] + 1 會傳回靜態錯誤,其中含有前述之元素 <r> 的類型定義。有一種解決方法,就是將它改寫成 (//r)[1] cast as xs:int?+1,其中 "?" 指示出現次數 0 或 1。SQL Server 2005 需要 "cast as" 含有 "?",因為任何轉換都可能會因執行階段錯誤,而造成空的序列。

Value()、Nodes() 及 OpenXML()

您可以在 SELECT 子句的 xml 資料類型上使用多重 value() 方法,以產生擷取值的資料列集。nodes() 方法會針對可用於額外查詢的每個所選節點,各產生一項內部參考。在產生資料列集時,如果所產生的資料列集會有數個資料行,且用來產生資料列集的路徑運算式很複雜時,合併 nodes()value() 方法會比較有效率。

nodes() 方法會產生特殊 xml 資料類型的執行個體,其中每個執行個體都將其內容設定至不同的選取節點。這種 XML 執行個體可支援 query()value()nodes()exist() 方法,並可用於 count(*) 彙總。所有其他用法都會導致錯誤。

範例:使用 nodes()

假設您要擷取作者的姓名,而名字部份不是 "David"。此外,您還想要將此資訊擷取成包含二個資料行 (FirstName 及 LastName) 的資料列集。您可以使用 nodes()value() 方法來完成此作業,如下所示:

SELECT nref.value('(first-name/text())[1]', 'nvarchar(50)') FirstName,
       nref.value('(last-name/text())[1]', 'nvarchar(50)') LastName
FROM   T CROSS APPLY xCol.nodes('//author') AS R(nref)
WHERE  nref.exist('first-name[. != "David"]') = 1

在此範例中,nodes('//author') 產生參考各 XML 執行個體之 <author> 元素的資料列集。藉由評估與那些參考有關的 value() 方法,即可取得作者的名字和姓氏。

SQL Server 2000 提供一種功能,可使用 OpenXml() 從 XML 執行個體產生資料列集。您可以指定資料列集的關聯式結構描述,以及 XML 執行個體中的值要如何對應到資料列集中的資料行。

範例:在 xml 資料類型上使用 OpenXml()

您可以依下列方式使用 OpenXml() 來改寫上一個範例中的查詢。這個方式是建立資料指標來將每個 XML 執行個體讀入 XML 變數,然後再套用 OpenXML:

DECLARE name_cursor CURSOR
FOR
   SELECT xCol 
   FROM   T
OPEN name_cursor
DECLARE @xmlVal XML
DECLARE @idoc int
FETCH NEXT FROM name_cursor INTO @xmlVal

WHILE (@@FETCH_STATUS = 0)
BEGIN
   EXEC sp_xml_preparedocument @idoc OUTPUT, @xmlVal
   SELECT   *
   FROM   OPENXML (@idoc, '//author')
          WITH (FirstName  varchar(50) 'first-name',
                LastName   varchar(50) 'last-name') R
   WHERE  R.FirstName != 'David'

   EXEC sp_xml_removedocument @idoc
   FETCH NEXT FROM name_cursor INTO @xmlVal
END
CLOSE name_cursor
DEALLOCATE name_cursor 

OpenXml() 會建立一個 in-memory 表示法,並使用工作資料表來代替查詢處理器。它是倚賴 MSXML 3.0 版的 XPath 1.0 版處理器,而不是 XQuery 引擎。即使是在同一個 XML 執行個體上,工作資料表還是不能讓多個 OpenXml() 呼叫共用。這限制了它的可調適性。OpenXml() 可讓您在沒有指定 WITH 子句的情況下,存取 XML 資料的邊緣資料表格式。此外,也可以讓您在另一個「溢位」資料行中使用其餘的 XML 值。

nodes()value() 函數的組合可以有效地利用 XML 索引。因此,這種組合所展現的可調適性比 OpenXml 好。

使用 FOR XML 從資料列集產生 XML

您可以使用 FOR XML 搭配新的 TYPE 指示詞,以從資料列集產生 xml 資料類型執行個體。

其結果可以指派給 xml 資料類型資料行、變數或參數。此外,還可以將 FOR XML 巢狀化,以產生任何階層式結構。與 FOR XML EXPLICIT 相較,這樣撰寫巢狀 FOR XML 更為方便,但是對於較深的階層,其效能可能沒那麼好。FOR XML 也導入了一種新的 PATH 模式。這種新模式可以在資料行值出現的 XML 樹狀結構中指定路徑。

新的 FOR XML TYPE 指示詞可用來定義含有 SQL 語法之關聯式資料的唯讀 XML 檢視。您可以用 SQL 陳述式和內嵌的 XQuery 來查詢該檢視,如下列範例所示。您也可以在預存程序中參照這些 SQL 檢視。

範例:傳回所產生之 xml 資料類型的 SQL 檢視

下列 SQL 檢視定義會建立一個 XML 檢視,可供檢視從 XML 資料行中擷取的關聯式資料行、pk 及書籍作者。

CREATE VIEW V (xmlVal) AS
SELECT pk, xCol.query('/book/author')
FROM   T
FOR XML AUTO, TYPE

V 檢視包含單一資料列及 XML 類型的單一 columnxmlVal。其查詢方法就像一般 xml 資料類型執行個體一樣。例如,下列查詢會傳回名字叫 "David" 的作者:

SELECT xmlVal.query('//author[first-name = "David"]')
FROM   V

SQL 檢視定義有點像用註解結構描述來建立的 XML 檢視。但是,有幾個重要的相異之處。SQL 檢視定義是唯讀的,而且必須用內嵌的 XQuery 來操控。XML 檢視則是用註解結構描述來建立的。此外,SQL 檢視會先將 XML 結果具體化,再套用 XQuery 運算式,而 XML 檢視上的 XPath 查詢則是會在基礎資料表上評估 SQL 查詢。

加入商務邏輯

將商務邏輯加入至 XML 資料的方法有好幾種:

  • 您可以撰寫資料列或資料行條件約束,以在插入及修改 XML 資料時,強制執行網域專屬的條件約束。
  • 您可以在 XML 資料行上撰寫觸發程序,當您在資料行中插入或更新值時,即引發該觸發程序。觸發程序可包含網域專屬的驗證規則,或是擴展屬性資料表。
  • 您可以用 Managed 程式碼來撰寫要接收 XML 值的 SQLCLR 函數,並使用 System.Xml 命名空間所提供的 XML 處理功能。例如,將 XSL 轉換套用至 XML 資料。或者,您可以將 XML 還原序列化成一或多個受管理類別,並使用 Managed 程式碼來加以操作。
  • 您可以撰寫 Transact-SQL 預存程序及函數,以針對您的商業需求開始處理 XML 資料行。
範例:套用 XSL 轉換

試想,有一個 CLR 函數 TransformXml() 要接受 xml 資料類型執行個體和儲存在檔案中的 XSL 轉換,將該轉換套用至 XML 資料之後,在結果中傳回已轉換的 XML。以下是用 C# 來撰寫的基本架構函數:

public static SqlXml TransformXml (SqlXml XmlData, string xslPath) {
   // Load XSL transformation
   XslCompiledTransform xform = new XslCompiledTransform();
   XPathDocument xslDoc = new XPathDocument (xslPath);
   xform.Load(xslDoc);

   // Load XML data 
   XPathDocument xDoc = new XPathDocument (XmlData.CreateReader());

   // Return the transformed value
   MemoryStream xsltResult = new MemoryStream();
   xform.Transform(xDoc, null, xsltResult);
   SqlXml retSqlXml = new SqlXml(xsltResult);
   return (retSqlXml);
} 

在註冊完組件,並建立好使用者自訂的 Transact-SQL 函數之後 (SqlXslTransform() 對應到 TransformXml()),即可從 Transact-SQL 來叫用該函數,如下列查詢所示:

SELECT SqlXslTransform (xCol, 'C:\MyFile\xsltransform.xsl')
FROM    T
WHERE  xCol.exist('/book/title/text()[contains(.,"custom")]') =1

查詢結果包含已轉換之 XML 的資料列集。

SQLCLR 擴展了下列作業的可能性:將 XML 資料分解在資料表或屬性升級中,以及在 System.Xml 命名空間中使用受管理的類別來查詢 XML 資料。如需詳細資訊,請參閱《SQL Server 線上叢書》與 .NET Framework SDK 文件集。

跨網域查詢

若您的資料位於關聯式與 xml 資料類型資料行的組合中,您可能會想要撰寫查詢來合併處理關聯式及 XML 資料。例如,您可以使用 FOR XML 來將關聯式及 XML 資料行中的資料轉換成 xml 資料類型執行個體,然後使用 XQuery 來查詢。相反地,您也可以從 XML 值中產生資料列集,並使用 Transact-SQL 來查詢。

撰寫跨網域查詢時,較方便且有效率的方法,就是在 XQuery 或 XML DML 運算式中使用 SQL 變數或資料行的值:

  • 您可以使用 sql:variable(),以在 XQuery 或 XML DML 運算式中使用 SQL 變數的值。
  • 您可以使用 sql:column(),以在 XQuery 或 XML DML 運算式中使用關聯資料行的值。

這二種方法都可以讓應用程式將查詢參數化,如下一個範例所示。然而,在 sql:variable()sql:column() 中,並不容許 XML 及使用者自訂類型。

範例:使用 sql:variable() 的跨網域查詢

下列查詢是「範例:查詢以 xml 資料類型方法為基礎的計算的資料行」中的查詢修改版本。在下列版本中,會使用 SQL 變數 @isbn 來傳遞這個特殊的 ISBN。將常數置換成 sql:variable() 之後,就可以使用該查詢來搜尋任何 ISBN,而不只是 ISBN 為 0-7356-1588-2 的 ISBN。

DECLARE @isbn varchar(20)
SET     @isbn = '0-7356-1588-2'
SELECT  xCol
FROM    T
WHERE   xCol.exist ('/book/@ISBN[. = sql:variable("@isbn")]') = 1

sql:column() 的用法類似,且提供更多的好處。因為有以成本為考量的查詢最佳化工具,在資料行上使用索引會更有效率。此外,計算的資料行可能會儲存已升級的屬性。

提供原生 XML 支援的目錄檢視

目錄檢視的存在是為了提供有關 XML 用法的中繼資料資訊。下節中將有部份討論。

XML 索引

XML 索引項目出現在目錄檢視 sys.indexes 中,索引「類型」為 3。名稱資料行包含 XML 索引的名稱。

XML 索引也會記錄在目錄檢視 sys.xml_indexes 中。其中包含 sys.indexes 的所有資料行,以及對 XML 索引有助益的一些特定資料行。資料行 secondary_type 中的 NULL 值是指主要 XML 索引;'P'、'R' 和 'V' 這三個值分別代表 PATH、PROPERTY 和 VALUE 次要 XML 索引。

您可以在資料表值的函數 sys.dm_db_index_physical_stats 中找到 XML 索引的空間使用情況。其提供所有索引類型的資訊,例如:所佔用的磁碟分頁數量、平均資料列大小 (位元組),以及記錄的數量。另外還包含 XML 索引。每個資料庫分割區都有此資訊。XML 索引使用相同的基底資料表分割配置及分割函數。

擷取 XML 結構描述集合

XML 結構描述集合會列舉在目錄檢視 sys.xml_schema_collections 中。XML 結構描述集合 "sys" 是由系統定義的。其包含預先定義的命名空間,您不需要明確地將其載入,即可用在所有使用者自訂的 XML 結構描述集合中。此清單包含 xml、xs、xsi、fn 及 xdt 的命名空間。另外二個目錄檢視為 sys.xml_schema_namespaces:列舉出每個 XML 結構描述集合中的所有命名空間;以及 sys.xml_components:列舉出每個 XML 結構描述中的所有 XML 結構描述元件。

內建函數 XML_SCHEMA_NAMESPACE (schemaName、XmlSchemacollectionName、namespace-uri) 會產生 xml 資料類型執行個體。此執行個體包含 XML 結構描述集合中所包含之結構描述的 XML 結構描述片段 (預先定義的 XML 結構描述除外)。

您可以用下列方法來列舉 XML 結構描述集合的內容:

  • 在 XML 結構描述集合的適當目錄檢視上撰寫 Transact-SQL 查詢。
  • 使用內建函數 XML_SCHEMA_NAMESPACE()。您可以將 xml 資料類型方法套用在此函數的輸出上。但是您不能修改基礎 XML 結構描述。

如下列範例所示。

範例:列舉 XML 結構描述集合中的 XML 命名空間

針對 XML 結構描述集合 "myCollection" 來使用下列查詢:

SELECT XSN.name
FROM    sys.xml_schema_collections XSC JOIN sys.xml_schema_namespaces XSN
    ON (XSC.xml_collection_id = XSN.xml_collection_id)
WHERE    XSC.name = 'myCollection'   
範例:列舉 XML 結構描述集合的內容

下列陳述式會列舉關聯式結構描述 dbo 中之 XML 結構描述集合 "myCollection" 的內容。

SELECT XML_SCHEMA_NAMESPACE (N'dbo', N'myCollection')

您可以將目標命名空間指定為 XML_SCHEMA_NAMESPACE() 的第三個引數,以 xml 資料類型執行個體的型式來取得集合中的個別 XML 結構描述。如下列範例所示。

範例:從 XML 結構描述集合輸出指定的結構描述

下列陳述式會從關聯式結構描述 dbo 中的 XML 結構描述集合 "myCollection",輸出含有目標命名空間 "https://www.microsoft.com/books" 的 XML 結構描述。

SELECT XML_SCHEMA_NAMESPACE (N'dbo', N'myCollection', 
N'https://www.microsoft.com/books')

查詢 XML 結構描述

您可以用下列方法來查詢您已載入至 XML 結構描述集合的 XML 結構描述:

  • 在 XML 結構描述命名空間的目錄檢視上撰寫 Transact-SQL 查詢。
  • 建立一個包含 xml 資料類型資料行的資料表來儲存您的 XML 結構描述,並將其載入至 XML 類型系統。您可以使用 xml 資料類型方法來查詢 XML 資料行。您也可以在此資料行上建立 XML 索引。然而,使用這個方法時,應用程式必須維護儲存在 XML 資料行中之 XML 結構描述與 XML 類型系統之間的一致性。例如,若您從 XML 類型系統中卸除 XML 結構描述命名空間,就必須也將它從資料表中卸除,以維持一致性。

請參閱

參考

管理伺服器上的 XML 結構描述集合
對 XML 資料類型進行 XQuery 函數

概念

XML 資料類型

其他資源

sys.dm_db_index_physical_stats
全文檢索搜尋簡介

說明及資訊

取得 SQL Server 2005 協助