Expressions de chemin : spécification de prédicats

S’applique à :SQL Server

Comme décrit dans la rubrique Expressions de chemin dans XQuery, une étape d’axe dans une expression de chemin d’accès comprend les composants suivants :

Le prédicat facultatif représente la troisième partie de l'étape d'axe dans une expression de chemin d'accès.

Prédicats

Un prédicat permet de filtrer une séquence de nœuds en appliquant un test spécifié. L'expression de prédicat est incluse dans un crochet et est liée au dernier nœud d'une expression de chemin d'accès.

Par exemple, supposons qu’une valeur de paramètre SQL (x) du type de données xml soit déclarée, comme indiqué dans ce qui suit :

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

Dans ce cas, les expressions suivantes sont des expressions valides qui utilisent une valeur de prédicat de [1] à chacun des trois différents niveaux de nœuds :

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

Notez que dans chaque cas, le prédicat est lié au nœud dans l'expression de chemin d'accès où il est appliqué. Par exemple, la première expression de chemin d’accès sélectionne le premier <Name> élément dans chaque nœud /Personnes/Person et, avec l’instance XML fournie, retourne ce qui suit :

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

Toutefois, la deuxième expression de chemin sélectionne tous les <Name> éléments qui se trouvent sous le premier nœud /Personnes/Person. Par conséquent, il retourne ce qui suit :

<Name>John</Name>  

Des parenthèses peuvent également être utilisées pour modifier l'ordre d'évaluation du prédicat. Par exemple, dans l'expression suivante, un ensemble de parenthèses est utilisé pour séparer le chemin d'accès (/People/Person/Name) du prédicat [1] :

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

Dans cet exemple, l'ordre dans lequel le prédicat est appliqué change. Cela est dû au fait que le chemin d'accès entre parenthèses est évalué en premier (/People/Person/Name), puis l'opérateur [1] de prédicat est appliqué à l'ensemble qui contient tous les nœuds qui correspondent au chemin d'accès entre parenthèses. Sans les parenthèses, l'ordre de fonctionnement serait différent, du fait que [1] est appliqué en tant que test de nœud child::Name, similaire au premier exemple d'expression de chemin d'accès.

Quantificateurs et prédicats

Les quantificateurs peuvent être utilisés et ajoutés plusieurs fois au sein des accolades du prédicat lui-même. Par exemple, en utilisant l'exemple précédent, ce qui suit est une utilisation valide de plusieurs quantificateurs au sein d'une sous-expression de prédicat complexe.

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

Le résultat d'une expression de prédicat est converti en valeur booléenne et est appelé valeur de vérité du prédicat. Seuls les nœuds de la séquence pour lesquels la valeur de vérité du prédicat est True sont retournés dans le résultat. Tous les autres nœuds sont ignorés.

Par exemple, l'expression de chemin d'accès ci-dessous inclut un prédicat dans sa deuxième étape :

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

La condition spécifiée par ce prédicat est appliquée à tous les enfants de nœud d’élément <Location> . Il en résulte que seuls les ateliers dont l'attribut LocationID a la valeur 10 sont retournés.

L'expression de chemin d'accès précédente est exécutée dans l'instruction SELECT suivante :

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  

Calcul des valeurs de vérité de prédicat

Les règles ci-dessous s'appliquent pour déterminer la valeur de vérité de prédicat, en fonction des spécifications XQuery :

  1. Si la valeur de l'expression de prédicat est une séquence vide, la valeur de vérité de prédicat est False.

    Par exemple :

    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  
    

    L’expression de chemin dans cette requête retourne uniquement les <Location> nœuds d’élément qui ont un attribut LotSize spécifié. Si le prédicat retourne une séquence vide pour un emplacement spécifique <Location>, cet emplacement de centre de travail n’est pas retourné dans le résultat.

  2. Les valeurs de prédicat peuvent uniquement être xs:integer, xs:Boolean ou node*. Pour node*, le prédicat a la valeur True si des nœuds existent et la valeur False dans le cas d'une séquence vide. Tout autre type numérique, tel que le type double et float, génère une erreur de type statique. La valeur de vérité de prédicat d'une expression est True si et seulement si l'entier résultant est égal à la valeur de la position du contexte. En outre, seules les valeurs littérales entières et la fonction last() réduisent la cardinalité de l’expression d’étape filtrée à 1.

    Par exemple, la requête suivante récupère le troisième nœud d’élément enfant de l’élément <Features> .

    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  
    

    Notez les points suivants dans la requête précédente :

    • La troisième étape de l'expression spécifie une expression de prédicat de valeur égale à 3. Par conséquent, la valeur de vérité de prédicat de cette expression est True seulement pour les nœuds dont la position de contexte est 3.

    • La troisième étape spécifie également un caractère générique (*) qui indique tous les nœuds dans le test de nœud. Toutefois, le prédicat filtre les nœuds et retourne uniquement le nœud en troisième position.

    • La requête retourne le troisième nœud d’élément enfant des enfants de l’élément enfants de l’élémentProductDescription><de la racine du document.<Features>

  3. Si la valeur de l'expression de prédicat est une valeur de type simple de type booléen, la valeur de vérité de prédicat est égale à la valeur de l'expression de prédicat.

    Par exemple, la requête suivante est spécifiée sur une variable de type xmlqui contient une instance XML, l’instance XML de l’enquête client. La requête récupère les clients qui ont des enfants. Dans cette requête, il s’agirait <de 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  
    

    Notez les points suivants dans la requête précédente :

    • L’expression dans la boucle for comporte deux étapes, et la deuxième étape spécifie un prédicat. La valeur de ce prédicat est une valeur de type booléen. Si cette valeur est True, la valeur de vérité du prédicat est également True.

    • La requête retourne les enfants de l’élément <Customer> , dont la valeur de prédicat est True, des enfants de l’élément <Survey> de la racine du document. Voici le résultat obtenu :

      <CustomerWithChildren CustomerID="1"/>   
      
  4. Si la valeur de l'expression de prédicat est une séquence contenant au moins un nœud, la valeur de vérité de prédicat est True.

Par exemple, la requête suivante récupère ProductModelID pour les modèles de produits dont la description du catalogue XML inclut au moins une fonctionnalité, un élément enfant de l’élément, à partir de l’espace <Features> de noms associé au préfixe wm .

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  

Notez les points suivants dans la requête précédente :

  • La clause WHERE spécifie la méthode exist() (type de données XML).

  • L’expression path à l’intérieur de la méthode exist() spécifie un prédicat dans la deuxième étape. Si l'expression de prédicat retourne une séquence contenant au moins une fonctionnalité, la valeur de vérité de cette expression de prédicat a la valeur True. Dans ce cas, étant donné que la méthode exist() retourne une valeur True, le ProductModelID est retourné.

Déduction de type statique et filtres de prédicat

Les prédicats peuvent également affecter le type déduit statiquement d'une expression. Les valeurs littérales entières et la fonction last() réduisent la cardinalité de l’expression d’étape filtrée à un maximum.