Teilen über


Pfadausdrücke – Angeben von Prädikaten

Gilt für:SQL Server

Wie im Thema Pfadausdrücke in XQuery beschrieben, umfasst ein Achsenschritt in einem Pfadausdruck die folgenden Komponenten:

Das optionale Prädikat ist der dritte Teil des Achsenschritts in einem Pfadausdruck.

Prädikate

Ein Prädikat wird zum Filtern einer Knotensequenz durch Anwenden eines angegebenen Tests verwendet. Der Prädikatausdruck ist in eckige Klammern eingeschlossen und an den letzten Knoten in einem Pfadausdruck gebunden.

Angenommen, ein SQL-Parameterwert (x) des xml-Datentyps wird deklariert, wie im Folgenden gezeigt:

declare @x xml  
set @x = '  
<People>  
  <Person>  
    <Name>John</Name>  
    <Age>24</Age>  
  </Person>  
  <Person>  
    <Name>Goofy</Name>  
    <Age>54</Age>  
  </Person>  
  <Person>  
    <Name>Daffy</Name>  
    <Age>30</Age>  
  </Person>  
</People>  
'  

In diesem Fall sind die folgenden Ausdrücke gültig, die einen Prädikatwert von [1] für jede der drei unterschiedlichen Knotenebenen verwenden:

select @x.query('/People/Person/Name[1]')  
select @x.query('/People/Person[1]/Name')  
select @x.query('/People[1]/Person/Name')  

Beachten Sie, dass in jedem Fall das Prädikat an den Knoten im Pfadausdruck gebunden wird, für den es angewendet wird. Beispielsweise wählt der erste Pfadausdruck das erste <Name> Element innerhalb jedes /Personen/Person-Knotens aus und gibt mit der bereitgestellten XML-Instanz Folgendes zurück:

<Name>John</Name><Name>Goofy</Name><Name>Daffy</Name>  

Der zweite Pfadausdruck wählt jedoch alle <Name> Elemente aus, die sich unter dem ersten Knoten /Personen/Person befinden. Deshalb gibt er das folgende Ergebnis zurück:

<Name>John</Name>  

Es können auch Klammern verwendet werden, um die Auswertungsreihenfolge des Prädikats zu ändern. So wird z. B. im folgenden Ausdruck ein Klammernsatz verwendet, um den Pfad von (/People/Person/Name) vom Prädikat [1] zu trennen:

select @x.query('(/People/Person/Name)[1]')  

In diesem Beispiel ändert sich die Reihenfolge, in der das Prädikat angewendet wird. Das liegt daran, dass der in Klammern eingeschlossene Pfad (/People/Person/Name) zuerst ausgewertet und anschließend der Prädikatoperator [1] für das Set angewendet wird, das alle mit dem eingeschlossenen Pfad übereinstimmenden Knoten enthält. Ohne die Klammern wäre die Reihenfolge des Vorgangs anders: Der Prädikatoperator [1] würde dann als ein child::Name-Knotentest angewendet werden, wie das im ersten Beispiel für den Pfadausdruck der Fall war.

Quantifizierer und Prädikate

Quantifizierer können innerhalb der Klammern des Prädikats mehrfach verwendet und hinzugefügt werden. So wäre z. B. unter Nutzung des vorigen Beispiels folgende Verwendung von mehreren Quantifizierern innerhalb eines komplexen Prädikatunterausdrucks gültig.

select @x.query('/People/Person[contains(Name[1], "J") and xs:integer(Age[1]) < 40]/Name/text()')  

Das Ergebnis eines Prädikatausdrucks wird in einen booleschen Wert konvertiert und wird als Wahrheitswert des Prädikats bezeichnet. Im Ergebnis werden nur die Knoten in der Sequenz zurückgegeben, deren Prädikatwahrheitswert True ist. Alle anderen Knoten werden verworfen.

Beim folgenden Pfadausdruck ist z. B. ein Prädikat in den zweiten Schritt eingeschlossen:

/child::root/child::Location[attribute::LocationID=10]  

Die von diesem Prädikat angegebene Bedingung wird auf alle untergeordneten <Location> Elementknoten angewendet. Das führt dazu, dass als Ergebnis nur solche Arbeitsplatzstandorte zurückgegeben werden, bei denen der Attributwert der Standortkennung (LocationID) 10 ist.

Der vorige Pfadausdruck wird in der folgenden SELECT-Anweisung ausgeführt:

