Sdílet prostřednictvím


Generování přímo vloženého schématu XSD

platí pro:SQL Serverazure SQL Database

V klauzuli FOR XML můžete požádat, aby dotaz vrátil vložené schéma společně s výsledky dotazu. Pokud chcete schéma XDR, použijete klíčové slovo XMLDATA v klauzuli FOR XML. Pokud chcete schéma XSD, použijte klíčové slovo XMLSCHEMA.

Tento článek popisuje klíčové slovo XMLSCHEMA a vysvětluje strukturu výsledného vloženého schématu XSD. Při vyžádání vložených schémat platí následující omezení:

  • XMLSCHEMA můžete zadat pouze v režimu "RAW" a "AUTO", nikoli v režimu "EXPLICIT".

  • Pokud vnořený dotaz FOR XML určuje direktivu TYPE, výsledek dotazu je typu xml, a tento výsledek se považuje za instanci netypových dat XML. Další informace naleznete v tématu XML Data (SQL Server).

Když v dotazu FOR XML zadáte XMLSCHEMA, obdržíte jak schéma, tak data XML, výsledek dotazu. Každý prvek nejvyšší úrovně dat odkazuje na předchozí schéma pomocí výchozí deklarace oboru názvů, která zase odkazuje na cílový obor názvů vloženého schématu.

Například:

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

Výsledek obsahuje schéma XML a výsledek XML. Prvek nejvyšší úrovně <ProductModel> ve výsledku odkazuje na schéma pomocí výchozí deklarace oboru názvů xmlns="urn:schemas-microsoft-com:sql:SqlRowSet1".

Část výsledku schématu může obsahovat více dokumentů schématu, které popisují více oborů názvů. Vrátí se minimálně následující dva dokumenty schématu:

  • Jeden dokument schématu pro obor názvů Sqltypes, pro který se vrací základní typy SQL.

  • Další dokument schématu, který popisuje tvar výsledku dotazu FOR XML.

Pokud jsou do výsledku dotazu zahrnuté také datové typy xml, jsou zahrnuta schémata přidružená k těmto typům xml datových typů.

Cílový obor názvů dokumentu schématu, který popisuje tvar výsledku FOR XML, obsahuje pevnou část a číselnou část, která se automaticky zvýší. Formát tohoto oboru názvů je znázorněn v následujícím příkladu, kde n je kladné celé číslo. Například v předchozím dotazu je obor názvů urn:schemas-microsoft-com:sql:SqlRowSet1 cílový.

urn:schemas-microsoft-com:sql:SqlRowSetn

Ke změně cílových jmenných prostorů ve výsledku, ke které došlo z jednoho spuštění na druhé, možná není žádoucí. Pokud například zadáte dotaz na výsledný kód XML, bude změna v cílovém oboru názvů vyžadovat aktualizaci dotazu. Volitelně můžete zadat cílový obor názvů při přidání možnosti XMLSCHEMA do klauzule FOR XML. Výsledný kód XML bude obsahovat zadaný obor názvů a zůstane stejný bez ohledu na to, kolikrát dotaz spustíte.

SELECT ProductModelID, Name
FROM   Production.ProductModel
WHERE ProductModelID=1
FOR XML AUTO, XMLSCHEMA ('MyURI');

Prvky entity

Aby bylo možné probrat podrobnosti struktury schématu XSD vygenerované pro výsledek dotazu, musí být nejprve popsán element entity.

Element entity v datech XML vrácených dotazem FOR XML je element, který je generován z tabulky, a ne ze sloupce. Například následující dotaz FOR XML vrátí kontaktní informace z tabulky Person v databázi AdventureWorks2022.

SELECT BusinessEntityID, FirstName
FROM Person.Person
WHERE BusinessEntityID = 1
FOR XML AUTO, ELEMENTS;

Toto je výsledek:

<Person>
  <BusinessEntityID>1</BusinessEntityID>
  <FirstName>Ken</FirstName>
</Person>

Ve výsledku je prvek entity <Person>. Ve výsledku XML může existovat více prvků entity a každý z nich má globální deklaraci ve vloženém schématu XSD. Následující dotaz například načte záhlaví prodejní objednávky a podrobné informace o konkrétní objednávce.

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

Vzhledem k tomu, že dotaz určuje direktivu ELEMENTS, je výsledný XML element-orientovaný. Dotaz také určuje direktivu XMLSCHEMA. Proto se vrátí vložené schéma XSD. Toto je výsledek:

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

Všimněte si následujících věcí z předchozího dotazu:

  • Ve výsledku jsou prvky entity <SalesOrderHeader> a <SalesOrderDetail>. Z tohoto důvodu jsou globálně deklarovány ve schématu. To znamená, že deklarace se zobrazí na nejvyšší úrovni uvnitř <Schema> elementu.

  • <SalesOrderID>, <ProductID>a <OrderQty> nejsou prvky entity, protože se mapují na sloupce. Data sloupce je vrácena jako elementy v XML díky direktivě ELEMENTS. Tyto prvky jsou mapovány na místní prvky komplexního typu elementu entity. Pokud není zadána direktiva ELEMENTS, jsou hodnoty SalesOrderID, ProductID a OrderQty mapovány na místní atributy komplexního typu příslušného prvku entity.

