Tenha uma iniciação rápida com o DB2 V9 pureXML, Parte 4: Consulte dados XML do DB2 com XQuery

O IBM DB2® V9 para Linux®, UNIX® e Windows®(R) oferece novos e significativos recursos de suporte ao armazenamento, gerenciamento e pesquisa de dados XML, designados como pureXML. Esta série o ajudará a dominar rapidamente esses novos recursos por meio de vários artigos passo a passo que explicam como executar tarefas fundamentais. Neste artigo, você aprenderá a consultar dados armazenados em colunas XML usando o XQuery. [25 de março de 2010: Originalmente redigido em 2006, este artigo foi atualizado para incluir alterações nas versões 9.5 e 9.7 do DB2.--Ed.]

Don Chamberlin, IBM Fellow, EMC

Don Chamberlin, um IBM Fellow no Centro de Pesquisas Almaden, é um dos representantes da IBM no W3C XML Query Working Group. Também é coautor da proposta da linguagem Quilt, na qual o projeto do XQuery foi baseado. Don é mais conhecido como um dos inventores da linguagem de banco de dados SQL e autor de dois livros sobre o sistema de banco de dados DB2. É formado pelo Harvey Mudd College, com doutorado na Universidade de Stanford. Também é um ACM Fellow e membro da Academia Nacional de Engenharia.



Cynthia M. Saracco, Kiến trúc giải pháp cao cấp, EMC

Cindy Saracco photoC. M. Saracco trabalha com o Laboratório da IBM no Vale do Silício na organização de XML no DB2. Ela trabalha no gerenciamento de banco de dados, XML, desenvolvimento de aplicativo da Web e assuntos relacionados.



16/Abr/2010 (Primeira publicação 16/Abr/2010)

Você provavelmente já ouviu falar do DB2 V9 -- O primeiro sistema de gerenciamento de banco de dados da IBM com suporte a estruturas de dados tanto tabulares (baseadas em SQL) como hierárquicas (baseadas em XML). Os artigos anteriores da série resumiram os novos recursos de XML do DB2, descreveram como criar objetos de banco de dados e preenchê-los com dados XML e explicaram como trabalhar com dados XML usando SQL e SQL/XML. Este artigo continua a explorar os recursos de XML do DB2, concentrando-se em seu novo suporte a XQuery.

O DB2 trata XQuery como uma linguagem de primeira classe, permitindo que os usuários escrevam expressões diretamente em XQuery, em vez de exigir que incorporem ou agrupem XQueries em instruções SQL. Além disso, o mecanismo de consulta do DB2 processa XQueries nativamente, o que significa que ele analisa, avalia e otimiza XQueries sem jamais traduzi-las para SQL em segundo plano. Evidentemente, se você optar por escrever consultas bilíngues incluindo expressões tanto em XQuery como em SQL, o DB2 também processará e otimizará essas consultas.

Como é feito com SQL/XML na Parte 3 desta série, este artigo explora várias tarefas de consulta comuns e explica como você pode usar XQuery para atingir seus objetivos. Em primeiro lugar, considere como XQuery difere de SQL.

Sobre XQuery

XQuery difere de SQL em vários aspectos fundamentais, principalmente porque as linguagens foram projetadas para trabalhar com diferentes modelos de dados, que têm diferentes características. Os documentos XML contêm hierarquias e possuem uma ordem intrínseca. As estruturas de dados tabulares suportadas por DBMSs baseados em SQL são planas e baseadas em conjuntos. Como tal, as linhas não são ordenadas.

As diferenças entre esses modelos de dados resultam em várias diferenças fundamentais em suas respectivas linguagens de consulta, inclusive as seguintes:

  • XQuery suporta expressões de caminho para permitir que os programadores naveguem através da estrutura hierárquica de XML, ao contrário do que acontece com SQL simples (sem extensões XML).
  • XQuery suporta dados tanto tipificados como não tipificados, enquanto os dados SQL sempre são definidos com um tipo específico.
  • XQuery não possui valores nulos, porque os documentos XML omitem dados ausentes ou desconhecidos. SQL, obviamente, usa valores nulos para representar valores de dados ausentes ou desconhecidos.
  • XQuery retorna sequências de dados XML, enquanto SQL retorna conjuntos de resultados de vários tipos de dados SQL.

Este é um subconjunto das diferenças fundamentais entre XQuery e SQL. Está além do escopo deste artigo fornecer uma lista exaustiva, mas um artigo no IBM Systems Journal discute mais detalhadamente as diferenças entre as linguagens. Este artigo concentra-se em alguns aspectos básicos da linguagem XQuery e como ela pode ser usada para consultar dados XML no DB2 V9.


