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. Pertanto, il valore di verità del predicato di questa espressione sarà 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

Dalla query precedente si noti quanto segue:

  • La clausola WHERE specifica il metodo exist() (tipo di dati XML).

  • L'espressione del percorso all'interno del metodo exist() specifica un predicato nel secondo passo. Se l'espressione del predicato restituisce una sequenza di almeno una caratteristica, il valore di verità di questa espressione del predicato sarà True. In questo caso, poiché il metodo exist() restituisce True, viene restituito ProductModelID.

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.