Koliduje název atributu

Následující diskuze vychází z tabulek CustOrder a CustOrderDetail. Pokud chcete otestovat následující ukázky, vytvořte tyto tabulky a přidejte vlastní ukázková data:

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

Ve formátu FOR XML se stejný název někdy používá k označení různých vlastností, atributů. Například následující dotaz režimu RAW orientovaný na atribut generuje dva atributy, které mají stejný název, OrderID. Tím se vygeneruje chyba.

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

Vzhledem k tomu, že je přijatelné mít dva prvky se stejným názvem, můžete problém odstranit přidáním direktivy ELEMENTS:

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

Toto je výsledek. Všimněte si, že ve vloženém schématu XSD je prvek OrderID definován dvakrát. Jedna z deklarací má hodnotu minOccurs nastavenou na hodnotu 0, která odpovídá IDobjednávky z tabulky CustOrderDetail, a druhý z nich se mapuje na sloupec primárního klíče OrderID tabulky CustOrder, kde minOccurs je ve výchozím nastavení 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 názvů elementů

V jazyce XML lze stejný název použít k označení dvou dílčích elementů. Například následující dotaz načte hodnoty ListPrice a DealerPrice produktů, ale dotaz určuje stejný alias Price pro tyto dva sloupce. Výsledná sada řádků proto bude mít dva sloupce se stejným názvem.

Případ 1: Obě dílčí části jsou sloupce bez klíče stejného typu a můžou mít hodnotu NULL.

V následujícím dotazu jsou oba podsložky bezklíčové sloupce stejného typu a mohou mít hodnotu 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;

Toto je odpovídající vygenerovaný kód XML. Zobrazí se jenom zlomek integrovaného 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>

Všimněte si následující položky ve vloženém schématu XSD:

  • Jak ListPrice, tak DealerPrice jsou stejného typu moneya obě mohou být v tabulce NULL. Protože nemusí být vráceny ve výsledném XML, existuje pouze jeden podřízený element <Price> v deklaraci komplexního typu elementu <row>, který má minOccurs=0 a maxOccurs=2.

  • Vzhledem k tomu, že hodnota DealerPrice v tabulce má hodnotu NULL, vrátí se jako prvek <Price> pouze ListPrice. Pokud přidáte parametr XSINIL do direktivy ELEMENTS, obdržíte oba prvky, které mají xsi:nil hodnotu nastavenou na TRUE pro<Price> element, který odpovídá DealerPrice. Obdržíte také dva podřízené prvky <Price> v definici komplexního typu <row> ve vloženém schématu XSD s atributem nillable nastaveným na TRUE pro oba. Tento fragment je částečný výsledek:

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

Případ 2: Jeden klíčový a jeden neklíčový sloupec stejného typu

Následující dotaz znázorňuje jeden klíč a jeden sloupec bez klíče stejného typu.

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

Následující dotaz na tabulku T určuje stejný alias pro sloupec Col1 a Col2, kde Col1 je primární klíč a nemůže mít hodnotu null a sloupec Col2 může mít hodnotu null. Tím se vygenerují dva sourozenecké prvky, které jsou podřízenými prvky elementu <row>.

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

Toto je výsledek. Zobrazí se pouze fragment vloženého schématu 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>

Všimněte si, že ve vloženém XSD schématu je prvek <Col> odpovídající sloupci Col2 nastaven s minOccurs na 0.

Případ 3: Oba prvky různých typů a odpovídajících sloupců můžou mít hodnotu NULL.

V případě 2 je proti ukázkové tabulce specifikován následující dotaz:

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

V následujícím dotazu mají sloupce Col2 a Col3 stejné aliasy. Tím se vygenerují dva související prvky, které mají stejný název a které jsou oba podřízené elementu <raw> ve výsledku. Oba tyto sloupce mají různé typy a oba můžou mít hodnotu NULL. Toto je výsledek. Zobrazí se pouze částečné interní schéma 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>

Všimněte si následující položky ve vloženém schématu XSD:

  • Vzhledem k tomu, že col2 i Col3 mohou být NULL, <Col> element deklarace určuje minOccurs jako 0 a maxOccurs jako 2.

  • Vzhledem k tomu, že oba prvky <Col> jsou sourozenci, je ve schématu jedna deklarace prvku. Vzhledem k tomu, že oba prvky jsou také různé typy, i když oba jsou jednoduché typy, typ prvku ve schématu je xsd:anySimpleType. Ve výsledku je každý typ instance identifikován atributem xsi:type.

  • Ve výsledku každá instance prvku <Col> odkazuje na jeho typ instance pomocí atributu xsi:type.