Banco de dados de exemplo

As consultas neste artigo acessam as tabelas de exemplo criadas na Parte 1 desta série. Para uma revisão rápida, a Listagem 1 define as tabelas de exemplo items e clients.

Listagem 1. Definições de tabelas
create table items (
id 		int primary key not null, 
brandname 	varchar(30), 
itemname 	varchar(30), 
sku 		int, 
srp 		decimal(7,2), 
comments 	xml
)

create table clients(
id 		int primary key not null, 
name 		varchar(50), 
status 		varchar(10), 
contactinfo 	xml
)

Os dados XML de exemplo incluídos na coluna items.comments são mostrados na Listagem 2, enquanto os dados XML de exemplo incluídos na coluna clients.contactinfo são mostrados na Listagem 3. Os exemplos de consultas subsequentes irão se referir a elementos específicos de um ou de ambos documentos XML.

Listagem 2. Documento XML de exemplo armazenado na coluna Comments da tabela Items
<Comments>
	<Comment>
		<CommentID>133</CommentID>
		<ProductID>3926</ProductID>
		<CustomerID>8877</CustomerID>
		<Message>Heels on shoes wear out too quickly.</Message>
		<ResponseRequested>No</ResponseRequested>
	</Comment>
	<Comment>
		<CommentID>514</CommentID>
		<ProductID>3926</ProductID>
		<CustomerID>3227</CustomerID>
		<Message>Where can I find a supplier in San Jose?</Message>
		<ResponseRequested>Yes</ResponseRequested>
	</Comment>
</Comments>
Listagem 3. Documento XML de exemplo armazenado na coluna Contactinfo da tabela Clients
<Client>
	<Address>
		<street>5401 Julio Ave.</street>
		<city>San Jose</city>
		<state>CA</state>
		<zip>95116</zip>
	</Address>
	<phone>
		<work>4084630000</work>
		<home>4081111111</home>
		<cell>4082222222</cell>
	</phone>
	<fax>4087776666</fax>
	<email>love2shop@yahoo.com</email>
</Client>

Ambiente de consulta

Todas as consultas neste artigo são projetadas para serem emitidas interativamente. Isso pode ser feito por meio do processador de linha de comando do DB2 ou pelo DB2 Command Editor, no DB2 Control Center. As imagens de tela e as instruções neste artigo concentram-se no segundo. (O IBM Data Studio e o IBM Optim Development Studio são fornecidos com um Developer Workbench baseado em Eclipse que também pode ajudar os programadores a construir consultas graficamente. Este artigo não discute questões de desenvolvimento de aplicativos ou o Development Studio.)

Para usar o DB2 Command Editor, inicie o Control Center e selecione Tools > Command Editor. Uma janela semelhante à da Figura 1 aparecerá.

Figura 1. O DB2 Command Editor, que pode ser iniciado a partir do DB2 Control Center
Shows an SQL query in the top pane, and a record of commands entered in bottom pane

Digite suas consultas no painel superior, clique na seta verde no canto superior esquerdo para executá-las e visualize a saída no painel inferior ou na guia Query Results separada.


Exemplos XQuery

Assim como na Parte 3 da série, este artigo descreve passo a passo vários cenários comerciais comuns e mostra como usar XQuery para satisfazer solicitações de dados XML. Também são exploradas situações mais complexas que envolvem a integração de SQL a XQuery.

XQuery fornece vários tipos diferentes de expressões que podem ser combinadas como você quiser. Cada expressão retorna uma lista de valores que podem ser usados como entrada para outras expressões. O resultado da expressão mais externa é o resultado da consulta.

Este artigo enfoca dois tipos importantes de expressões XQuery: Expressões FLWOR e expressões de caminho. Uma expressão FLWOR é muito semelhante à expressão SELECT-FROM-WHERE em SQL: ela é usada para iterar através de uma lista de itens e, opcionalmente, retornar algo que é calculado com base em cada item. Uma expressão de caminho, por outro lado, navega através de uma hierarquia de elementos XML e retorna os elementos encontrados no final do caminho.

Como uma expressão SELECT-FROM-WHERE em SQL, uma expressão FLWOR em XQuery pode conter várias cláusulas que começam com certas palavras-chave. As seguintes palavras-chave são usadas para iniciar cláusulas em uma expressão FLWOR:

  • for: Itera através de uma sequência de entrada, ligando uma variável a cada item de entrada individual
  • let: Declara uma variável e atribui a ela um valor, que pode ser uma lista contendo vários itens
  • where: Especifica critérios para filtrar resultados da consulta
  • order by: Especifica a ordem de classificação do resultado
  • return: Define o resultado a ser retornado

