在 FOR XML 子句中,您可以要求您的查詢將內嵌結構描述連同查詢結果一起傳回。 如果您要的是 XDR 結構描述,請在 FOR XML 子句中使用 XMLDATA 關鍵字。 而如果您要的是 XSD 結構描述,則請使用 XMLSCHEMA 關鍵字。
本主題描述 XMLSCHEMA 關鍵詞,並說明產生的內嵌 XSD 架構結構。 以下是您在要求內嵌架構時的限制事項:
您只能在 RAW 和 AUTO 模式中指定 XMLSCHEMA,但不能在 EXPLICIT 模式中指定。
如果巢狀 FOR XML 查詢指定 TYPE 指示詞,則查詢結果的類型為
xml,而且此結果會視為不具類型的 XML 數據的實例。 如需詳細資訊,請參閱 XML 資料 (SQL Server)。
當您在 FOR XML 查詢中指定 XMLSCHEMA 時,會同時收到結構描述和 XML 資料做為查詢結果。 此資料的每個頂層元素利用預設命名空間宣告來參照上一個模式,該宣告再指向內嵌模式的目標命名空間。
例如:
<xsd:schema targetNamespace="urn:schemas-microsoft-com:sql:SqlRowSet1" xmlns:schema="urn:schemas-microsoft-com:sql:SqlRowSet1" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:sqltypes="https://schemas.microsoft.com/sqlserver/2004/sqltypes" elementFormDefault="qualified">
<xsd:import namespace="https://schemas.microsoft.com/sqlserver/2004/sqltypes" schemaLocation="https://schemas.microsoft.com/sqlserver/2004/sqltypes/sqltypes.xsd" />
<xsd:element name="Production.ProductModel">
<xsd:complexType>
<xsd:attribute name="ProductModelID" type="sqltypes:int" use="required" />
<xsd:attribute name="Name" use="required">
<xsd:simpleType sqltypes:sqlTypeAlias="[AdventureWorks2012].[dbo].[Name]">
<xsd:restriction base="sqltypes:nvarchar" sqltypes:localeId="1033" sqltypes:sqlCompareOptions="IgnoreCase IgnoreKanaType IgnoreWidth" sqltypes:sqlSortId="52">
<xsd:maxLength value="50" />
</xsd:restriction>
</xsd:simpleType>
</xsd:attribute>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<Production.ProductModel xmlns="urn:schemas-microsoft-com:sql:SqlRowSet1" ProductModelID="1" Name="Classic Vest" />
此結果包含 XML 結構描述和 XML 結果。 結果 <ProductModel> 中的最上層元素會使用預設命名空間宣告 xmlns=“urn:schemas-microsoft-com:sql:SqlRowSet1” 來參考架構。
結果的結構描述部份可能包含了描述多個命名空間的多個結構描述文件。 至少會傳回下列兩份結構描述文件:
一份結構描述文件用於 Sqltypes 命名空間,並對其傳回基底 SQL 類型。
另一份結構描述文件描述 FOR XML 查詢結果的外觀。
此外,如果查詢結果中包含任何具型別的 xml 數據類型,則會包含與這些具型別的 xml 數據類型相關聯的模式。
在描述 FOR XML 結果外觀的結構描述文件中,目標命名空間包含固定部分,以及會自動遞增的數值部分。 此命名空間的格式如下所示,其中 n 是正整數。 例如,在上一個查詢中,urn:schemas-microsoft-com:sql:SqlRowSet1 就是目標命名空間。
urn:schemas-microsoft-com:sql:SqlRowSetn
每次執行都會導致結果中的目標命名空間發生改變,但這可能不是您想要的。 例如,如果您查詢產生的 XML,目標命名空間中的變更會要求您更新查詢。 您可在 XMLSCHEMA 選項加入 FOR XML 子句時,選擇性地指定目標命名空間。 產生的 XML 將會包含您所提供的命名空間,並且維持不變,不論您執行查詢多少次都一樣。
SELECT ProductModelID, Name
FROM Production.ProductModel
WHERE ProductModelID=1
FOR XML AUTO, XMLSCHEMA ('MyURI')
實體元素
若要討論針對查詢結果而產生之 XSD 結構描述結構的詳細資料,必須先說明實體元素
由 FOR XML 查詢所傳回之 XML 資料中的實體元素,是從資料表產生的元素,而非從資料行產生。 例如,下列 FOR XML 查詢會從 Person 資料庫中的 AdventureWorks2012 資料表傳回連絡資訊。
SELECT BusinessEntityID, FirstName
FROM Person.Person
WHERE BusinessEntityID = 1
FOR XML AUTO, ELEMENTS
以下是結果:
<Person>
<BusinessEntityID>1</BusinessEntityID>
<FirstName>Ken</FirstName>
</Person>
在此結果中,<Person> 是實體元素。 在 XML 結果中可能有多個實體元素,每一個元素在內嵌 XSD 結構描述中都有全域宣告。 例如,下列查詢擷取特定訂單的銷售訂單標頭和詳細資訊。
SELECT SalesOrderHeader.SalesOrderID, ProductID, OrderQty
FROM Sales.SalesOrderHeader, Sales.SalesOrderDetail
WHERE SalesOrderHeader.SalesOrderID = SalesOrderDetail.SalesOrderID
AND SalesOrderHeader.SalesOrderID=5001
FOR XML AUTO, ELEMENTS, XMLSCHEMA
因為此查詢指定 ELEMENTS 指示詞,所以產生的 XML 是元素中心的。 此查詢也指定 XMLSCHEMA 指示詞。 因此,會傳回嵌入式 XSD 結構描述。 以下是結果:
<xsd:schema targetNamespace="urn:schemas-microsoft-com:sql:SqlRowSet1" xmlns:schema="urn:schemas-microsoft-com:sql:SqlRowSet1" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:sqltypes="https://schemas.microsoft.com/sqlserver/2004/sqltypes" elementFormDefault="qualified">
<xsd:import namespace="https://schemas.microsoft.com/sqlserver/2004/sqltypes" schemaLocation="https://schemas.microsoft.com/sqlserver/2004/sqltypes/sqltypes.xsd" />
<xsd:element name="Sales.SalesOrderHeader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="SalesOrderID" type="sqltypes:int" />
<xsd:element ref="schema:Sales.SalesOrderDetail" minOccurs="0" maxOccurs="unbounded" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="Sales.SalesOrderDetail">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="ProductID" type="sqltypes:int" />
<xsd:element name="OrderQty" type="sqltypes:smallint" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
請注意下列項目是從上一個查詢而來:
在結果中, <
SalesOrderHeader> 和 <SalesOrderDetail> 是實體元素。 因此,它們會在架構中做全域宣告。 也就是說,宣告會出現在<Schema>元素的最上層。<
SalesOrderID>、ProductID<> 和 <OrderQty> 不是實體項目,因為它們會對應至數據行。 因為 ELEMENTS 指示詞的緣故,資料行的資料是以 XML 中的元素傳回。 這些被映射到實體元素複雜類型的本地元素。 請注意,如果未指定 ELEMENTS 指示詞,SalesOrderID、ProductID和OrderQty值會映射到相應實體元素的複雜型別的本機屬性。
屬性名稱衝突
以下討論是以 CustOrder 和 CustOrderDetail 資料表為基礎。 若要測試下列範例,請建立這些資料表並加入您自己的範例資料:
CREATE TABLE CustOrder (OrderID int primary key, CustomerID int)
GO
CREATE TABLE CustOrderDetail (OrderID int, ProductID int, Qty int)
GO
在 FOR XML 中,有時候相同的名稱會表示不同的屬性 (Property) 或屬性 (Attribute)。 例如,下列屬性中心的 RAW 模式查詢會產生兩個屬性,其名稱都是 OrderID。 這樣會產生錯誤。
SELECT CustOrder.OrderID,
CustOrderDetail.ProductID,
CustOrderDetail.OrderID
FROM dbo.CustOrder, dbo.CustOrderDetail
WHERE CustOrder.OrderID = CustOrderDetail.OrderID
FOR XML RAW, XMLSCHEMA
不過,因為可以接受有兩個具有相同名稱的元素,所以您可以藉由新增 ELEMENTS 指示詞來消除問題:
SELECT CustOrder.OrderID,
CustOrderDetail.ProductID,
CustOrderDetail.OrderID
from dbo.CustOrder, dbo.CustOrderDetail
where CustOrder.OrderID = CustOrderDetail.OrderID
FOR XML RAW, XMLSCHEMA, ELEMENTS
以下是結果。 請注意內嵌 XSD 結構描述中,OrderID 元素定義了兩次。 其中一個宣告將 minOccurs 設為 0,對應於 CustOrderDetail 資料表的 OrderID;第二個宣告對應於 CustOrder 資料表的 OrderID 主索引鍵資料行,其中的 minOccurs 預設為 1。
<xsd:schema targetNamespace="urn:schemas-microsoft-com:sql:SqlRowSet1" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:sqltypes="https://schemas.microsoft.com/sqlserver/2004/sqltypes" elementFormDefault="qualified">
<xsd:import namespace="https://schemas.microsoft.com/sqlserver/2004/sqltypes" schemaLocation="https://schemas.microsoft.com/sqlserver/2004/sqltypes/sqltypes.xsd" />
<xsd:element name="row">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="OrderID" type="sqltypes:int" />
<xsd:element name="ProductID" type="sqltypes:int" minOccurs="0" />
<xsd:element name="OrderID" type="sqltypes:int" minOccurs="0" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
元素名稱衝突
在 FOR XML 中,可以使用相同的名稱來表示兩個子元素。 例如,下列查詢會擷取產品的 ListPrice 和 DealerPrice 值,但此查詢對這兩個資料行指定相同的別名:Price。 因此,產生的資料列集將具有兩個相同名稱的資料行。
案例 1:兩個子元素都是非索引鍵資料行且類型相同,並且可以是 NULL
在下列查詢中,兩個子元素都是相同類型的非索引鍵的資料行,且可以是 NULL。
DROP TABLE T
go
CREATE TABLE T (ProductID int primary key, ListPrice money, DealerPrice money)
go
INSERT INTO T values (1, 1.25, null)
go
SELECT ProductID, ListPrice Price, DealerPrice Price
FROM T
for XML RAW, ELEMENTS, XMLSCHEMA
這是所產生的對應 XML。 以下只顯示內嵌式 XSD 的部分內容:
...
<xsd:schema targetNamespace="urn:schemas-microsoft-com:sql:SqlRowSet1" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:sqltypes="https://schemas.microsoft.com/sqlserver/2004/sqltypes" elementFormDefault="qualified">
<xsd:import namespace="https://schemas.microsoft.com/sqlserver/2004/sqltypes" />
<xsd:element name="row">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="ProductID" type="sqltypes:int" />
<xsd:element name="Price" type="sqltypes:money" minOccurs="0" maxOccurs="2" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<row xmlns="urn:schemas-microsoft-com:sql:SqlRowSet1">
<ProductID>1</ProductID>
<Price>1.2500</Price>
</row>
請注意內嵌 XSD 結構描述中的下列各項:
ListPrice 和 DealerPrice 都屬於相同類型
money,而且在資料表中都可以是 NULL。 因此,由於它們可能不會在產生的 XML 中傳回,所以具有 minOccurs=0 和 maxOccurs=2 之元素的複雜型別宣告><row中只有一個<Price>子元素。在結果中,因為
DealerPrice數據表中的值是 NULL,所以只會ListPrice以 <Price> 專案的形式傳回。 如果您將XSINIL參數新增至 ELEMENTS 指示詞,您會收到兩個對應到 DealerPrice 元素的,且其xsi:nil值設定為 TRUE 的元素<Price>。 您也會收到兩個<Price>子元素,屬性nillable設置皆為 TRUE,位於<row>複合型別定義中的內嵌 XSD 架構。 以下片段是部分結果:
...
<xsd:schema targetNamespace="urn:schemas-microsoft-com:sql:SqlRowSet1" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:sqltypes="https://schemas.microsoft.com/sqlserver/2004/sqltypes" elementFormDefault="qualified">
<xsd:import namespace="https://schemas.microsoft.com/sqlserver/2004/sqltypes" />
<xsd:element name="row">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="ProductID" type="sqltypes:int" nillable="1" />
<xsd:element name="Price" type="sqltypes:money" nillable="1" />
<xsd:element name="Price" type="sqltypes:money" nillable="1" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<row xmlns="urn:schemas-microsoft-com:sql:SqlRowSet1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ProductID>1</ProductID>
<Price>1.2500</Price>
<Price xsi:nil="true" />
</row>
案例 2:一個索引鍵資料行和一個相同類型的非索引鍵資料行
下列查詢說明同類型的一個索引鍵資料行和一個非索引鍵資料行。
CREATE TABLE T (Col1 int primary key, Col2 int, Col3 nvarchar(20))
go
INSERT INTO T VALUES (1, 1, 'test')
go
下列針對資料表 T 的查詢,為 Col1 和 Col2 指定了相同別名,其中 Col1 是不能為 Null 的主索引鍵,而 Col2 則可以是 Null。 這會產生兩個同層級元素,這些元素是<row>元素的子元素。
SELECT Col1 as Col, Col2 as Col, Col3
FROM T
FOR XML RAW, ELEMENTS, XMLSCHEMA
以下是結果。 以下只顯示內嵌的 XSD 結構的一部分:
...
<xsd:schema targetNamespace="urn:schemas-microsoft-com:sql:SqlRowSet1" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:sqltypes="https://schemas.microsoft.com/sqlserver/2004/sqltypes" elementFormDefault="qualified">
<xsd:import namespace="https://schemas.microsoft.com/sqlserver/2004/sqltypes" />
<xsd:element name="row">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="Col" type="sqltypes:int" />
<xsd:element name="Col" type="sqltypes:int" minOccurs="0" />
<xsd:element name="Col3" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="sqltypes:nvarchar"
sqltypes:localeId="1033"
sqltypes:sqlCompareOptions="IgnoreCase
IgnoreKanaType IgnoreWidth"
sqltypes:sqlSortId="52">
<xsd:maxLength value="20" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<row xmlns="urn:schemas-microsoft-com:sql:SqlRowSet1">
<Col>1</Col>
<Col>1</Col>
<Col3>test</Col3>
</row>
請注意,在內嵌 XSD 架構中, <Col> 對應至 Col2 的專案已將 minOccurs 設定為 0。
案例 3:兩個不同類型的元素,且對應的資料行可以是 NULL
下列查詢是針對案例 2 所顯示的範例資料表而指定:
SELECT Col1, Col2 as Col, Col3 as Col
FROM T
FOR XML RAW, ELEMENTS, XMLSCHEMA
下列查詢中,Col2 和 Col3 使用相同別名。 這會在結果中產生兩個名稱相同的同層級元素,且這兩個元素都是 <raw> 元素的子元素。 這兩個資料行屬於不同類型,而且兩者都可以是 NULL。 以下是結果。 只顯示出部分嵌入式 XSD 結構描述。
...
<xsd:schema targetNamespace="urn:schemas-microsoft-com:sql:SqlRowSet1" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:sqltypes="https://schemas.microsoft.com/sqlserver/2004/sqltypes" elementFormDefault="qualified">
<xsd:import namespace="https://schemas.microsoft.com/sqlserver/2004/sqltypes" />
<xsd:simpleType name="Col1">
<xsd:restriction base="sqltypes:int" />
</xsd:simpleType>
<xsd:simpleType name="Col2">
<xsd:restriction base="sqltypes:nvarchar" sqltypes:localeId="1033"
sqltypes:sqlCompareOptions="IgnoreCase
IgnoreKanaType IgnoreWidth" sqltypes:sqlSortId="52">
<xsd:maxLength value="20" />
</xsd:restriction>
</xsd:simpleType>
<xsd:element name="row">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="Col1" type="sqltypes:int" />
<xsd:element name="Col" minOccurs="0" maxOccurs="2" type="xsd:anySimpleType" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<row xmlns="urn:schemas-microsoft-com:sql:SqlRowSet1">
<Col1>1</Col1>
<Col xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:type="Col1">1</Col>
<Col xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:type="Col2">test</Col>
</row>
請注意內嵌 XSD 結構描述中的下列各項:
由於 Col2 和 Col3 可以是 NULL,因此 <
Col> 元素宣告會將 minOccurs 指定為 0,maxOccurs 指定為 2。由於這兩個 <
Col> 元素都是同層級專案,因此模式中有一個元素宣告。 同時,因為兩元素也都是不同類型 (雖然都是簡單類型),所以結構描述中的元素類型是xsd:anySimpleType。 在結果中,每一個執行個體類型是由xsi:type屬性加以識別。在結果中,元素的每個實例 <
Col> 都會使用xsi:type屬性來參考其實例類型。