SELECT Instructions.query('  
declare namespace AWMI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions";  
 /child::AWMI:root/child::AWMI:Location[attribute::LocationID=10]  
')  
FROM Production.ProductModel  
WHERE ProductModelID=7  

Berechnen des Prädikatwahrheitswerts

Gemäß den XQuery-Spezifikationen werden die folgenden Regeln angewendet, um den Prädikatwahrheitswert zu ermitteln:

  1. Wenn der Wert des Prädikatausdrucks eine leere Sequenz ist, ist der Prädikatwahrheitswert False.

    Beispiel:

    SELECT Instructions.query('  
    declare namespace AWMI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions";  
     /child::AWMI:root/child::AWMI:Location[attribute::LotSize]  
    ')  
    FROM Production.ProductModel  
    WHERE ProductModelID=7  
    

    Der Pfadausdruck in dieser Abfrage gibt nur die Elementknoten zurück, für die <Location> ein LotSize-Attribut angegeben ist. Wenn das Prädikat eine leere Sequenz für eine bestimmte <Location>zurückgibt, wird dieser Arbeitsplatzstandort im Ergebnis nicht zurückgegeben.

  2. Prädikatwerte können nur xs:integer, xs:Boolean oder node* sein. Bei node* wird das Prädikat als True ausgewertet, wenn es irgendwelche Knoten gibt, und als False für eine leere Sequenz. Alle anderen numerischen Typen wie z. B. double und float generieren einen statischen Typisierungsfehler. Der Prädikatwahrheitswert eines Ausdrucks ist ausschließlich dann True, wenn die resultierende ganze Zahl gleich dem Wert der Kontextposition ist. Außerdem reduzieren nur ganzzahlige Literalwerte und die last() -Funktion die Kardinalität des gefilterten Schrittausdrucks auf 1.

    Die folgende Abfrage ruft beispielsweise den dritten untergeordneten Elementknoten des <Features> Elements ab.

    SELECT CatalogDescription.query('  
    declare namespace PD="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelDescription";  
    declare namespace wm="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelWarrAndMain";  
     /child::PD:ProductDescription/child::PD:Features/child::*[3]  
    ')  
    FROM Production.ProductModel  
    WHERE ProductModelID=19  
    

    Beachten Sie hinsichtlich der vorherigen Abfrage Folgendes:

    • Der dritte Schritt im Ausdruck gibt einen Prädikatausdruck mit dem Wert 3 an. Daher ist der Prädikatwahrheitswert dieses Ausdrucks nur für die Knoten True, deren Kontextposition 3 ist.

    • Der dritte Schritt gibt auch ein Platzhalterzeichen (*) an, das alle Knoten im Knotentest anzeigt. Das Prädikat filtert jedoch die Knoten und gibt nur den Knoten in der dritten Position zurück.

    • Die Abfrage gibt den dritten untergeordneten Elementknoten des <Features> untergeordneten Elements der untergeordneten Elemente des <ProductDescription> Dokumentstamms zurück.

  3. Wenn der Wert des Prädikatausdrucks ein einfacher Werttyp des booleschen Datentyps ist, entspricht der Prädikatwahrheitswert dem Wert des Prädikatausdrucks.

    Beispielsweise wird die folgende Abfrage für eine Xml-Typvariableangegeben, die eine XML-Instanz enthält, die XML-Instanz der Kundenumfrage. Die Abfrage ruft solche Kunden ab, die über untergeordnete Elemente verfügen. In dieser Abfrage wäre <dies HasChildren>1</HasChildren>.

    declare @x xml  
    set @x='  
    <Survey>  
      <Customer CustomerID="1" >  
      <Age>27</Age>  
      <Income>20000</Income>  
      <HasChildren>1</HasChildren>  
      </Customer>  
      <Customer CustomerID="2" >  
      <Age>27</Age>  
      <Income>20000</Income>  
      <HasChildren>0</HasChildren>  
      </Customer>  
    </Survey>  
    '  
    declare @y xml  
    set @y = @x.query('  
      for $c in /child::Survey/child::Customer[( child::HasChildren[1] cast as xs:boolean ? )]  
      return   
          <CustomerWithChildren>  
              { $c/attribute::CustomerID }  
          </CustomerWithChildren>  
    ')  
    select @y  
    

    Beachten Sie hinsichtlich der vorherigen Abfrage Folgendes:

    • Der Ausdruck in der for-Schleife umfasst zwei Schritte, und der zweite Schritt gibt ein Prädikat an. Der Wert dieses Prädikats ist ein Wert des booleschen Datentyps. Wenn dieser Wert True ist, so ist auch der Wahrheitswert des Prädikats True.

    • Die Abfrage gibt das <Customer> untergeordnete Element zurück, dessen Prädikatwert True ist, der untergeordneten Elemente des <Survey-Elements> des Dokumentstamms. Dies ist das Ergebnis:

      <CustomerWithChildren CustomerID="1"/>   
      
  4. Wenn der Wert des Prädikatausdrucks eine Sequenz ist, die mindestens einen Knoten enthält, so ist der Wahrheitswert des Prädikats True.

Die folgende Abfrage ruft beispielsweise ProductModelID für Produktmodelle ab, deren XML-Katalogbeschreibung mindestens ein Feature ( ein untergeordnetes Element des <Features> Elements) aus dem Namespace enthält, der dem Präfix wm zugeordnet ist.

SELECT ProductModelID  
FROM   Production.ProductModel  
WHERE CatalogDescription.exist('  
             declare namespace PD="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelDescription";  
             declare namespace wm="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelWarrAndMain";  
             /child::PD:ProductDescription/child::PD:Features[wm:*]  
             ') = 1  

Beachten Sie hinsichtlich der vorherigen Abfrage Folgendes:

  • Die WHERE-Klausel gibt die exist()-Methode (XML-Datentyp) an.

  • Der path-Ausdruck innerhalb der exist() -Methode gibt ein Prädikat im zweiten Schritt an. Wenn der Prädikatausdruck eine Sequenz von mindestens einer Funktion zurückgibt, ist der Wahrheitswert dieses Prädikatausdrucks True. In diesem Fall wird die ProductModelID zurückgegeben, da die exist() -Methode einen True-Wert zurückgibt.

Statische Typisierung und Prädikatfilter

Die Prädikate können sich auch auf den statisch abgeleiteten Typ eines Ausdrucks auswirken. Ganzzahlige Literalwerte und die last() -Funktion reduzieren die Kardinalität des gefilterten Schrittausdrucks auf höchstens eins.