Uma expressão de caminho em XQuery consiste em uma série de etapas, separadas por caracteres de barra. Em sua forma mais simples, cada etapa navega em sentido descendente em uma hierarquia XML para localizar os filhos dos elementos retornados pela etapa anterior. Cada etapa em uma expressão de caminho também pode conter um predicado que filtra os elementos retornados por essa etapa, retendo apenas os elementos que satisfazem alguma condição. Por exemplo, presumindo que a variável $clients está ligada a uma lista de documentos XML que contêm elementos <Client>, a expressão de caminho em quatro etapas $clients/Client/Address[state = "CA"]/zip retornará a lista de códigos de endereçamento postal de clientes cujos endereços estão na Califórnia.

Em muitos casos, é possível escrever uma consulta usando tanto uma expressão FLWOR como uma expressão de caminho.

Usando DB2 XQuery como uma linguagem de consulta de nível mais alto

Para executar uma XQuery diretamente no DB2 V9 (em vez de integrá-la a uma instrução SQL), é necessário preceder a consulta com a palavra-chave xquery. Isso instrui o DB2 a invocar seu analisador de XQuery para processar a solicitação. Observe que só é necessário fazer isso se você estiver usando XQuery como a linguagem mais externa (ou de nível mais alto). Se você integrar expressões XQuery a SQL, não precisará precedê-las com a palavra-chave xquery. Entretanto, como este artigo usa XQuery como a linguagem principal, todas as consultas são precedidas por xquery.

Quando é executada como uma linguagem de nível superior, XQuery deve ter uma fonte de dados de entrada. Uma maneira pela qual XQuery pode obter dados de entrada é chamar uma função chamada db2-fn:xmlcolumn com um parâmetro que identifica o nome da tabela e o nome de uma coluna XML em uma tabela do DB2. A função db2-fn:xmlcolumn retorna a sequência de documentos XML armazenada na coluna especificada. Por exemplo, a consulta da Listagem 4 a seguir retorna uma sequência de documentos XML contendo informações de contato de clientes.

Listagem 4. XQuery simples para retornar dados de contato de clientes
 xquery db2-fn:xmlcolumn('CLIENTS.CONTACTINFO')

Como você talvez se lembre de nosso esquema de banco de dados (consulte a seção "Banco de dados de exemplo"), os documentos XML são armazenados na coluna Contactinfo da tabela Clients. Observe que os nomes da coluna e da tabela são especificados em maiúsculas aqui. A razão é que os nomes de tabela e de coluna geralmente são convertidos para maiúsculas antes de serem gravados no catálogo interno do DB2. Como XQuery faz distinção entre maiúsculas e minúsculas, nomes de tabela e de coluna em minúsculas não corresponderiam aos nomes em maiúsculas no catálogo do DB2.

Recuperando elementos XML específicos

Agora exploraremos uma tarefa básica. Suponha que você queira recuperar os números de fax de todos os clientes que lhe forneceram essa informação. A Listagem 5 mostra uma maneira de escrever essa consulta.

Listagem 5. Expressão FLWOR para recuperar dados de fax dos clientes
 xquery  for $y in db2-fn:xmlcolumn('CLIENTS.CONTACTINFO')/Client/fax return $y

A primeira linha determina ao DB2 que invoque seu analisador de XQuery. A próxima linha determina ao DB2 que itere através dos subelementos fax dos elementos Client contidos na coluna CLIENTS.CONTACTINFO. Cada elemento fax é ligado por sua vez à variável $y. A terceira linha indica que, para cada iteração, o valor de $y é retornado. O resultado é uma sequência de elementos XML, como é mostrado na Listagem 6.

Listagem 6. Exemplo de saída da consulta anterior
 <fax>4081112222</fax> <fax>5559998888</fax>

A propósito, a saída também conterá algumas informações que não são de grande interesse para este artigo: versão de XML e dados de codificação, como <?xml version="1.0" encoding="windows-1252" ?>, e informações do espaço de nomes XML, como <fax xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">. Para facilitar a compreensão da saída, essas informações são omitidas neste artigo. Entretanto, elas podem ser importantes para diferentes aplicativos XML. Se você usar o processador de linha de comando do DB2 para executar suas consultas, poderá usar a opção -d para suprimir as informações de declaração XML e a opção -i para imprimir os resultados de maneira atraente.

A consulta mostrada na Listagem 5 poderia ser expressa de maneira ligeiramente mais concisa como uma expressão de caminho em três etapas, como é mostrado na Listagem 7.

