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:
Un test del nodo. Per ulteriori informazioni, vedere Definizione del test di nodo in un passo dell'espressione di percorso.
Zero o più predicati (facoltativo).
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:
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.
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.
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"/>
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.