SequenceType-Ausdrücke (XQuery)

In XQuery ist jeder Wert eine Sequenz. Der Typ des Werts wird als Sequenztyp bezeichnet. Der Sequenztyp kann in XQuery in einem instance of-Ausdruck verwendet werden. Die in der XQuery-Spezifikation beschriebene SequenceType-Syntax wird verwendet, wenn in einem XQuery-Ausdruck auf einen Typ verwiesen werden muss.

Außerdem kann in XQuery auch der atomare Typname in einem cast as-Ausdruck verwendet werden. In SQL Server werden der instance of - und der cast as-XQuery-Ausdruck für Sequenztypen teilweise unterstützt.

instance of-Operator

Der instance of-Operator kann verwendet werden, um den dynamischen oder Laufzeittyp des Werts eines angegebenen Ausdrucks zu bestimmen. Beispiel:

Expression instance of SequenceType[Occurrence indicator]

Beachten Sie, dass der instance of -Operator Occurrence indicator die Kardinalität, d. h. die Anzahl der Elemente in der resultierenden Sequenz angibt. Wenn dieser Operator nicht angegeben wird, wird eine Kardinalität von 1 verwendet. In SQL Server wird nur das Fragezeichen (?) als Häufigkeitsindikator unterstützt. Der ?-Häufigkeitsindikator zeigt an, dass Expression null oder ein Element(e) zurückgeben kann. Wenn der ?-Häufigkeitsindikator angegeben ist, gibt instance of True zurück, wenn der Expression-Typ mit dem angegebenen Wert für SequenceType übereinstimmt, unabhängig davon, ob Expression ein Singleton oder eine leere Sequenz zurückgibt.

Wenn der ?-Häufigkeitsindikator nicht angegeben ist, gibt sequence of nur dann True zurück, wenn der Expression-Typ mit dem angegebenen Wert für Type übereinstimmt und Expression ein Singleton zurückgibt.

Hinweis Pluszeichen (+) und Sternchen (*) werden in SQL Server nicht als Häufigkeitsindikatoren unterstützt.

Die folgenden Beispiele veranschaulichen die Verwendung des instance of-Operators in XQuery:

Beispiel A

Im folgenden Beispiel wird eine Variable vom Typ xml erstellt und eine Abfrage dafür angegeben. Der Abfrageausdruck gibt einen instance of-Operator an, um zu bestimmen, ob der dynamische Typ des von dem ersten Operanden zurückgegebenen Werts mit dem im zweiten Operanden angegebenen Typ übereinstimmt.

Die folgende Abfrage gibt True zurück, da der Wert 125 eine Instanz des angegebenen Typs (xs:integer) ist:

declare @x xml
set @x=''
select @x.query('125 instance of xs:integer')
go

Die folgende Abfrage gibt True zurück, da der von dem Ausdruck (/a[1]) zurückgegebene Wert im ersten Operanden ein Element ist:

declare @x xml
set @x='<a>1</a>'
select @x.query('/a[1] instance of element()')
go

Entsprechend gibt instance of in der folgenden Abfrage True zurück, da der Werttyp des Ausdrucks im ersten Ausdruck ein Attribut ist:

declare @x xml
set @x='<a attr1="x">1</a>'
select @x.query('/a[1]/@attr1 instance of attribute()')
go