Listagem 7. Expressão de caminho para recuperar dados de fax de clientes
 xquery  db2-fn:xmlcolumn('CLIENTS.CONTACTINFO')/Client/fax

A primeira etapa da expressão de caminho chama a função db2-fn:xmlcolumn para obter uma lista de documentos XML na coluna CONTACTINFO da tabela CLIENTS. A segunda etapa retorna todos os elementos Client nesses documentos, e a terceira etapa retorna os elementos fax aninhados nesses elementos Client.

Se você não estiver interessado em obter fragmentos XML com sua consulta e, em vez disso, quiser apenas uma representação em texto dos valores dos elementos XML que se qualificam, poderá invocar a função text() na cláusula return, como é mostrado na Listagem 8.

Listagem 8. Duas consultas para recuperar a representação em texto dos dados de fax de clientes
xquery  
for $y in db2-fn:xmlcolumn('CLIENTS.CONTACTINFO')/Client/fax 
return $y/text() 

 (or)  

xquery 
db2-fn:xmlcolumn('CLIENTS.CONTACTINFO')/Client/fax/text()

A saída dessas consultas será semelhante à que é mostrada na Listagem 9.

Listagem 9. Exemplo de saída das consultas anteriores
 4081112222 5559998888

Os resultados das consultas de exemplo são relativamente simples porque o elemento fax é baseado em um tipo de dados primitivo. Evidentemente, elementos podem ser baseados em tipos complexos, o que significa que eles podem conter subelementos (ou hierarquias aninhadas). O elemento Address das informações de contato do cliente é um exemplo disso. Segundo o esquema definido na Parte 2 desta série, ele pode conter um endereço, número de apartamento, cidade, estado e CEP. Considere o que o XQuery na Listagem 10 retornaria.

Listagem 10. Expressão FLWOR para recuperar um tipo XML complexo
 xquery  for $y in db2-fn:xmlcolumn('CLIENTS.CONTACTINFO')/Client/Address return $y

Se respondeu que o retorno seria uma sequência de fragmentos XML contendo elementos Address e todos os seus subelementos, você acertou. A Listagem 11 mostra um exemplo:

Listagem 11. Exemplo de saída da consulta anterior
 <Address>   
   <street>5401 Julio Ave.</street>   
   <city>San Jose</city>   
   <state>CA</state>   
   <zip>95116</zip> 
</Address> 
. . .  
<Address>   
   <street>1204 Meridian Ave.</street>   
   <apt>4A</apt>   
   <city>San Jose</city>   
   <state>CA</state>   
   <zip>95124</zip> 
</Address>

Observação: Esse exemplo de saída está formatado para facilitar a leitura. O DB2 Command Editor exibe cada registro de endereço de cliente em uma linha.

Filtragem de valores de elementos XML

É possível refinar os exemplos anteriores de XQuery para torná-los mais seletivos. Por exemplo, considere como retornar os endereços postais de todos os clientes que moram na área identificada pelo CEP 95116 nos Estados Unidos.

Como você poderia imaginar, a cláusula where de XQuery permite filtrar os resultados com base no valor do elemento zip nos documentos XML. A Listagem 12 mostra como adicionar uma cláusula where à expressão FLWOR anterior da Listagem 10 para obter apenas os endereços que lhe interessam.

Listagem 12. Expressão FLWOR com uma nova cláusula "where"
xquery 
for $y in db2-fn:xmlcolumn('CLIENTS.CONTACTINFO')/Client/Address
where $y/zip="95116"
return $y

A cláusula where adicionada é muito fácil de entender. A cláusula for liga a variável $y a um endereço de cada vez. A cláusula where contém uma pequena expressão de caminho que navega de cada endereço para seu elemento zip aninhado. A cláusula where é verdadeira (e o endereço é retido) apenas se o valor desse elemento zip é igual a 95116.

O mesmo resultado poderia ser obtido adicionando um predicado à expressão de caminho, como é mostrado na Listagem 13.

Listagem 13. Expressão de caminho com predicado de filtragem adicional
 xquery db2-fn:xmlcolumn('CLIENTS.CONTACTINFO')/Client/Address[zip="95116"]

Evidentemente, é possível filtrar com base em valores de CEP e retornar elementos não relacionados a endereços postais. Além disso, também é possível filtrar vários valores de elementos XML em uma única consulta. A consulta na Listagem 14 retorna informações de e-mail de clientes que vivem em um CEP específico na cidade de Nova York (10011) ou em qualquer parte da cidade de San Jose.

Listagem 14. Filtragem de vários valores de elementos XML com uma expressão FLWOR
xquery  
for $y in db2-fn:xmlcolumn('CLIENTS.CONTACTINFO')/Client
where $y/Address/zip="10011" or $y/Address/city="San Jose" 
return $y/email

