Generowanie wbudowanego schematu XSD
Dotyczy:programu SQL Server
Azure SQL Database
W klauzuli FOR XML możesz zażądać, aby zapytanie zwróciło wbudowany schemat wraz z wynikami zapytania. Jeśli chcesz uzyskać schemat XDR, użyj słowa kluczowego XMLDATA w klauzuli FOR XML. Jeśli chcesz użyć schematu XSD, użyj słowa kluczowego XMLSCHEMA.
W tym artykule opisano słowo kluczowe XMLSCHEMA i objaśniono strukturę wbudowanego schematu XSD. Poniżej przedstawiono ograniczenia dotyczące żądań schematów wbudowanych:
Można określić tylko XMLSCHEMA w trybie RAW i AUTO, a nie w trybie EXPLICIT.
Jeśli zagnieżdżone zapytanie FOR XML określa dyrektywę TYPE, wynikiem zapytania jest typu XML, a ten wynik jest traktowany jako wystąpienie niezatypowanych danych XML. Aby uzyskać więcej informacji, zobacz XML Data (SQL Server).
Po określeniu xmlSCHEMA w zapytaniu FOR XML otrzymasz zarówno schemat, jak i dane XML, wynik zapytania. Każdy element najwyższego poziomu danych odnosi się do poprzedniego schematu przy użyciu domyślnej deklaracji przestrzeni nazw, która z kolei odwołuje się do docelowej przestrzeni nazw schematu wbudowanego.
Na przykład:
<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="[AdventureWorks2022].[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" />
Wynik zawiera schemat XML i wynik XML. Element najwyższego poziomu <ProductModel>
w wyniku przy użyciu domyślnej deklaracji przestrzeni nazw xmlns="urn:schemas-microsoft-com:sql:SqlRowSet1" odwołuje się do schematu.
Część schematu wyniku może zawierać wiele dokumentów schematu, które opisują wiele przestrzeni nazw. Zwracane są co najmniej dwa następujące dokumenty schematu:
Jeden dokument schematu dla przestrzeni nazw Sqltypes, z której zwracane są podstawowe typy SQL.
Inny dokument schematu opisujący kształt wyniku zapytania FOR XML.
Ponadto, jeśli w wyniku zapytania znajdują się jakiekolwiek typowane typy danych xml, uwzględniane są schematy skojarzone z tymi typowanymi typami danych xml.
Docelowa przestrzeń nazw dokumentu schematu, która opisuje kształt wyniku FOR XML, zawiera stałą część i część liczbową, która zwiększa się automatycznie. Format tej przestrzeni nazw jest wyświetlany w poniższym miejscu, w którym n jest dodatnią liczbą całkowitą. Na przykład w poprzednim zapytaniu urn:schemas-microsoft-com:sql:SqlRowSet1 jest docelową przestrzenią nazw.
urn:schemas-microsoft-com:sql:SqlRowSetn
Zmiana docelowych przestrzeni nazw w wyniku z jednego uruchomienia na inne może nie być pożądana. Jeśli na przykład wykonasz zapytanie dotyczące wynikowego kodu XML, zmiana docelowej przestrzeni nazw będzie wymagać zaktualizowania zapytania. Opcjonalnie można określić docelową przestrzeń nazw, gdy opcja XMLSCHEMA zostanie dodana w klauzuli FOR XML. Wynikowy kod XML będzie zawierać podaną przestrzeń nazw i pozostanie taki sam, niezależnie od tego, ile razy uruchamiasz zapytanie.
SELECT ProductModelID, Name
FROM Production.ProductModel
WHERE ProductModelID=1
FOR XML AUTO, XMLSCHEMA ('MyURI');
Elementy jednostki
Aby omówić szczegóły struktury schematu XSD wygenerowanej dla wyniku zapytania, należy najpierw opisać element jednostki
Element jednostki w danych XML zwracanych przez zapytanie FOR XML jest elementem generowanym na podstawie tabeli, a nie z kolumny. Na przykład następujące zapytanie FOR XML zwraca informacje kontaktowe z tabeli Person
w bazie danych AdventureWorks2022
.
SELECT BusinessEntityID, FirstName
FROM Person.Person
WHERE BusinessEntityID = 1
FOR XML AUTO, ELEMENTS;
Jest to wynik:
<Person>
<BusinessEntityID>1</BusinessEntityID>
<FirstName>Ken</FirstName>
</Person>
W związku z tym <Person>
jest elementem jednostki. W wyniku XML może znajdować się wiele elementów jednostki, a każda z nich ma deklarację globalną w wbudowanym schemacie XSD. Na przykład następujące zapytanie pobiera nagłówek zamówienia sprzedaży i szczegółowe informacje dotyczące określonego zamówienia.
SELECT SalesOrderHeader.SalesOrderID, ProductID, OrderQty
FROM Sales.SalesOrderHeader, Sales.SalesOrderDetail
WHERE SalesOrderHeader.SalesOrderID = SalesOrderDetail.SalesOrderID
AND SalesOrderHeader.SalesOrderID=5001
FOR XML AUTO, ELEMENTS, XMLSCHEMA;
Ponieważ zapytanie określa dyrektywę ELEMENTS, wynikowy kod XML jest skoncentrowany na elementach. Zapytanie określa również dyrektywę XMLSCHEMA. W związku z tym zwracany jest wbudowany schemat XSD. Jest to wynik:
<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>
Zwróć uwagę na następujące elementy z poprzedniego zapytania:
W rezultacie
<SalesOrderHeader>
i<SalesOrderDetail>
są elementami jednostki. W związku z tym są one globalnie deklarowane w schemacie. Oznacza to, że deklaracja jest wyświetlana na najwyższym poziomie wewnątrz elementu<Schema>
.<SalesOrderID>
,<ProductID>
i<OrderQty>
nie są elementami jednostki, ponieważ odnoszą się do kolumn. Dane kolumny są zwracane jako elementy w kodzie XML ze względu na dyrektywę ELEMENTS. Są one mapowane na lokalne elementy typu złożonego elementu jednostki. Jeśli dyrektywa ELEMENTS nie zostanie określona, wartościSalesOrderID
,ProductID
iOrderQty
są mapowane na atrybuty lokalne odpowiadającego typu złożonego elementu jednostki.
Starcia nazw atrybutów
Poniższa dyskusja opiera się na tabelach CustOrder
i CustOrderDetail
. Aby przetestować następujące przykłady, utwórz te tabele i dodaj własne przykładowe dane:
CREATE TABLE CustOrder (OrderID int primary key, CustomerID int);
GO
CREATE TABLE CustOrderDetail (OrderID int, ProductID int, Qty int);
GO
W obszarze FOR XML ta sama nazwa jest czasami używana do wskazywania różnych właściwości, atrybutów. Na przykład następujące zapytanie trybu RAW skoncentrowane na atrybutach generuje dwa atrybuty o takiej samej nazwie, OrderID. Spowoduje to wygenerowanie błędu.
SELECT CustOrder.OrderID,
CustOrderDetail.ProductID,
CustOrderDetail.OrderID
FROM dbo.CustOrder, dbo.CustOrderDetail
WHERE CustOrder.OrderID = CustOrderDetail.OrderID
FOR XML RAW, XMLSCHEMA;
Jednak ze względu na to, że dopuszczalne jest posiadanie dwóch elementów o tej samej nazwie, można wyeliminować problem, dodając dyrektywę ELEMENTS:
SELECT CustOrder.OrderID,
CustOrderDetail.ProductID,
CustOrderDetail.OrderID
from dbo.CustOrder, dbo.CustOrderDetail
where CustOrder.OrderID = CustOrderDetail.OrderID
FOR XML RAW, XMLSCHEMA, ELEMENTS;
Jest to wynik. Zwróć uwagę, że w wbudowanym schemacie XSD element OrderID jest definiowany dwa razy. Jedna z deklaracji ma wartość minOccurs ustawioną na 0, odpowiadającą identyfikatorowi OrderID z tabeli CustOrderDetail, a druga mapuje kolumnę klucza podstawowego OrderID tabeli CustOrder
, w której wartość minOccurs jest domyślnie równa 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>
Konflikty nazw elementów
W obszarze FOR XML można użyć tej samej nazwy, aby wskazać dwa podelementy. Na przykład następujące zapytanie pobiera wartości ListPrice i DealerPrice produktów, ale zapytanie określa ten sam alias Price dla tych dwóch kolumn. W związku z tym wynikowy zestaw wierszy będzie miał dwie kolumny o tej samej nazwie.
Przypadek 1: Oba podelementy są kolumnami niebędącymi kluczami tego samego typu i mogą mieć wartość NULL
W poniższym zapytaniu oba podelementy są kolumnami niebędącymi kluczami tego samego typu i mogą mieć wartość 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;
Jest to odpowiedni wygenerowany kod XML. Wyświetlany jest tylko ułamek wbudowanego 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>
Zwróć uwagę na następujące elementy w wbudowanym schemacie XSD:
Zarówno ListPrice, jak i DealerPrice są tego samego typu,
money
, i obie mogą być NULL w tabeli. W związku z tym, ponieważ nie mogą być zwracane w wynikowym kodzie XML, w deklaracji typu złożonego elementu<row>
, który maminOccurs=0
imaxOccurs=2
, istnieje tylko jeden element podrzędny<Price>
.W rezultacie, ponieważ wartość
DealerPrice
ma wartość NULL w tabeli, zwracana jest tylkoListPrice
jako element<Price>
. Jeśli dodasz parametrXSINIL
do dyrektywy ELEMENTS, otrzymasz oba elementy, które mają wartośćxsi:nil
ustawioną na TRUE dla elementu<Price>
odpowiadającego cenie dealera. Otrzymasz również dwa<Price>
elementy podrzędne w złożonej definicji typu<row>
w wbudowanym schemacie XSD, z atrybutemnillable
ustawionym na TRUE dla obu. Ten fragment jest wynikiem częściowym:
...
<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>
Przypadek 2: jeden klucz i jedna kolumna niekluczowa tego samego typu
Poniższe zapytanie ilustruje jeden klucz i jedną kolumnę inną niż klucz tego samego typu.
CREATE TABLE T (Col1 int primary key, Col2 int, Col3 nvarchar(20));
GO
INSERT INTO T VALUES (1, 1, 'test');
GO
Poniższe zapytanie względem tabeli T określa ten sam alias dla kolumn Col1 i Col2, gdzie Col1 jest kluczem podstawowym i nie może mieć wartości null, a kolumna Col2 może mieć wartość null. Spowoduje to wygenerowanie dwóch elementów siostrzanych, które są elementami podrzędnymi elementu <row>
.
SELECT Col1 as Col, Col2 as Col, Col3
FROM T
FOR XML RAW, ELEMENTS, XMLSCHEMA
Jest to wynik. Wyświetlany jest tylko fragment wbudowanego schematu 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>
Zwróć uwagę na wbudowany schemat XSD, że element <Col>
odpowiadający kolumnie Col2 ma wartość minOccurs ustawioną na 0.
Przypadek 3: Oba elementy różnych typów i odpowiadające im kolumny mogą mieć wartość NULL
Następujące zapytanie jest określone względem przykładowej tabeli pokazanej w przypadku 2:
SELECT Col1, Col2 as Col, Col3 as Col
FROM T
FOR XML RAW, ELEMENTS, XMLSCHEMA;
W poniższym zapytaniu kolumny Col2 i Col3 mają te same aliasy. Spowoduje to wygenerowanie dwóch elementów równorzędnych, które mają taką samą nazwę i które w wyniku są elementami podrzędnymi elementu <raw>
. Obie te kolumny mają różne typy, a oba mogą mieć wartość NULL. Jest to wynik. Wyświetlany jest tylko częściowo wbudowany schemat 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>
Zwróć uwagę na następujące elementy w wbudowanym schemacie XSD:
Ponieważ zarówno Col2, jak i Col3 mogą być puste, deklaracja elementu
<Col>
określa minOccurs jako 0 i maxOccurs jako 2.Ponieważ oba elementy
<Col>
są elementami równorzędnymi, istnieje jedna deklaracja elementu w schemacie. Ponadto, ponieważ oba elementy są różnych typów, choć oba są typami prostymi, typ elementu w schemacie toxsd:anySimpleType
. W wyniku każdy typ wystąpienia jest identyfikowany przez atrybutxsi:type
.W rezultacie każde wystąpienie elementu
<Col>
odwołuje się do jego typu wystąpienia przy użyciu atrybutuxsi:type
.