Im folgenden Beispiel gibt der Ausdruck data(/a[1] einen atomaren Wert mit der Typisierung xdt:untypedAtomic zurück. Folglich gibt instance of True zurück.

declare @x xml
set @x='<a>1</a>'
select @x.query('data(/a[1]) instance of xdt:untypedAtomic')
go

In der folgenden Abfrage gibt der Ausdruck data(/a[1]/@attrA einen nicht typisierten atomaren Wert zurück. Folglich gibt instance of True zurück.

declare @x xml
set @x='<a attrA="X">1</a>'
select @x.query('data(/a[1]/@attrA) instance of xdt:untypedAtomic')
go

Beispiel B

In diesem Beispiel fragen Sie eine typisierte XML-Spalte in der AdventureWorks-Beispieldatenbank ab. Die der abzufragenden Spalte zugeordnete XML-Schemaauflistung stellt die Typisierungsinformationen bereit.

In diesem Ausdruck gibt data() dem der Spalte zugeordneten Schema gemäß den typisierten Wert des ProductModelID-Attributs zurück, also xs:string. Folglich gibt instance of True zurück.

SELECT CatalogDescription.query('
   declare namespace PD="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelDescription";
   data(/PD:ProductDescription[1]/@ProductModelID) instance of xs:string
') as Result
FROM Production.ProductModel
WHERE ProductModelID = 19

Weitere Informationen finden Sie unter Typisiertes XML im Vergleich zu nicht typisiertem XML. Informationen zu der der CatalogDescription-Spalte zugeordneten XML-Schemaauflistung finden Sie unter Informationen zur XML-Spalte ProductModel.CatalogDescription.

Die folgenden Abfragen verwenden den booleschen instance of-Ausdruck, um zu bestimmen, ob das LocationID-Attribut vom Typ xs:integer ist:

SELECT Instructions.query('
   declare namespace AWMI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions";
   /AWMI:root[1]/AWMI:Location[1]/@LocationID instance of attribute(LocationID,xs:integer)
') as Result
FROM Production.ProductModel
WHERE ProductModelID=7

Die folgende Abfrage wird für die typisierte CatalogDescription-Spalte vom Typ XML angegeben. Die dieser Spalte zugeordnete XML-Schemaauflistung stellt die Typisierungsinformationen bereit. Weitere Informationen zu XML-Schemaauflistungen finden Sie unter Informationen zur XML-Spalte ProductModel.CatalogDescription.

Die Abfrage verwendet den element(ElementName, ElementType?)-Test im instance of-Ausdruck, um zu überprüfen, ob /PD:ProductDescription[1] einen Elementknoten eines bestimmten Namens und Typs zurückgibt.

SELECT CatalogDescription.query('
     declare namespace PD="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelDescription";
     /PD:ProductDescription[1] instance of element(PD:ProductDescription, PD:ProductDescription?)
    ') as Result
FROM  Production.ProductModel
where ProductModelID=19

Diese Abfrage gibt True zurück.

Beispiel C

Beim Verwenden von UNION-Datentypen in einem instance of-Ausdruck gilt in SQL Server die folgende Einschränkung: speziell wenn ein Element oder Attribut vom Typ UNION ist, kann instance of den genauen Typ möglicherweise nicht bestimmen. Folglich gibt eine Abfrage False zurück, es sei denn, der in SequenceType verwendete atomare Typ ist das höchste übergeordnete Element des aktuellen Typs des Ausdrucks in der simpleType-Hierarchie. Mit anderen Worten müssen die in SequenceType angegebenen atomaren Typen dem Typ anySimpleType direkt untergeordnet sein. Weitere Informationen zur Typhierarchie finden Sie unter Typumwandlungsregeln in XQuery.

Das nächste Abfragebeispiel führt folgende Vorgänge aus:

  • Erstellen einer XML-Schemaauflistung und Definieren eines UNION-Typs wie integer oder string.

  • Deklarieren einer typisierten xml-Variablen mithilfe der XML-Schemaauflistung.

  • Zuordnen einer XML-Beispielinstanz zu der Variablen.

  • Abfragen der Variablen, um das Verhalten von instance of mit einem UNION-Typ zu veranschaulichen.

Im Folgenden wird die Abfrage aufgeführt:

CREATE XML SCHEMA COLLECTION MyTestSchema AS '
<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://ns" xmlns:ns="http://ns">
<simpleType name="MyUnionType">
<union memberTypes="integer string"/>
</simpleType>
<element name="TestElement" type="ns:MyUnionType"/>
</schema>'
Go

Die folgende Abfrage gibt False zurück, da der in dem instance of-Ausdruck angegebene Sequenztyp nicht das höchste übergeordnete Element des aktuellen Typs des angegebenen Ausdrucks ist. Mit anderen Worten, der Wert von <TestElement> ist vom Typ integer, und das höchste übergeordnete Element ist xs:decimal. Es ist jedoch nicht als der zweite Operand des instance of-Operators angegeben.

SET QUOTED_IDENTIFIER ON
DECLARE @var XML(MyTestSchema)

SET @var = '<TestElement xmlns="http://ns">123</TestElement>'

SELECT @var.query('declare namespace ns="http://ns" 
   data(/ns:TestElement[1]) instance of xs:integer')
go

Nachdem das höchste übergeordnete Element von xs:integer xs:decimal ist, würde die Abfrage True zurückgeben, wenn Sie sie ändern und xs:decimal als SequenceType angeben.

SET QUOTED_IDENTIFIER ON
DECLARE @var XML(MyTestSchema)
SET @var = '<TestElement xmlns="http://ns">123</TestElement>'
SELECT @var.query('declare namespace ns="http://ns"   
   data(/ns:TestElement[1]) instance of xs:decimal')
go

Beispiel D

In diesem Beispiel erstellen Sie zunächst eine XML-Schemaauflistung und verwenden diese anschließend, um eine xml-Variable zu typisieren. Die typisierte xml-Variable wird dann abgefragt, um die Funktionalität von instance of zu veranschaulichen.

Die folgende XML-Schemaauflistung definiert einen einfachen Typ, myType, und ein Element, <root>, vom Typ myType:

drop xml schema collection SC
go
CREATE XML SCHEMA COLLECTION SC AS '
<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="myNS" xmlns:ns="myNS"
xmlns:s="https://schemas.microsoft.com/sqlserver/2004/sqltypes">
      <import namespace="https://schemas.microsoft.com/sqlserver/2004/sqltypes"/>
      <simpleType name="myType">
           <restriction base="s:varchar">
                  <maxLength value="20"/>
            </restriction>
      </simpleType>
      <element name="root" type="ns:myType"/>
</schema>'
Go

Erstellen Sie nun eine typisierte xml-Variable, und fragen Sie sie ab:

DECLARE @var XML(SC)
SET @var = '<root xmlns="myNS">My data</root>'
SELECT @var.query('declare namespace sqltypes = "https://schemas.microsoft.com/sqlserver/2004/sqltypes";
declare namespace ns="myNS"; 
   data(/ns:root[1]) instance of ns:myType')
go

Nachdem der myType-Typ durch Einschränkung aus einem im sqltpypes-Schema definierten varchar-Typ abgeleitet ist, gibt instance of ebenfalls True zurück.

DECLARE @var XML(SC)
SET @var = '<root xmlns="myNS">My data</root>'
SELECT @var.query('declare namespace sqltypes = "https://schemas.microsoft.com/sqlserver/2004/sqltypes";
declare namespace ns="myNS"; 
data(/ns:root[1]) instance of sqltypes:varchar?')
go

Beispiel E

Im folgenden Beispiel ruft der Ausdruck einen der Werte des IDREFS-Attributs auf und verwendet instance of, um zu bestimmen, ob der Wert vom Typ IDREF ist. In diesem Beispiel werden folgende Vorgänge ausgeführt:

  • Erstellt eine XML-Schemaauflistung, in der das <Customer>-Element ein OrderList-Attribut vom Typ IDREFS und das <Order>-Element ein OrderID-Attribut vom Typ ID besitzen.

  • Erstellt eine typisierte xml-Variable und weist dieser eine XML-Beispielinstanz zu.

  • Gibt eine Abfrage für die Variable an. Der Abfrageausdruck ruft den ersten Wert für OrderID aus dem OrderList-Attribut vom Typ IDREFS des ersten <Customer>-Elements ab. Der abgerufene Wert ist vom Typ IDREF. Folglich gibt instance of True zurück.

create xml schema collection SC as
'<schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:Customers="Customers" targetNamespace="Customers">
            <element name="Customers" type="Customers:CustomersType"/>
            <complexType name="CustomersType">
                        <sequence>
                            <element name="Customer" type="Customers:CustomerType" minOccurs="0" maxOccurs="unbounded" />
                        </sequence>
            </complexType>
             <complexType name="OrderType">
                <sequence minOccurs="0" maxOccurs="unbounded">
                            <choice>
                                <element name="OrderValue" type="integer" minOccurs="0" maxOccurs="unbounded"/>
                            </choice>
                </sequence>                                           
                <attribute name="OrderID" type="ID" />
            </complexType>

            <complexType name="CustomerType">
                <sequence minOccurs="0" maxOccurs="unbounded">
                            <choice>
                                <element name="spouse" type="string" minOccurs="0" maxOccurs="unbounded"/>
                                <element name="Order" type="Customers:OrderType" minOccurs="0" maxOccurs="unbounded"/>
                            </choice>
                </sequence>                                           
                <attribute name="CustomerID" type="string" />
                <attribute name="OrderList" type="IDREFS" />
            </complexType>
 </schema>'
go
declare @x xml(SC)
set @x='<CustOrders:Customers xmlns:CustOrders="Customers">
                <Customer CustomerID="C1" OrderList="OrderA OrderB"  >
                              <spouse>Jenny</spouse>
                                <Order OrderID="OrderA"><OrderValue>11</OrderValue></Order>
                                <Order OrderID="OrderB"><OrderValue>22</OrderValue></Order>

                </Customer>
                <Customer CustomerID="C2" OrderList="OrderC OrderD" >
                                <spouse>John</spouse>
                                <Order OrderID="OrderC"><OrderValue>33</OrderValue></Order>
                                <Order OrderID="OrderD"><OrderValue>44</OrderValue></Order>

                        </Customer>
                <Customer CustomerID="C3"  OrderList="OrderE OrderF" >
                                <spouse>Jane</spouse>
                                <Order OrderID="OrderE"><OrderValue>55</OrderValue></Order>
                                <Order OrderID="OrderF"><OrderValue>55</OrderValue></Order>
                </Customer>
                <Customer CustomerID="C4"  OrderList="OrderG"  >
                                <spouse>Tim</spouse>
                                <Order OrderID="OrderG"><OrderValue>66</OrderValue></Order>
                        </Customer>
                <Customer CustomerID="C5"  >
                </Customer>
                <Customer CustomerID="C6" >
                </Customer>
                <Customer CustomerID="C7"  >
                </Customer>
</CustOrders:Customers>'

select @x.query(' declare namespace CustOrders="Customers"; 
 data(CustOrders:Customers/Customer[1]/@OrderList)[1] instance of xs:IDREF ? ') as XML_result

Implementierungseinschränkungen

Die folgenden Einschränkungen sind zu beachten:

  • Der schema-element()- und der schema-attribute()-Sequenztyp werden für den Vergleich mit dem instance of-Operator nicht unterstützt.

  • Vollständige Sequenzen wie z. B. (1,2) instance of xs:integer* werden nicht unterstützt.

  • Wenn Sie einen element()-Sequenztyp in der Form verwenden, dass er einen Typnamen angibt, wie z. B. element(ElementName, TypeName), muss der Typ mit einem Fragezeichen (?) qualifiziert werden. Beispielsweise zeigt element(Title, xs:string?) an, dass das Element möglicherweise NULL ist. In SQL Server wird die Erkennung der xsi:nil-Eigenschaft mithilfe von instance of zur Laufzeit nicht unterstützt.

  • Wenn der Wert in Expression aus einem als UNION typisierten Element oder Attribut stammt, identifiziert SQL Server nur den primitiven Typ, nicht aber den Typ, aus dem der Typ des Werts abgeleitet wurde. Wenn beispielsweise <e1> als statischer Typ (xs:integer | xs:string) definiert ist, gibt der folgende Code False zurück.

    data(<e1>123</e1>) instance of xs:integer
    

    Jedoch gibt data(<e1>123</e1>) instance of xs:decimal True zurück.

  • Für den processing-instruction()- und den document-node()-Sequenztyp sind nur Formen ohne Argumente zulässig. Beispielsweise ist processing-instruction() zulässig, processing-instruction('abc') jedoch nicht.

cast as-Operator

Der cast as-Ausdruck kann verwendet werden, um einen Wert in einen bestimmten Datentyp umzuwandeln. Beispiel:

Expression cast as  AtomicType?

In SQL Server ist das Fragezeichen (?) nach AtomicType erforderlich. Beispielsweise konvertiert "2" cast as xs:integer? einen string-Wert in einen integer-Wert, wie in der folgenden Abfrage gezeigt:

declare @x xml
set @x=''
select @x.query('"2" cast as xs:integer?')

In der folgenden Abfrage gibt data() den typisierten Wert des ProductModelID-Attributs als string-Typ zurück. Der cast as-Operator konvertiert den Wert zu xs:integer.

WITH XMLNAMESPACES ('https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelDescription' AS PD)
SELECT CatalogDescription.query('
   data(/PD:ProductDescription[1]/@ProductModelID) cast as xs:integer?
') as Result
FROM Production.ProductModel
WHERE ProductModelID = 19

In dieser Abfrage ist es nicht erforderlich, data() explizit zu verwenden. Der cast as-Ausdruck führt die implizite Atomisierung des Eingabeausdrucks aus.

Konstruktorfunktionen

Sie können die Konstruktorfunktionen für atomare Typen verwenden. Beispielsweise können Sie anstelle des cast as-Operators "2" cast as xs:integer? die xs:integer()-Konstruktorfunktion verwenden, wie im folgenden Beispiel gezeigt:

declare @x xml
set @x=''
select @x.query('xs:integer("2")')

Das folgende Beispiel gibt einen Datumswert vom Typ xs:date gleich 2000-01-01Z zurück.

declare @x xml
set @x=''
select @x.query('xs:date("2000-01-01Z")')

Sie können Konstruktoren auch für benutzerdefinierte atomare Typen verwenden. Wenn die dem XML-Datentyp zugeordnete XML-Schemaauflistung beispielsweise einen einfachen Typ definiert, kann ein myType() -Konstruktor verwendet werden, um einen Wert von diesem Typ zurückzugeben.

Implementierungseinschränkungen

  • Die XQuery-Ausdrücke typeswitch, castable und treat werden nicht unterstützt.

  • cast as erfordert ein Fragezeichen (?) nach dem atomaren Typ.

  • Der xs:QName-Typ wird für die Umwandlung mit CAST nicht unterstützt. Verwenden Sie stattdessen expanded-QName.

  • xs:date, xs:time und xs:datetime erfordern eine Zeitzone, was durch ein Z gekennzeichnet ist.

    Die folgende Abfrage schlägt fehl, da die Zeitzone nicht angegeben ist.

    DECLARE @var XML
    SET @var = ''
    SELECT @var.query(' <a>{xs:date("2002-05-25")}</a>')
    go
    

    Wenn Sie dem Wert ein Z zum Anzeigen der Zeitzone hinzufügen, kann die Abfrage ordnungsgemäß ausgeführt werden.

    DECLARE @var XML
    SET @var = ''
    SELECT @var.query(' <a>{xs:date("2002-05-25Z")}</a>')
    go
    

    Dies ist das Ergebnis:

    <a>2002-05-25Z</a>