Observe que a cláusula for é alterada de modo para ligar a variável $y a elementos Client em vez de elementos Address. Isso lhe permite filtrar os elementos Client por uma parte da subárvore (Address) e retornar outra parte da subárvore (e-mail). As expressões de caminho na cláusula where e na cláusula return devem ser escritas com relação ao elemento que é ligado à variável (no caso, $y).

A mesma consulta pode ser expressa de forma ligeiramente mais concisa como uma expressão de caminho, como é mostrado na Listagem 15.

Listagem 15. Filtragem em vários valores de elementos XML com uma expressão de caminho
xquery  
db2-fn:xmlcolumn('CLIENTS.CONTACTINFO')/Client[Address/zip="10011"   
or Address/city="San Jose"]/email;

O que não é tão óbvio ao analisar ambas as formas dessa consulta é que os resultados retornados diferirão de duas maneiras significativas daquilo que um programador de SQL poderia esperar:

  1. Não serão retornados dados XML para clientes qualificados que não forneceram um endereço de e-mail. Em outras palavras, se você tem 1000 clientes que vivem em San Jose ou no CEP 10011, dos quais 700 lhe forneceram um endereço de e-mail, você obterá uma lista em que serão retornados esses 700 endereços de e-mail. Isso decorre de uma diferença fundamental entre XQuery e SQL mencionada anteriormente: XQuery não usa valores nulos.
  2. Você não saberá quais endereços de e-mail foram derivados do mesmo documento XML. Em outras palavras, se você tem 700 clientes que vivem em San Jose ou no CEP 10011 e cada um lhe forneceu dois endereços de e-mail, você obterá uma lista em que serão retornados 1400 elementos de e-mail. Você não obterá uma sequência 700 registros, cada um consistindo em dois endereços de e-mail.

Ambas as situações podem ser desejáveis em algumas circunstâncias e indesejáveis em outras. Por exemplo, se você precisar enviar um aviso por e-mail para cada conta qualificada existente no registro, é fácil usar um aplicativo para iterar através de uma lista de endereços de e-mail de clientes em formato XML. Porém, se você quiser enviar apenas um aviso por e-mail a todos os clientes, inclusive aqueles que só lhe forneceram um endereço postal, o XQuery mostrado anteriormente não será suficiente.

Há várias maneiras de reescrever essa consulta de modo que os resultados retornados representem as informações ausentes de alguma maneira e indiquem quando vários endereços de e-mail forem derivados do mesmo registro de cliente, ou seja, do mesmo documento XML (como será visto mais adiante). Entretanto, se quiser apenas recuperar uma lista contendo um endereço de e-mail para cada cliente qualificado, você poderá modificar ligeiramente a cláusula return da consulta anterior.

Listagem 16. Recuperando apenas o primeiro elemento de e-mail de cada cliente
xquery  
for $y in db2-fn:xmlcolumn('CLIENTS.CONTACTINFO')/Client 
where $y/Address/zip="10011" or $y/Address/city="San Jose" 
return $y/email[1]

Essa consulta faz o DB2 retornar o primeiro elemento de e-mail que encontra em cada documento XML qualificado (registro de contato de cliente). Se ela não encontrar um endereço de e-mail para um cliente qualificado, nenhum dado relativo a esse cliente será retornado.

Transformando a saída XML

Um aspecto poderoso de XQuery é sua capacidade de transformar a saída XML de um formato XML para outro. Por exemplo, é possível usar XQuery para recuperar total ou parcialmente os documentos XML armazenados e converter a saída em HTML para facilitar a exibição em um navegador da Web. A consulta na Listagem 17 recupera os endereços dos clientes, classifica os resultados por CEP e converte a saída em elementos XML que fazem parte de uma lista HTML não ordenada.

Listagem 17. Consultando dados XML do DB2 e retornando resultados como HTML
xquery  
<ul> { 
for $y in db2-fn:xmlcolumn('CLIENTS.CONTACTINFO')/Client/Address 
order by $y/zip 
return <li>{$y}</li>  
} </ul>

A consulta pode ser desmembrada da seguinte maneira:

  • A consulta começa de maneira simples com a palavra-chave xquery para indicar ao analisador do DB2 que XQuery está sendo usada como a linguagem principal.
  • A segunda linha faz a marcação HTML de uma lista não ordenada (<ul>) ser incluída nos resultados. Ela também introduz uma chave, a primeira de dois pares usados nessa consulta. As chaves instruem o DB2 a avaliar e processar a expressão delimitada em vez de tratá-la como uma cadeia de caractere literal.
  • A terceira linha itera através dos endereços de clientes, ligando a variável $y a um elemento de endereço por vez.
  • A quarta linha inclui uma nova cláusula order by, especificando que os resultados deverão ser retornados em ordem crescente (a ordem padrão) de CEP do cliente (o subelemento zip de cada endereço ligado a $y).
  • A cláusula return indica que os elementos Address devem ser circundados por marcas HTML de item de lista antes de serem retornados.
  • A última linha conclui a consulta e insere a marca HTML de lista não ordenada.

