Share via


XSD-Inlineschemagenerierung

In einer FOR XML-Klausel können Sie anfordern, dass die Abfrage ein Inlineschema zusammen mit den Abfrageergebnissen zurückgibt. Wenn Sie ein XDR-Schema wünschen, verwenden Sie das XMLDATA-Schlüsselwort in der FOR XML-Klausel. Wenn Sie ein XSD-Schema wünschen, verwenden Sie das XMLSCHEMA-Schlüsselwort.

Dieses Thema beschreibt das XMLSCHEMA-Schlüsselwort und erläutert die Struktur des sich ergebenden XSD-Inlineschemas. Die folgenden Einschränkungen gelten beim Anfordern von Inlineschemas:

  • Sie können XMLSCHEMA nur im RAW- und AUTO-Modus angeben, nicht im EXPLICIT-Modus.

  • Wenn eine geschachtelte FOR XML-Abfrage die TYPE-Direktive angibt, ist das Abfrageergebnis vom Typ xml, und dieses Ergebnis wird als eine Instanz nicht typisierter XML-Daten behandelt. Weitere Informationen finden Sie unter Implementieren von XML in SQL Server.

Wenn Sie XMLSCHEMA in einer FOR XML-Abfrage angeben, erhalten Sie sowohl ein Schema als auch XML-Daten als Abfrageergebnis. Jedes Datenelement der obersten Ebene verweist mithilfe einer Standard-Namespacedeklaration auf das vorherige Schema, das seinerseits auf den Zielnamespace des Inlineschemas verweist.

Beispiel:

<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="[AdventureWorks].[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" />

Das Ergebnis enthält das XML-Schema und das XML-Ergebnis. Das <ProductModel>-Element der obersten Ebene im Ergebnis verweist mithilfe der Standard-Namespacedeklaration xmlns="urn:schemas-microsoft-com:sql:SqlRowSet1" auf das Schema.

Der Schemateil des Ergebnisses kann mehrere Schemadokumente enthalten, die mehrere Namespaces beschreiben. Es werden mindestens die beiden folgenden Schemadokumente zurückgegeben:

  • Ein Schemadokument für den Sqltypes-Namespace, für das die SQL-Basistypen zurückgegeben werden.

  • Ein weiteres Schemadokument, das die Form des FOR XML-Abfrageergebnisses beschreibt.

Wenn typisierte xml-Datentypen im Abfrageergebnis enthalten sind, werden die Schemas, die diesen typisierten xml-Datentypen zugeordnet sind, ebenfalls eingeschlossen.

Der Zielnamespace des Schemadokuments, das die Form des FOR XML-Ergebnisses beschreibt, enthält einen festen Teil und einen numerischen Teil, der automatisch inkrementiert wird. Das Format dieses Namespace wird im folgenden Beispiel gezeigt; dabei ist n eine positive ganze Zahl. In der vorherigen Abfrage ist z. B. urn:schemas-microsoft-com:sql:SqlRowSet1 der Zielnamespace.

urn:schemas-microsoft-com:sql:SqlRowSetn

Die Änderung in den Zielnamespaces, die zwischen den einzelnen Ausführungen auftritt, kann unerwünscht sein. Wenn Sie z. B. das sich ergebende XML abfragen, wird durch die Änderung im Zielnamespace eine Aktualisierung der Abfrage erforderlich. Sie können optional einen Zielnamespace angeben, wenn die Option XMLSCHEMA in der FOR XML-Klausel hinzugefügt wird. Das sich ergebende XML enthält den von Ihnen bereitgestellten Namespace und bleibt unabhängig davon gleich, wie häufig die Abfrage ausgeführt wird.

select ProductModelID, Name
from   Production.ProductModel
where ProductModelID=1
FOR XML AUTO, XMLSCHEMA ('MyURI')

Entitätselemente

Um die Einzelheiten der XSD-Schemastruktur behandeln zu können, die für das Abfrageergebnis generiert wird, muss zuerst das Entitätselement beschrieben werden.

Ein Entitätselement in den XML-Daten, die durch eine FOR XML-Abfrage zurückgegeben werden, ist ein Element, das aus einer Tabelle und nicht aus einer Spalte generiert wird. Die folgende FOR XML-Abfrage gibt z. B. Kontaktinformationen aus der Contact-Tabelle in der AdventureWorks-Datenbank zurück.

SELECT ContactID, FirstName
FROM Person.Contact
WHERE ContactID = 1
FOR XML AUTO, ELEMENTS

