示例:聯合類型上的運算符
加法運算"+"要求精確的操作數類型,以至於表達式 (//r)[1] + 1 對上述元素 的類型定義返回靜態錯誤。可以解決該問題的一種改寫方式是 (//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[1]', 'nvarchar(50)') FirstName,
nref.value('last-name[1]', 'nvarchar(50)') LastName
FROM T CROSS APPLY xCol.nodes('//author') AS R(nref)
WHERE nref.exist('.[first-name != "David"]') = 1
在該示例中,nodes('//author') 會生成一個由對每個 XML 實例的 元素的引用組成的行集。通過相對於這些引用對 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() 會創建內存中的表示形式,並使用工作表而不是查詢處理器。它依賴於 MSXML 3.0 的 XPath 1.0 處理器而不是 XQuery 引擎。工作表不在對 OpenXml() 的多個調用中共享(即使是在同一個 XML 實例上)。這限制了它的可伸縮性。在未指定 WITH 子句時,可以通過 OpenXml() 來訪問 XML 數據的邊緣表格式。而且,還可以通過它使用 XML 值在單獨的"溢出"列中的剩余部分。
nodes() 和 value() 函數的組合可以有效地使用 XML 索引。因此,這一組合可以表現出比 OpenXML 更高的可伸縮性。
使用 FOR XML 從行集中生成 XML
通過新的 TYPE 指令,可以使用 FOR XML 從行集中生成 XML 數據類型實例。
可以將結果賦給 XML 數據類型列、變量或參數。而且,可以將 FOR XML 嵌套以便生成任意層次結構。這使得嵌套的 FOR XML 比 FOR XML EXPLICIT 更加便於編寫,但是對於較深的層次結構,它的性能可能不太好。FOR XML 還引入了新的 PATH 模式,該模式指定列的值應該出現在 XML 樹中的哪個路徑。
可以使用新的 FOR XML TYPE 指令,通過 SQL 語法來定義關系數據上的只讀 XML 視圖。可以通過 SQL 語句和嵌入式 XQuery 來查詢該視圖,如下面的示例所示。例如,您可以在存儲過程中引用此類 SQL 視圖。
示例:返回生成的 XML 數據類型的 SQL 視圖
下面的 SQL 視圖定義可在一個關系列 (pk) 以及從一個 XML 列中檢索到的書籍作者上創建一個 XML 視圖:
CREATE VIEW V (XMLVal) AS
SELECT pk, xCol.query('/book/author')
FROM T
FOR XML AUTO, TYPE
視圖 V 包含一個行,該行只有一個列:XML 類型的 xmlValtype。可以像查詢常規的 XML 數據類型實例那樣查詢它。例如,下面的查詢將返回名字為"David"的作者:
SELECT XMLVal.query('//author[first-name = "David"]')
FROM V
SQL 視圖定義在某種程度上類似於使用帶有批注的架構創建的 XML 視圖。然而,二者之間存在重要的區別。SQL 視圖定義是只讀的,並且必須通過嵌入式 XQuery 來操作;而使用帶有批注的架構的 XML 視圖則不是這樣。而且,SQL 視圖在應用 XQuery 表達式之前生成 XML 結果,而 XML 視圖上的 XPath 查詢在基礎表上計算 SQL 查詢。
添加業務邏輯
可以用多種方式將業務邏輯添加到 XML 數據中:
• 您可以編寫行或列約束,在插入和修改 XML 數據的過程中實施特定於域的約束。
• 您可以在 XML 列上編寫相應的觸發器,使其當您在該列中插入或更新值時引發。該觸發器可以包含特定於域的驗證規則,或者填充屬性表。
• 可以使用托管代碼編寫 SQLCLR 函數並向其傳遞 XML 值,並且使用由 System.Xml 命名空間提供的 XML 處理功能。這方面的一個例子是將 XSL 轉換應用於 XML 數據,如下所示。您還可以將 XML 反序列化為一個或多個托管類,並且使用托管代碼來操作它們。
• 您可以編寫 T-SQL 存儲過程和函數,激活 XML 列上的處理以滿足您的業務需要。
示例:應用 XSL 轉換
考慮 CLR 函數 TransformXml(),它接受一個 XML 數據類型實例和一個存儲在文件中的 XSL 轉換,將該轉換應用於 XML 數據,並且在結果中返回轉換後的 XML。用 C# 編寫的主干函數如下所示:
在注冊該程序集,並且創建了對應於 TransformXML() 的用戶定義 T-SQL 函數 SqlXslTransform() 之後,就可以像在下面的查詢中那樣從 T-SQL 中調用該函數:
SELECT SqlXslTransform (xCol, 'C:\yukon\xsltransform.xsl')
FROM T
WHERE xCol.exist('/book/title/text()[contains(.,"custom")]') =1
查詢結果包含轉換後的 XML 的行集。
SQLCLR 打開了一個全新的世界,可以使用它將 XML 數據分解到表或屬性提升中,並使用 System.Xml 命名空間中的托管類來查詢 XML 數據。有關詳細信息,請參閱 SQL Server 2005 和 Microsoft Visual Studio"Whidbey"聯機圖書。
返回頁首
跨域查詢
當您的數據同時駐留在關系列和 XML 數據類型列中時,您可能希望編寫將關系數據處理和 XML 數據處理結合起來的查詢。例如,您可以使用 FOR XML 將關系列和 XML 列中的數據轉換為 XML 數據類型實例,然後使用 XQuery 對其進行查詢。相反,可以從 XML 值生成行集(請參閱用法),並使用 T-SQL 對其進行查詢。
編寫跨域查詢的更為方便和有效的方法是在 XQuery 或 XML DML 表達式內使用 SQL 變量或列的值:
• 可以在 XQuery 或 XML DML 表達式中,通過 sql:variable() 來使用 SQL 變量的值。
• 可以在 XQuery 或 XML DML 表達式中,通過 sql:column() 來使用關系列中的值。
• 該方法使應用程序可以將查詢參數化,如下面的示例所示。然而,不允許在 sql:variable() 和 sql:column() 中使用 XML 和用戶定義的類型。
示例:使用 sql:variable() 的跨域查詢
下面的查詢是對示例:基於 XML 數據類型方法的計算列上的查詢中顯示的查詢進行修改後得到的版本。在該版本中,使用 SQL 變量 @isbn 傳入感興趣的 ISBN。通過將常量替換為 sql:variable(),可以使用該查詢來搜索任意 ISBN,而不僅是其 ISBN 為 0-7356-1588-2 的那個。
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 索引
XML 索引項出現在目錄視圖 sys.indexes 中,索引"type"為 3。"name"列包含 XML 索引的名稱。
XML 索引還被記錄在目錄視圖 sys.xml_indexes 中,它包含 sys.indexes 的所有列以及一些對 XML 索引有意義的特殊列。列"secondary_type"中的值 NULL 表示主 XML 索引;值"P"、"R"和"V' "分別代表 PATH、PROPERTY 和 VALUE 輔助 XML 索引。
XML 索引的空間利用率可以在表值函數 sys.fn_indexinfo() 中找到。該函數會提供許多信息,例如,所占用的磁盤頁數、平均行大小(字節)、記錄數以及所有索引類型(包括 XML 索引)的其他信息。對於每個數據庫分區都會提供這些信息;XML 索引使用基表的相同分區方案和分區函數。
示例:XML 索引的空間利用率
SELECT sum(Pages)
FROM sys.fn_indexinfo ('T', 'idx_xCol_Path' , DEFAULT, 'DETAILED')
這會產生表 T 中的 XML 索引 idx_xCol_Path 在所有分區中占用的磁盤頁數。如果不使用 sum() 函數,結果將返回每個分區的磁盤頁利用率。
檢索 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 架構集合的適當目錄視圖上編寫 T-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"中輸出目標命名空間為"http://www.microsoft.com/books"的 XML 架構。
SELECT XML_SCHEMA_NAMESPACE (N'dbo', N'myCollection',
N'http://www.microsoft.com/books')
查詢 XML 架構
如果您需要查詢已經加載到 XML 架構集合中的 XML 架構,可以采用下列方式:
• 在 XML 架構命名空間的目錄視圖上編寫 T-SQL 查詢。
• 除了將 XML 架構加載到 XML 類型系統中以外,創建一個包含 XML 數據類型列的表來存儲 XML 架構。您可以使用 XML 數據類型方法來查詢 XML 列。而且,您可以在該列上生成 XML 索引。然而,需要由應用程序來維護存儲在 XML 列中的 XML 架構與存儲在 XML 類型系統中的 XML 架構之間的一致性。例如,如果您從 XML 類型系統中刪除了 XML 架構命名空間,則還必須從表中刪除該命名空間以保持一致性。