A saída será semelhante à da Listagem 18.

Listagem 18. Exemplo de saída HTML da consulta anterior
<ul>   <li>  
    <Address> 
        <street>9407 Los Gatos Blvd.</street>  
        <city>Los Gatos</city>   
        <state>CA</state>   
        <zip>95032</zip>   
   </Address>   
</li>   
<li>      
   <Address>   
       <street>4209 El Camino Real</street>          
       <city>Mountain View</city>         
       <state>CA</state>        
       <zip>95033</zip>     
   </Address>   
</li>
 . . .  
</ul>

Agora considere um tópico mencionado anteriormente: como escrever uma XQuery que indique valores ausentes nos resultados retornados, indicando também quando um único documento XML (por exemplo, um único registro de cliente) contém elementos repetidos (por exemplo, vários endereços de e-mail). Uma maneira de fazer isso é agrupar a saída retornada em um novo elemento XML, como é mostrado na consulta da Listagem 19:

Listagem 19. Indicando valores ausentes e elementos repetidos em um resultado de XQuery
xquery  
for $y in db2-fn:xmlcolumn('CLIENTS.CONTACTINFO')/Client 
where $y/Address[zip="10011"] or $y/Address[city="San Jose"] 
return <emailList> {$y/email} </emailList>

A execução dessa consulta retornará uma sequência de elementos emailList, um para cada registro de cliente qualificado. Cada elemento emailList contém dados de e-mail. Se encontrar um único endereço de e-mail no registro de um cliente, o DB2 retornará esse elemento e seu valor. Se encontrar vários endereços de e-mail, ele retornará todos os elementos de e-mail e seus valores. Finalmente, se não encontrar nenhum endereço de e-mail, ele retornará um elemento emailList vazio. Portanto, a saída poderá ser semelhante à que é mostrada na Listagem 20.

Listagem 20. Exemplo de saída da consulta anterior
<emailList>

   <email>love2shop@yahoo.com</email>
</emailList>
<emailList/>
<emailList>
   <email>beatlesfan36@hotmail.com</email>
   <email>lennonfan36@hotmail.com</email>

</emailList>       
. . .

Usando lógica condicional

A capacidade de XQuery de transformar saída XML pode ser combinada ao seu suporte integrado ao uso de lógica condicional para reduzir a complexidade do código do aplicativo. Considere um exemplo simples. A tabela Items inclui uma coluna XML contendo comentários sobre produtos feitos pelos clientes. Para os clientes que solicitaram uma resposta a seus comentários, você poderia criar novos elementos Action contendo o ID do produto, ID do cliente e mensagem de modo que essas informações pudessem ser encaminhadas à pessoa apropriada para processamento. Entretanto, os comentários que não exigem resposta também são importantes para a empresa e não convém simplesmente ignorá-los. Em vez disso, você criaria um elemento Info contendo apenas o ID do produto e a mensagem. Aqui está como você poderia usar uma expressão if-then-else em XQuery para executar essa tarefa:

Listagem 21. Usando uma expressão "if-then-else" em uma XQuery
xquery 
for $y in db2-fn:xmlcolumn('ITEMS.COMMENTS')/Comments/Comment 
return ( 
	if ($y/ResponseRequested = 'Yes') 
		then <action>
			{$y/ProductID, 
			 $y/CustomerID, 
			 $y/Message}
		      </action>
		else ( <info>
			{$y/ProductID, 
			 $y/Message}
			</info>
		)
)

A esta altura, você deve estar familiarizado com a maioria dos aspectos dessa consulta; portanto, concentre-se na lógica condicional. A cláusula if determinar se o valor do subelemento ResponseRequested de um dado comentário é igual a Yes. Em caso afirmativo, a cláusula then é avaliada, fazendo o DB2 retornar um novo elemento (action) que contém três subelementos: ProductID, CustomerID e Message. Caso contrário, a cláusula else é avaliada e o DB2 retorna um elemento Info contendo apenas o ID do produto e os dados da mensagem.

Usando a cláusula let