Dies ist das Ergebnis:

  <Contact>
    <ContactID>1</ContactID>
    <FirstName>Syed</FirstName>
  </Contact>

In diesem Ergebnis ist <Contact> das Entitätselement. Das XML-Ergebnis kann mehrere Entitätselemente enthalten, von denen jedes eine globale Deklaration im XSD-Inlineschema besitzt. Die folgende Abfrage ruft z. B. Bestellungskopfzeilen- und Detailinformationen für eine bestimmte Bestellung ab.

SELECT  SalesOrderHeader.SalesOrderID, ProductID, OrderQty
FROM    Sales.SalesOrderHeader, Sales.SalesOrderDetail
WHERE   SalesOrderHeader.SalesOrderID = SalesOrderDetail.SalesOrderID
AND     SalesOrderHeader.SalesOrderID=5001
FOR XML AUTO, ELEMENTS, XMLSCHEMA

Da die Abfrage die ELEMENTS-Direktive angibt, ist das sich ergebende XML elementzentriert. Die Abfrage gibt außerdem die XMLSCHEMA-Direktive an. Daher wird ein XSD-Inlineschema zurückgegeben. Dies ist das Ergebnis:

<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>

Beachten Sie hinsichtlich der vorherigen Abfrage Folgendes:

  • Im Ergebnis sind <SalesOrderHeader> und <SalesOrderDetail> Entitästelemente. Aus diesem Grund werden sie global im Schema deklariert. Dies bedeutet, dass die Deklaration auf der obersten Ebene im <Schema>-Element erfolgt.

  • <SalesOrderID>, <ProductID> und <OrderQty> sind keine Entitätselemente, da sie Spalten zugeordnet sind. Die Spaltendaten werden aufgrund der ELEMENTS-Direktive als Elemente im XML zurückgegeben. Diese werden lokalen Elementen des complex-Typs des Entitätselements zugeordnet. Beachten Sie, dass die SalesOrderID-, ProductID- und OrderQty-Werte lokalen Attributen des entsprechenden complex-Typs des Entitätselements zugeordnet werden, wenn die ELEMENTS-Direktive nicht angegeben wird.

Attributnamenkollisionen

Die folgende Erläuterung basiert auf den CustOrder- und CustOrderDetail-Tabellen. Wenn Sie die folgenden Beispiele testen möchten, erstellen Sie diese Tabellen und fügen eigene Beispieldaten hinzu:

CREATE TABLE CustOrder (OrderID int primary key, CustomerID int)
go
CREATE TABLE CustOrderDetail (OrderID int, ProductID int, Qty int)
go

In FOR XML wird der gleiche Name manchmal zum Angeben verschiedener Eigenschaften oder Attribute verwendet. Die folgende attributzentrierte Abfrage im RAW-Modus generiert z. B. zwei Attribute, die den gleichen Namen (OrderID) besitzen. In diesem Fall wird ein Fehler generiert.

SELECT CustOrder.OrderID, 
       CustOrderDetail.ProductID, 
       CustOrderDetail.OrderID
FROM   dbo.CustOrder, dbo.CustOrderDetail
WHERE  CustOrder.OrderID = CustOrderDetail.OrderID
FOR XML RAW, XMLSCHEMA

Da es jedoch zulässig ist, zwei Elemente mit gleichem Namen zu verwenden, können Sie das Problem durch Hinzufügen der ELEMENTS-Direktive beseitigen:

SELECT CustOrder.OrderID,
       CustOrderDetail.ProductID, 
       CustOrderDetail.OrderID
from   dbo.CustOrder, dbo.CustOrderDetail
where  CustOrder.OrderID = CustOrderDetail.OrderID
FOR XML RAW, XMLSCHEMA, ELEMENTS

Dies ist das Ergebnis. Beachten Sie, dass das OrderID-Element im XSD-Inlineschema zweimal definiert wird. In einer der Deklarationen wird minOccurs entsprechend der OrderID aus der CustOrderDetail-Tabelle auf 0 festgelegt, in der zweiten Deklaration erfolgt die Zuordnung zur primären Schlüsselspalte OrderID der CustOrder-Tabelle, wobei minOccurs standardmäßig den Wert 1 besitzt.

<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>

Elementnamenkollisionen

In FOR XML kann der gleiche Name zum Angeben von zwei Unterelementen verwendet werden. Die folgende Abfrage ruft z. B. die ListPrice- und DealerPrice-Werte von Produkten ab; die Abfrage gibt jedoch den gleichen Alias (Price) für diese beiden Spalten an. Aus diesem Grund besitzt das sich ergebende Rowset zwei Spalten mit dem gleichen Namen.

