該解決方案包括以下步驟:(a) 定義 CLR 類 SqlReaderBase,它實現了 ISqlReader,並且通過在 XML 實例上應用路徑表達式來生成流式表值輸出;(b) 創建一個程序集和一個 T-SQL 用戶定義函數 (UDF) 來激活該 CLR 類;(c) 使用 UDF 定義插入、更新和刪除觸發器,以維護屬性表。
首先,創建流式 CLR 函數,其主干如下所示。XML 數據類型被公開為 ADO.Net 中的托管類 SqlXml;它支持返回 XMLReader 的方法 CreateReader()。
接下來,創建一個程序集,以及一個與 CLR 函數 streaming_xml_tvf 對應的 T-SQL 用戶定義函數 SQL_streaming_xml_tvf(未顯示)。該 UDF 用於定義表值函數 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
最後,定義觸發器,如示例創建觸發器以填充屬性表中所示,但用函數 CLR_udf_XML2Table 替換 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 架構。XML 架構集合中的單獨 XML 架構由其目標命名空間標識。
XML 架構集合是使用 CREATE XML SCHEMA COLLECTION 語法創建的,並且提供了一個或多個 XML 架構。可以向現有 XML 架構中添加更多的 XML 架構組件,並且可以使用 ALTER XML SCHEMA COLLECTION 語法向 XML 架構集合中添加更多的架構。可以使用 SQL Server 2005 中的安全模型像任何 SQL 對象那樣保證 XML 架構集合的安全。
多類型化列
XML 架構集合 C 按照多個 XML 架構將 XML 列 xCol 類型化。此外,標志 DOCUMENT 或 CONTENT 分別指定 XML 樹或片段是否可以存儲在列 xCol 中。
對於 DOCUMENT,每個 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 或圖像列中,可以使用 DTS 等將表導入到 SQL Server 2005 數據庫中。使用 ALTER TABLE 語句將列類型更改為 XML。
• 可以使用 bcp out 批量復制 SQL Server 2000 中的數據,使用 bcp in 將數據批量插入到 SQL Server 2005 數據庫中。
• 如果您將數據存儲在 SQL Server 2000 數據庫的關系列中,請創建一個帶有一個 ntext 列的新表,同時根據需要在該表中創建一個主鍵列以用作行標識符。使用客戶端編程檢索在服務器中通過 FOR XML 生成的 XML,並且將其寫入 ntext 列。然後,使用上述技巧將數據傳輸到 SQL Server 2005 數據庫。您可以選擇將 XML 直接寫入 SQL Server 2005 數據庫的 XML 列中。
示例:將列類型更改為 XML
假設您需要將表 R 中的 [n]text 或圖像列 XYZ 的類型更改為非類型化 XML。下面的語句可執行此類更改:
ALTER TABLE R ALTER COLUMN XYZ XML
• 如果需要,可以通過指定一個 XML 架構集合將目標類型化為 XML。
批量加載 XML 數據
可以使用 SQL Server 中的批量加載功能(如 bcp),將 XML 數據批量加載到服務器中。通過 OPENROWSET 可以將文件中的數據加載到 XML 列中。下面的示例闡明了這一點。
示例:從文件中加載 XML
該示例說明了如何在表 T 中插入行。XML 列的值作為 CLOB 從文件 C:\yukon\xmlfile.XML 中加載,並且整數列被提供了值 10。
INSERT INTO T
SELECT 10, xCol
FROM (SELECT *
FROM OPENROWSET (BULK 'C:\Yukon\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 ((''+ vcdoc)
AS VARBINARY (MAX))
AS XML)
Xquery 與類型推理
嵌入到 T-SQL 中的 XQuery (http://www.w3.org/TR/xquery/) 語言支持查詢 XML 數據類型。該語言正在由 WWW 聯合會 (W3C) 進行開發(在本文作者最後一次召集起來撰寫本文時),並且所有主要數據庫供應商(包括 Microsoft)都參與了開發工作。它包括了 XPath 2.0 作為導航語言。同時,還提供了針對 XML 數據類型的數據修改語言構造。有關 SQL Server 2005 中支持的 Xquery 構造、函數和運算符的信息,請參閱聯機圖書。
錯誤模型
具有語法錯誤的 Xquery 表達式和 XML DML 語句會返回編譯錯誤。編譯階段會檢查 XQuery 表達式和 DML 語句的靜態類型正確性,並且對於類型化 XML 使用 XML 架構進行類型推理。如果某個表達式可能在運行時由於類型安全沖突而失敗,它會引發靜態類型錯誤。靜態錯誤的例子有將字符串添加到整數以及在不存在的節點中查詢類型化數據。
與 W3C 標准有所不同的是,XQuery 運行時錯誤被轉換為可以作為空 XML 或 NULL 傳播給查詢結果的空序列(具體取決於調用上下文)。
通過顯式轉換到正確的類型,用戶可以避免靜態錯誤,盡管運行時轉換錯誤將被轉化為空序列。
下面的小節將詳細討論類型檢查。
唯一性檢查
如果編譯器無法確定能否在運行時保證唯一性,則要求唯一性的定位步驟、函數參數和運算符(例如 eq)將返回錯誤。問題經常出現在非類型化數據上。例如,屬性查找要求存在唯一的父元素;能夠選擇單個父節點的序號即可滿足需要。計算 node()-value() 組合(請參閱 Value()、Nodes() 和 OpenXML())以提取屬性值,這可能不需要指定序號,如下面的示例所示。
示例:已知的唯一性
在該示例中,nodes() 方法為每個 元素生成一個單獨的行。(有關 nodes() 方法的詳細說明,請參閱 Value()、Nodes() 和 OpenXML())。在 節點上進行求值的 value() 方法會提取 @genre(它作為屬性具有唯一性)的值。
SELECT nref.value('@genre', 'varchar(max)') LastName
FROM T CROSS APPLY xCol.nodes('//book') AS R(nref)
XML 架構用於對類型化 XML 進行類型檢查。如果節點被指定為 XML 架構中的唯一節點,則編譯器將使用該信息,並且不會出現任何錯誤。否則,需要能夠選擇單個節點的序號。特別地,如果使用子代或自身軸 (//),例如 /book//title,則會丟失