Compartilhar via


Especificando predicados em uma etapa de expressão de caminho

Como descrito no tópico, Expressões de caminho no XQuery, uma etapa de eixo em uma expressão de caminho, inclui os seguintes componentes:

O predicado opcional é a terceira parte da etapa de eixo em uma expressão de caminho.

Predicados

Um predicado é usado para filtrar uma seqüência de nó aplicando-se um teste especificado. A expressão de predicado é inclusa em um colchete e associada ao último nó em uma expressão de caminho.

Por exemplo, suponha que um valor de parâmetro SQL (x) do tipo de dados xml seja declarado, como mostrado no seguinte exemplo:

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

Nesse caso, são válidas as seguintes expressões que usam um valor de predicado de [1] em cada um dos três diferentes níveis de nó:

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

Observe que em cada caso, o predicado associa-se ao nó na expressão de caminho em que ele é aplicado. Por exemplo, a primeira expressão de caminho seleciona o primeiro elemento <Name> dentro de cada nó de /People/Person e, com a instância XML fornecida, retorna o seguinte:

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

Porém, a segunda expressão de caminho seleciona todos os elementos <Name> que estão sob o primeiro nó de /People/Person. Portanto, ele retorna o seguinte:

<Name>John</Name>

Os parênteses também podem ser usados para alterar a ordem de avaliação do predicado. Por exemplo, na expressão a seguir, um conjunto de parênteses é usado para separar o caminho de (/People/Person/Name) do predicado [1]:

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

Nesse exemplo, é alterada a ordem em que o predicado é aplicado. Isso acontece porque o caminho incluso é avaliado em primeiro lugar (/People/Person/Name) e, então, o operador do predicado [1] é aplicado ao conjunto que contém todos os nós que corresponderam ao caminho incluso. Sem os parênteses, a ordem de operação seria diferente, de forma que [1] é aplicado como teste de nó child::Name, semelhante ao primeiro exemplo de expressão de caminho.

Quantificadores e predicados

Os quantificadores podem ser usados e adicionados mais de uma vez dentro dos colchetes do próprio predicado. Por exemplo, usando o exemplo anterior, o descrito a seguir é um uso válido de mais de um quantificador dentro de uma subexpressão de predicado complexo.

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

O resultado de uma expressão de predicado é convertido em um valor Booleano e é chamado de valor verdadeiro do predicado. Apenas os nós da seqüência para a qual o valor verdadeiro do predicado é True são retornados no resultado. Todos os outros nós são descartados.

Por exemplo, a expressão de caminho a seguir inclui um predicado em sua segunda etapa:

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

A condição especificada por esse predicado é aplicada a todos os nós do elemento filho <Location>. O resultado é que só aqueles locais de centro de trabalho cujo valor do atributo LocationID seja 10 serão retornados.

A expressão de caminho anterior é executada na seguinte instrução SELECT:

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

Calculando valores verdadeiros do predicado

As regras a seguir são aplicadas de forma a determinar o valor verdadeiro do predicado, de acordo com as especificações do XQuery:

  1. Se o valor da expressão do predicado for uma seqüência vazia, o valor verdadeiro do predicado será False.

    Por exemplo:

    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
    

    O caminho de expressão nessa consulta, só retornará aqueles nós do elemento <Location> que tenham um atributo LotSize especificado. Se o predicado retornar uma seqüência vazia para um <Location>específico, aquele local de centro de trabalho não será retornado no resultado.

  2. Os valores do predicado só podem ser xs:integer, xs:Boolean ou node*. Para node*, o predicado avalia como True se existir qualquer nó e como False para uma seqüência vazia. Qualquer outro tipo numérico, como dobro e tipo de float, gera um erro de tipo estático. O valor verdadeiro do predicado de uma expressão é True se e somente se o inteiro resultante for igual ao valor da posição de contexto. Além disso, apenas valores inteiros literais e a função last() reduzem a cardinalidade da expressão de etapa filtrada para 1.

    Por exemplo, a consulta a seguir recupera o terceiro nó do elemento filho do 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
    

    Observe o seguinte na consulta anterior:

    • A terceira etapa na expressão especifica uma expressão de predicado cujo valor é 3. Portanto, o valor verdadeiro do predicado dessa expressão é True só para aqueles nós cuja posição de contexto é 3.

    • A terceira etapa também especifica um caractere curinga (*) que indica todos os nós no teste de nó. Porém, o predicado filtra os nós e retorna apenas o nó na terceira posição.

    • A consulta retorna o terceiro nó do elemento filho do elemento filho <Features> do elemento filho do <ProductDescription> do documento raiz.

  3. Se o valor da expressão do predicado é um valor de tipo simples de tipo Booleano, o valor verdadeiro do predicado é igual ao valor da expressão do predicado.

    Por exemplo, a consulta a seguir é especificada em um tipo de variável xmlque detém uma instância XML, a instância XML de pesquisa do cliente. A consulta recupera aqueles clientes que têm filhos. Nessa consulta, que seria <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
    

    Observe o seguinte na consulta anterior:

    • A expressão no loop for tem duas etapas, e a segunda etapa especifica um predicado. O valor desse predicado é um valor de tipo Booleano. Se esse valor for True, o valor verdadeiro do predicado também será True.

    • A consulta retorna o elemento filho <Customer>, cujo valor de predicado é True, do elemento filho <Survey> do documento raiz. Este é o resultado:

      <CustomerWithChildren CustomerID="1"/> 
      
  4. Se o valor da expressão do predicado é uma seqüência que contém no mínimo um nó, o valor verdadeiro do predicado é True.

Por exemplo, a consulta a seguir recupera ProductModelID para modelos de produto cuja descrição de catálogo XML inclui no mínimo um recurso, um elemento filho do elemento <Features>, do namespace associado ao prefixo 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

Digitação estática e filtros de predicado

Os predicados também podem afetar estaticamente o tipo inferido de uma expressão. Valores inteiros literais e a função last() reduzem a cardinalidade da expressão de etapa filtrada para no máximo um.