Agora você já viu como usar todas as partes de uma expressão FLWOR, exceto a cláusula let. Essa cláusula é usada para atribuir um valor (possivelmente contendo uma lista com vários itens) a uma variável que pode ser usada em outras cláusulas da expressão FLWOR.

Suponha que você queira fazer uma lista do número de comentários recebidos para cada produto. Isso pode ser feito com a consulta da Listagem 22.

Listagem 22. Usando a cláusula "let"
xquery
for $p in distinct-values
     (db2-fn:xmlcolumn('ITEMS.COMMENTS')/Comments/Comment/ProductID)
let $pc := db2-fn:xmlcolumn('ITEMS.COMMENTS')
        /Comments/Comment[ProductID = $p]
return
   <product>
          <id> { $p } </id> 
          <comments> { count($pc) } </comments>
   </product>

A função distinct-values na cláusula for retorna uma lista de todos os valores distintos de ProductID encontrados dentro de comentários na coluna Comments da tabela Items. A cláusula for liga a variável $p a um valor ProductID por vez. Para cada valor de $p, a cláusula let varre novamente a coluna Items e liga a variável $pc a uma lista contendo todos os comentários cujo ProductID corresponde ao ProductID em $p. A cláusula return constrói um novo elemento de produto para cada valor de ProductID distinto. Cada um desses elementos de produto contém dois subelementos: um elemento id contendo o valor de ProductID e um elemento comments contendo uma contagem do número de comentários recebidos para esse produto específico.

O resultado da consulta de exemplo poderá ser semelhante ao da Listagem 23.

Listagem 23. Exemplo de saída da consulta anterior
<product>
     <id>3926</id>
     <comments>28</comments>

</product>
<product>
      <id>4097</id>
      <comments>13</comments>
</product>

XQueries com SQL integrada

Neste ponto, você já viu como escrever XQueries que recuperam fragmentos de documentos XML, criam novos formatos de saída XML e retornam diferentes saídas com base em condições especificadas na própria consulta. Em suma, você conheceu algumas maneiras de usar XQuery para consultar dados XML armazenados no DB2.

É claro que há mais a ser aprendido sobre XQuery do que este breve artigo cobre. Mas ainda há um tópico amplo que não foi abordado: como integrar SQL a XQuery. Isso pode ser útil quando você precisar escrever consultas que filtram dados com base nos valores de colunas XML e não XML.

Como você deve estar lembrado, a Parte 3 desta série mostrou como integrar expressões XQuery simples a uma instrução SQL para executar essa tarefa. Veremos agora como fazer o contrário: integrar SQL a XQuery para restringir os resultados com base tanto em valores de dados SQL tradicionais como em valores de elementos XML.

Em vez da função db2-fn:xmlcolumn, que retorna todos os dados XML em uma coluna ou tabela, pode-se chamar a função db2-fn:sqlquery, que executa uma consulta SQL e retorna apenas os dados selecionados. A consulta SQL passada para db2-fn:sqlquery deve retornar dados XML. Esses dados XML, por sua vez, podem ser processados por XQuery.

A consulta na Listagem 24 recupera informações sobre comentários em produtos cujo preço de varejo sugerido (srp) é superior a US$ 100 que incluem uma solicitação de resposta do cliente. Lembre-se que os dados de preço são armazenados em uma coluna decimal SQL, enquanto os comentários dos clientes são armazenados como XML. Os dados retornados, incluindo o ID do produto, ID do cliente e mensagem do cliente, são incluídos em um único elemento de ação XML para cada comentário qualificado armazenado no banco de dados.

Listagem 24. Integrando SQL a uma XQuery
xquery 
for $y in 
db2-fn:sqlquery('select comments from items where srp > 100')/Comments/Comment 
where $y/ResponseRequested="Yes"
return (
   <action>
          {$y/ProductID, 
           $y/CustomerID, 
           $y/Message}
  </action>
)

Como a maior parte dessa consulta deve lhe parecer familiar a esta altura, examinaremos a nova função: db2-fn:sqlquery. O DB2 processa a instrução SQL SELECT fornecida a essa função para determinar quais linhas contêm informações sobre itens cujo preço é superior a US$ 100. Os documentos armazenados nessas linhas servem como entrada para uma expressão de caminho que retorna todos os elementos Comment aninhados. As porções subsequentes da consulta usam a cláusula XQuery where para filtrar adicionalmente os dados retornados e para transformar partes dos comentários selecionados em novos fragmentos XML.

Com isso em mente, considere como você resolveria um problema ligeiramente diferente. Imagine que você queira uma lista de todos os endereços de e-mail de clientes Gold que vivem em San Jose. Além disso, se tiver vários endereços de e-mail para um único cliente, você quer que todos sejam incluídos na saída como parte de um único registro de cliente. Finalmente, se um cliente Gold qualificado não tiver fornecido um e-mail, você quer recuperar seu endereço postal. A Listagem 25 mostra uma maneira de escrever essa consulta:

