Condividi tramite


Specifica di predicati in un passo dell'espressione di percorso

Come illustrato nell'argomento relativo alle espressioni di percorso in XQuery, un passo dell'asse di un'espressione di percorso include i componenti seguenti:

Il predicato facoltativo rappresenta la terza parte del passo dell'asse in un'espressione di percorso.

Predicati

Per filtrare una sequenza di nodi applicando un test specifico, è possibile utilizzare un predicato. L'espressione del predicato è racchiusa tra parentesi quadre ed è associata all'ultimo nodo di un'espressione di percorso.

Ad esempio, si supponga che venga dichiarato un parametro SQL (x) con tipo di dati xml, come illustrato di seguito:

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 questo caso, le espressioni seguenti che utilizzano un valore del predicato [1] in tre livelli del nodo diversi sono valide:

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

Si noti che in ognuno dei casi, il predicato viene associato al nodo dell'espressione di percorso nella quale è applicato. Ad esempio, la prima espressione di percorso seleziona il primo elemento <Name> all'interno di ogni nodo /People/Person e, nell'istanza XML specificata, restituisce quanto segue:

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

La seconda espressione di percorso seleziona tuttavia tutti gli elementi <Name> che si trovano sotto il primo nodo /People/Person. Viene pertanto restituito quando segue:

<Name>John</Name>

È inoltre possibile modificare l'ordine di valutazione del predicato utilizzando le parentesi. Ad esempio, nell'espressione seguente viene utilizzato un set di parentesi per separare il percorso (/People/Person/Name) dal predicato [1]:

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

Nell'esempio, viene modificato l'ordine in base al quale è applicato il predicato perché prima viene valutato il percorso tra parentesi (/People/Person/Name) e quindi l'operatore [1] del predicato viene applicato al set contenente tutti i nodi corrispondenti a tale percorso. L'ordine delle operazioni sarebbe diverso senza le parentesi, perché l'operatore [1] verrebbe applicato come un nodo del test child::Name, in modo similare al primo esempio di espressione di percorso.

Quantificatori e predicati

All'interno delle parentesi graffe del predicato è possibile utilizzare e aggiungere più quantificatori. Di seguito è riportato un esempio di utilizzo valido di più quantificatori in una sottoespressione con un predicato complesso, basato sull'esempio precedente.

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

Il risultato di un'espressione del predicato viene convertito in un valore booleano ed è definito valore di verità del predicato. Nel risultato vengono restituiti unicamente i nodi della sequenza per i quali il valore di verità del predicato è True. Tutti gli altri nodi vengono invece scartati.

Ad esempio, l'espressione di percorso seguente include un predicato nel secondo passo:

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

La condizione specificata dal predicato viene applicata a tutti i figli del nodo elemento <Location>. Vengono pertanto restituiti solo i centri di lavorazione il cui valore dell'attributo LocationID è 10.

L'espressione di percorso precedente viene eseguita nell'istruzione SELECT seguente:

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

Calcolo dei valori di verità del predicato

Per stabilire il valore di verità del predicato vengono applicate le regole seguenti, in base alle specifiche XQuery:

  1. Se il valore dell'espressione del predicato è una sequenza vuota, il valore di verità del predicato è False.

    Ad esempio:

    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'espressione di percorso nella query restituisce solo i nodi elemento <Location> per i quali è stato specificato un attributo LotSize. Se il predicato restituisce una sequenza vuota per un nodo elemento <Location> specifico, il relativo centro di lavorazione non verrà restituito nel risultato.

  2. I valori di un predicato possono essere solo di tipo xs:integer, xs:Boolean o node*. Per node*, il predicato restituisce True se sono presenti nodi e False per una sequenza vuota. Qualsiasi altro tipo numerico, ad esempio double e float, genera un errore di tipizzazione statica. Il valore di verità del predicato di un'espressione è True se e solo se il valore di tipo integer risultante è uguale al valore della posizione del contesto. Inoltre, solo i valori letterali integer e la funzione last() riducono la cardinalità dell'espressione per passi filtrata a 1.

    Ad esempio, la query seguente recupera il terzo nodo figlio dell'elemento <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
    

    Dalla query precedente si noti quanto segue:

    • Il terzo passo dell'espressione specifica un'espressione del predicato il cui valore è 3. Il valore di verità del predicato è pertanto True solo per i nodi la cui posizione del contesto è 3.

    • Nel terzo passo viene inoltre specificato un carattere jolly (*) che indica tutti i nodi nel test dei nodi. Il predicato filtra tuttavia i nodi e restituisce solo il nodo nella terza posizione.

    • La query restituisce il terzo nodo figlio degli elementi figlio <Features> degli elementi figlio <ProductDescription> della radice dei documenti.

  3. Se il valore dell'espressione predicato è un valore semplice booleano, il valore di verità del predicato è uguale al valore dell'espressione predicato.

    Ad esempio, la query seguente viene eseguita su una variabile di tipo xmlche contiene l'istanza XML di un sondaggio sui clienti. La query recupera i clienti con figli. Nella query, ciò corrisponde a <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
    

    Dalla query precedente si noti quanto segue:

    • L'espressione nel ciclo for include due passi e il secondo passo specifica un predicato il cui valore è di tipo booleano. Se il valore è True, anche il valore di verità del predicato è True.

    • La query restituisce gli elementi figlio <Customer>, con valore del predicato True, degli elementi figlio <Survey> della radice dei documenti. Risultato:

      <CustomerWithChildren CustomerID="1"/> 
      
  4. Se il valore dell'espressione predicato è una sequenza che contiene almeno un nodo, il valore di verità del predicato è True.

Ad esempio, la query seguente recupera il valore ProductModelID per i modelli di prodotto la cui descrizione del catalogo XML include almeno una caratteristica, ovvero un elemento figlio dell'elemento <Features>, appartenente allo spazio dei nomi associato al prefisso 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

Tipizzazione statica e filtri del predicato

I predicati possono inoltre influire sul tipo di un'espressione derivato staticamente. I valori letterali di tipo integer e la funzione last() riducono la cardinalità dell'espressione per passi filtrata al massimo a uno.