Fall 1: Beide Unterelemente sind Nichtschlüsselspalten des gleichen Typs und können den Wert NULL besitzen

In der folgenden Abfrage sind beide Unterelemente Nichtschlüsselspalten des gleichen Typs und können den Wert NULL besitzen.

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

Dies ist das entsprechende XML, das generiert wird. Es wird nur ein Teil des XSD-Inlineschemas dargestellt.

…
<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>

Beachten Sie Folgendes bezüglich des XSD-Inlineschemas:

  • ListPrice und DealerPrice sind vom gleichen Datentyp (money), und beide Angaben können in der Tabelle den Wert NULL aufweisen. Da sie im sich ergebenden XML nicht zurückgegeben werden können, ist nur ein untergeordnetes <Price>-Element in der komplexen Typdeklaration des <row>-Elements vorhanden, das die Werte minOccurs=0 und maxOccurs=2 aufweist.

  • Im Ergebnis wird nur ListPrice als <Price>-Element zurückgegeben, weil der Wert von DealerPrice in der Tabelle NULL ist. Wenn Sie der ELEMENTS-Direktive den XSINIL-Parameter hinzufügen, erhalten Sie beide Elemente, deren Wert xsi:nil für das <Price>-Element auf TRUE festgelegt wurde, das DealerPrice entspricht. Außerdem erhalten Sie zwei untergeordnete <Price>-Elemente in der komplexen Typdefinition <row> im XSD-Inlineschema, wobei das nillable-Attribute für beide auf TRUE festgelegt wurde. Dieses Fragment ist ein Teilergebnis:

…
<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>

Fall 2: Eine Schlüssel- und eine Nichtschlüsselspalte des gleichen Typs

Die folgende Abfrage zeigt eine Schlüssel- und eine Nichtschlüsselspalte des gleichen Typs.

CREATE TABLE T (Col1 int primary key, Col2 int, Col3 nvarchar(20))
go
INSERT INTO T VALUES (1, 1, 'test')
go 

Die folgende Abfrage für die Tabelle T gibt den gleichen Alias für Col1 und Col2 an, wobei Col1 ein Primärschlüssel ist und nicht null sein darf, wohingegen Col2 null sein darf. Diese Abfrage generiert zwei gleichgeordnete Elemente, die untergeordnete Elemente des <row>-Elements sind.

SELECT Col1 as Col, Col2 as Col, Col3
FROM T
FOR XML RAW, ELEMENTS, XMLSCHEMA

Dies ist das Ergebnis. Es wird nur ein Fragment des XSD-Schemas dargestellt.

…
<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>

Beachten Sie im XSD-Inlineschema, dass für das <Col>-Element, das Col2 entspricht, minOccurs auf 0 festgelegt wurde.

Fall 3: Beide Elemente eines unterschiedlichen Typs und entsprechender Spalten dürfen NULL sein

Die folgende Abfrage wird für die gleiche Tabelle angegeben, die auch in Fall 2 gezeigt wurde:

SELECT Col1, Col2 as Col, Col3 as Col
FROM T
FOR XML RAW, ELEMENTS, XMLSCHEMA

In der folgenden Abfrage erhalten Col2 und Col3 den gleichen Alias. Diese Abfrage generiert zwei gleichgeordnete Elemente, die den gleichen Namen besitzen und untergeordnete Elemente des <raw>-Elements im Ergebnis sind. Diese beiden Spalten gehören unterschiedlichen Typen an und dürfen NULL sein Dies ist das Ergebnis. Es wird nur ein Teil des XSD-Inlineschemas gezeigt.

…
<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>

Beachten Sie Folgendes bezüglich des XSD-Inlineschemas:

  • Da sowohl Col2 als auch Col3 NULL sein dürfen, gibt die Deklaration des <Col>-Elements minOccurs als 0 und maxOccurs als 2 an.

  • Da beide <Col>-Elemente gleichgeordnete Elemente sind, ist im Schema eine Elementdeklaration vorhanden. Da die Elemente unterschiedlichen Typen angehören, obwohl beide Elemente simple-Typen sind, ist der Typ des Elements im Schema xsd:anySimpleType. Im Ergebnis wird jeder Instanztyp durch das xsi:type-Attribut identifiziert.

  • Im Ergebnis verweist jede Instanz des <Col>-Elements mithilfe des xsi:type-Attributs auf ihren Instanztyp.