Listagem 25. Integrando SQL a uma XQuery que inclui lógica condicional
xquery 
for $y in 
db2-fn:sqlquery('select contactinfo from clients where status=''Gold'' ')/Client
where $y/Address/city="San Jose"
return (
     if ($y/email) then <emailList>{$y/email}</emailList>
     else $y/Address   
)

Dois aspectos dessa consulta merecem alguma explicação. Em primeiro lugar, a instrução SELECT integrada na segunda linha contém um predicado de consulta baseado na coluna Status, comparando o valor dessa coluna VARCHAR à cadeia de caractere Gold. Em SQL, essas cadeias de caractere são delimitadas por aspas simples. Observe que, embora o exemplo pareça estar usando aspas duplas, na verdade são usadas duas aspas simples antes e após o valor de comparação (''Gold''). As aspas simples adicionais são caracteres de escape. Se usar aspas duplas delimitando o predicado de uma consulta baseada em cadeia de caractere, em vez de pares de aspas simples, você receberá uma mensagem de erro.

Além disso, a cláusula return nessa consulta contém lógica condicional para determinar se um elemento de e-mail está presente em um determinado registro de cliente. Em caso afirmativo, a consulta retorna um novo elemento emailList contendo todos os endereços de e-mail do cliente (ou seja, todos os elementos de e-mail para esse cliente). Caso contrário, ela retorna o endereço postal do cliente (ou seja, o elemento Address desse cliente).

Indexação

Deve-se ressaltar que é possível criar índices XML especializados para acelerar o acesso aos dados armazenados em colunas XML. Como este é um artigo introdutório e os dados de exemplo são limitados, o tópico não é abordado aqui. Porém, em ambientes de produção, a definição de índices apropriados pode ser crucial para alcançar o máximo desempenho. Consulte os Recursos para obter mais informações sobre a tecnologia de indexação do DB2.


Resumo

XQuery difere de SQL de maneiras significativas, várias das quais são abordadas neste artigo. Aprender mais sobre a linguagem o ajudará a determinar quando ela pode ser mais benéfica para o seu trabalho, bem como a entender quando pode ser útil combinar XQuery a SQL. Outros artigos desta série descrevem como desenvolver aplicativos Java que exploram os recursos de XML do DB2. Por enquanto, porém, este artigo inclui um exemplo simples em Java que mostra como um aplicativo Java pode integrar uma XQuery.

Agradecimentos

Obrigado a George Lapis, Matthias Nicola e Gary Robinson pela revisão deste artigo.

Recursos

Aprender

Obter produtos e tecnologias

  • Elabore seu próximo projeto de desenvolvimento com o software de teste IBM, disponível para download diretamente no developerWorks.
  • Agora é possível usar o DB2 gratuitamente. Faça o download do DB2 Express-C, uma versão sem custos do DB2 Express Edition para a comunidade, que oferece os mesmos recursos de dados centrais que o DB2 Express Edition e fornece uma base sólida para construir e implementar aplicativos.

Discutir

Comentários

developerWorks: Conecte-se

Los campos obligatorios están marcados con un asterisco (*).


Precisa de um ID IBM?
Esqueceu seu ID IBM?


Esqueceu sua senha?
Alterar sua senha

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

 


A primeira vez que você entrar no developerWorks, um perfil é criado para você. Informações no seu perfil (seu nome, país / região, e nome da empresa) é apresentado ao público e vai acompanhar qualquer conteúdo que você postar, a menos que você opte por esconder o nome da empresa. Você pode atualizar sua conta IBM a qualquer momento.

Todas as informações enviadas são seguras.

Elija su nombre para mostrar



Ao se conectar ao developerWorks pela primeira vez, é criado um perfil para você e é necessário selecionar um nome de exibição. O nome de exibição acompanhará o conteúdo que você postar no developerWorks.

Escolha um nome de exibição de 3 - 31 caracteres. Seu nome de exibição deve ser exclusivo na comunidade do developerWorks e não deve ser o seu endereço de email por motivo de privacidade.

Los campos obligatorios están marcados con un asterisco (*).

(Escolha um nome de exibição de 3 - 31 caracteres.)

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

 


Todas as informações enviadas são seguras.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=80
Zone=Information Management
ArticleID=483303
ArticleTitle=Tenha uma iniciação rápida com o DB2 V9 pureXML, Parte 4: Consulte dados XML do DB2 com XQuery
publish-date=04162010