Sei sulla pagina 1di 14

8/4/2014

DevMedia - Verso para impresso

DevMedia - Verso para impresso

Usando linguagem SQL para gerao de relatrios - Parte 2


Vises e Consultas Aninhadas
De que se trata o artigo Uso de linguagem SQL para criao de relatrios, desde recursos bsicos at os mais avanados. Este o segundo artigo de uma srie e neste texto apresento tcnicas de uso de vises e consultas aninhadas, que do s consultas um grande poder de seleo de dados. A discusso deste tema auxilia o leitor iniciante em SQL a criar consultas e relatrios mais sofisticados, que funcionam de maneira parecida com a parametrizao de dados. O artigo mostra tambm como tcnicas diferentes tm impacto significativo na performance de toda consulta. Em que situao o tema til Este artigo se destina ao leitor que trabalha com bancos de dados, seja ele administrador, arquiteto ou desenvolvedor, e apresenta recursos da linguagem SQL que o auxiliam na execuo de tarefas comuns como a criao de consultas e/ou relatrios. Resumo Devman O artigo trata de tcnicas de seleo de dados que so largamente utilizadas em consultas SQL: uso de vises e o uso de consultas aninhadas. Avalia o uso de consultas aninhadas nas diferentes clusulas de uma declarao de seleo de dados e ao final mostra como significativo o impacto na performance causado por pequenas variaes na estratgia de seleo de dados.

Este o segundo artigo de uma srie que pretende apresentar recursos da linguagem SQL que ajudam na criao de relatrios. Repetindo o que escrevi no primeiro artigo: consenso entre os especialistas que SQL no a melhor linguagem para criao de consultas complexas. Apesar de esta ser uma verdade inegvel, muito comum nos depararmos com situaes em que ele, o SQL, a nica ferramenta que temos mo para criao de um relatrio. Isso ocorre muitas vezes por questo de custos, j que nem sempre economicamente vivel optar pela compra de uma soluo especializada. Este cenrio muito comum no dia-a-dia das empresas e, no fim das contas, somos forados a us-lo. Por esta razo, eu considero importante que todo profissional de banco de dados conhea os principais recursos do SQL para atender as solicitaes dos seus usurios. Neste sentido, importante relembrarmos uma definio bsica ao se trabalhar com
http://www.devmedia.com.br/websys.5/webreader_print.asp?cat=2&artigo=4194&revista=impressao_95#a-4194 1/14

8/4/2014

DevMedia - Verso para impresso

consultas SQL que a definio de expresso SQL. A definio que temos para o termo expresso bastante simples: uma expresso retorna um valor. Os tipos utilizados em uma expresso variam bastante, cobrindo diferentes tipos de dados como string, numeric e boolean. Na verdade, quase tudo que inserirmos depois do SELECT ou FROM em um comando SQL pode ser considerado uma expresso. Caso voc queria encontrar um item ou grupo de itens em particular em seu banco de dados, voc precisar fazer uso de uma ou mais condies em suas queries. Podemos definir condies em consultas SQL utilizando a clusula where. Vimos no artigo anterior vrios recursos teis da linguagem SQL que nos ajudam na criao de relatrios. Neste texto atual, apresentaremos recursos da linguagem SQL para gerao de objetos especiais para manipulao dos dados, como vises e consultas aninhadas. O leitor com alguma familiaridade com SQL j deve ter visto tais recursos, por isso acrescentaremos aqui um estudo de performance para auxili-lo a explorar estas tcnicas de forma otimizada. Este material foi extrado de uma palestra sobre recursos oferecidos pelo DB2, porm iremos priorizar nestes artigos os recursos e as sintaxes que sejam padro ANSI SQL, ou seja, que esto ou deveriam estar disponveis em qualquer sistema gerenciador de bancos de dados (SGBD). Neste artigo, vamos falar do uso dos seguintes recursos SQL: Vises; Consultas aninhadas na clusula WHERE; Consultas aninhadas na clusula FROM; Consultas aninhadas na clusula SELECT. Na teoria de banco de dados, uma viso (view) consiste de uma consulta armazenada acessvel como uma tabela virtual em um banco de dados relacional ou um conjunto de documentos em um banco de dados orientado a documentos, composto pelo conjunto de resultados de uma consulta. Ao contrrio de tabelas comuns (tabelas base) em um banco de dados relacional, uma viso no faz parte do esquema fsico: uma tabela virtual dinmica computada a partir de dados no banco de dados. Alterar os dados em uma tabela altera os dados mostrados nas invocaes subsequentes da viso. Em alguns bancos de dados NoSQL as vises so a nica forma de consulta a dados. Vises podem oferecer vantagens sobre tabelas nos seguintes aspectos: Vises podem representar apenas um subconjunto dos dados contidos em uma tabela; Vises podem juntar e simplificar vrias tabelas em uma tabela virtual nica; Vises podem funcionar como tabelas agregadas, atravs dos mecanismos de agregao do banco de dados (sum, average, etc.) e apresenta os resultados calculados como parte dos dados; Vises podem esconder a complexidade dos dados, por exemplo, uma viso poderia se chamar Vendas2000 ou Vendas2001, particionando transparentemente a tabela bsica real; Vises ocupam muito pouco espao de armazenamento, o banco de dados contm apenas a definio de uma viso e no uma cpia de todos os dados que ele apresenta; Dependendo do SGBD utilizado, vises podem fornecer a segurana extra; Vises podem limitar o grau de exposio de uma ou mais tabelas para o mundo exterior. Assim como funes (function, na programao) podem fornecer abstrao, usurios do banco de dados podem criar abstraes usando vises. Em outro paralelo com as funes, os usurios do banco de dados podem manipular vises aninhadas, assim, uma viso pode agregar dados de outras vises. Sem o uso de vises a normalizao de bases de dados alm da segunda forma normal se tornaria muito mais difcil. Vises podem tornar mais fcil a
http://www.devmedia.com.br/websys.5/webreader_print.asp?cat=2&artigo=4194&revista=impressao_95#a-4194 2/14

8/4/2014

DevMedia - Verso para impresso

criao de junes sem perdas de decomposio. Assim como as linhas em uma tabela base no tm qualquer ordem definida, as linhas disponveis atravs de uma viso no aparecem com qualquer classificao padro. A viso uma tabela relacional e o modelo relacional define uma tabela como um conjunto de linhas. Uma vez que as tabelas no so ordenadas - por definio - as linhas de uma viso tambm no so ordenadas. Portanto, uma clusula ORDER BY na definio de exibio no tem sentido. O padro SQL ANSI 2003 no permite que uma clusula ORDER BY em uma consulta SQL na instruo CREATE VIEW, assim como no permitida na instruo CREATE TABLE. No entanto, dados ordenados podem ser obtidos a partir de uma viso, da mesma forma como qualquer outra tabela - como parte de uma instruo de consulta. No entanto, alguns SGBDs (como Oracle e SQL Server) permitem uma viso a ser criada com uma clusula ORDER BY em uma subquery, afetando como os dados so exibidos. Em uma consulta SQL ao banco de dados, uma subconsulta (consulta aninhada dentro de outra consulta) uma consulta que utiliza os valores da consulta externa em sua clusula WHERE. A subconsulta avaliada uma vez para cada linha processada pela consulta externa. Voc pode usar uma subconsulta para os seguintes fins: Definir um conjunto de linhas que precisam ser inseridos em uma tabela; Definir um conjunto de resultados que ser usado para criao de uma viso; Definir um ou mais valores de uma instruo de atualizao (UPDATE); Fornecimento de valores para as clusulas WHERE, HAVING e START WITH para instrues SELECT, UPDATE e DELETE.

Base de dados e consideraes


Continuaremos a usar a mesma base de dados apresentada no primeiro artigo. Este banco de dados contm dados fictcios de demanda de produtos farmacuticos. A Figura 1 mostra o diagrama desta base.
[abrir im age m e m jane la]

Figura 1. Modelo de dados da base de exemplo.

Vises
As vises (do ingls views) so talvez os objetos mais comuns nos bancos de dados, mais at
http://www.devmedia.com.br/websys.5/webreader_print.asp?cat=2&artigo=4194&revista=impressao_95#a-4194 3/14

8/4/2014

DevMedia - Verso para impresso

do que as prprias tabelas. De certo modo, as vises so tabelas virtuais, ou seja, elas se parecem com tabelas, mas as vises buscam dados que esto fisicamente armazenados em uma ou mais tabelas. Para o usurio, as vises se parecem tanto com as tabelas que fica difcil dizer com qual objeto se est trabalhando. J para os administradores de bancos de dados (DBAs), as vises so um excelente recurso para gerenciamento da segurana dos dados. Afinal, elas so objetos que funcionam somente para leitura, ou em outras palavras, no se consegue alterar dados atravs de vises (existem tipos especiais de vises que so exceo, mas no sero discutidas aqui). Alm disso, o administrador pode criar vises de modo a restringir o acesso apenas a determinados campos da tabela, impedindo por exemplo a leitura de campos especiais. Portanto, se voc no o DBA do banco de dados com o qual costuma trabalhar, provavelmente voc j acessou vises pensando que lia tabelas. As vises funcionam como declaraes de SELECT precompiladas, que so executadas quando o objeto correspondente solicitado. Virtualmente, qualquer SELECT pode ser salvo como viso. Basta para isso usar a sintaxe CREATE VIEW nome AS, seguida da declarao em questo. Uma exceo importante que as vises no aceitam a clusula ORDER BY. At existem recursos para se burlar esta limitao, mas a entramos no terreno das famosas gambiarras. O melhor mesmo respeitar o limite, a menos que seja realmente necessrio. Outra situao muito comum de uso de vises a de guardar de uma maneira simples consultas e/ou subconsultas que so executadas com muita frequncia. Esta abordagem interessante porque pode simplificar bastante o trabalho dos desenvolvedores, reduzindo a complexidade das declaraes SQL. Vamos ver um exemplo. Digamos que uma consulta muito frequente no nosso banco de dados seja a identificao do ranking de produtos mais vendidos no ms anterior. Esta consulta usada para uma srie de relatrios e, para no termos que reescrev-la em todos os relatrios, vamos trat-la como uma viso. Primeiramente vamos definir esta viso. Precisamos criar uma consulta de agregao que calcule a demanda por produto ocorrida no ms passado. Para isso, vamos precisar das tabelas de demanda e de produto (veja na Figura 1). Usaremos a funo de agregao SUM() para totalizar a demanda e agruparemos os dados por produtos. Para tornar a viso mais til, importante incluir o cdigo dos produtos, uma vez que todas as junes com outras tabelas e/ou vises sero feitas atravs destes cdigos. Como as vises no consideram ordenao de dados (e nem devem faz-lo), vamos esquecer a questo do ranking e apresentar apenas a demanda de cada produto. Para filtrar as datas, precisamos definir algo que seja genrico, do contrrio vamos ter que criar uma nova viso a cada mudana do ms. Existem muitas maneiras de se criar este filtro e cada SGBD traz seus prprios registros e funes para trabalhar com datas. (Veja informaes adicionais a este respeito na seo LEITURA RECOMANDADA). Eu preferi construir este filtro usando recursos o mais prximos possveis do padro ANSI SQL, ento usamos funes escalares como MONTH(), YEAR(), RIGHT() e a funo CAST(), que usada para converso de tipos de dados. Usaremos tambm o registro especial CURRENT_TIMESTAMP, que retorna a hora atual do sistema com preciso de (pelo menos) milissegundos, alm de estar implementado numa grande variedade de SGDBs relacionais, como DB2, ORACLE, SQL SERVER, FIREBIRD e POSTGRES. A ideia selecionar datas que estejam entre o dia 1 e o ltimo dia do ms anterior. Como no muito simples identificar o ltimo dia de cada ms, fica mais fcil dizer que a data
http://www.devmedia.com.br/websys.5/webreader_print.asp?cat=2&artigo=4194&revista=impressao_95#a-4194 4/14

8/4/2014

DevMedia - Verso para impresso

desejada tem que ser maior ou igual ao 1 dia do ms anterior e menor do que o 1 dia do ms atual. Algo do tipo "Data >= 01/MesAnterior AND Data < 01/MesAtual". Usando as funes e registros de sistema citados acima, o filtro de datas ficar parecido com o apresentado na Listagem 1.
Listagem 1. Parametrizao do filtro de datas do ms anterior.
D a t a> =C A S T ( Y E A R ( C U R R E N T _ T I M E S T A M P )A SV A R C H A R )-a n o + R I G H T ( ' 0 ' + C A S T ( ( M O N T H ( C U R R E N T _ T I M E S T A M P ) 1 )A SV A R C H A R ) , 2 )-m e s +' 0 1 '-d i a A N D D a t a<C A S T ( Y E A R ( C U R R E N T _ T I M E S T A M P )A SV A R C H A R )-a n o +R I G H T ( ' 0 ' + C A S T ( ( M O N T H ( C U R R E N T _ T I M E S T A M P ) )A SV A R C H A R ) , 2 )-m e s+' 0 1 '-d i a

O leitor mais atento vai observar que a lgica da Listagem 1 tem uma falha: no funciona durante o ms de Janeiro. Na realidade, este problema com datas mais fcil de se resolver usando funes definidas pelo usurio (ou UDF), pois vai facilitar inclusive o entendimento da declarao SQL, j que esta lgica vai estar encapsulada numa funo. Porm as UDFs sero estudadas apenas no prximo artigo da srie. Por isso voltaremos a esta questo quando tratarmos do assunto. Por hora, vamos considerar que esta soluo adequada. Colocando tudo para funcionar e definindo a consulta como uma viso, temos o SQL apresentado na Listagem 2.
Listagem 2. Criao da viso com demanda por produto no ms anterior.
C R E A T EV I E Wv w D e m a n d a P r o d u t o M e s P a s s a d oA S S E L E C TP . p k P r o d u t o ,P . P r o d u t o ,S U M ( T . V a l o r R e a l )A SD e m a n d a F R O Mt b l D e m a n d aT I N N E RJ O I Nt b l P r o d u t oPO NT . f k P r o d u t o=P . p k P r o d u t o W H E R ET . D a t a> =C A S T ( Y E A R ( C U R R E N T _ T I M E S T A M P )A SV A R C H A R ) +R I G H T ( ' 0 ' + C A S T ( M O N T H ( C U R R E N T _ T I M E S T A M P )-1A SV A R C H A R ) ,2 ) +' 0 1 ' A N DT . D a t a<C A S T ( Y E A R ( C U R R E N T _ T I M E S T A M P )A SV A R C H A R ) +R I G H T ( ' 0 ' + C A S T ( M O N T H ( C U R R E N T _ T I M E S T A M P )A SV A R C H A R ),2 ) +' 0 1 ' G R O U PB YP . p k P r o d u t o ,P . P r o d u t o ;

A sentena da Listagem 2 para definio de uma viso pode ser executada em diferentes SGBDs, uma vez que usamos recursos padro ANSI SQL. Agora vamos usar esta viso na gerao de um relatrio simples: ranking com os 10 produtos mais vendidos no ms anterior. Como a viso j traz estas informaes, basta fazermos a ordenao dos dados e apresentarmos apenas os 10 primeiros registros. Porm, como comentamos no artigo anterior, cada SGBD usa um recurso diferente para fazer esta exibio. A Listagem 3 mostra a declarao SQL deste relatrio no DB2. No SQL SERVER, a mudana seria pequena, j que teramos que usar o SELECT TOP para esta seleo (veja Listagem 4).
Listagem 3. Sintaxe do DB2 para apresentao dos produtos mais vendidos.
S E L E C TP r o d u t o ,D e m a n d a F R O Mv w D e m a n d a P r o d u t o M e s P a s s a d o O R D E RB YD e m a n d aD E S C F E T C HF I R S T1 0R O W SO N L Y

http://www.devmedia.com.br/websys.5/webreader_print.asp?cat=2&artigo=4194&revista=impressao_95#a-4194

5/14

8/4/2014

DevMedia - Verso para impresso

Listagem 4. Sintaxe do SQL Server para apresentao dos produtos mais vendidos.
S E L E C TT O P1 0P r o d u t o ,D e m a n d a F R O Mv w D e m a n d a P r o d u t o M e s P a s s a d o O R D E RB YD e m a n d aD E S C

Como as consultas mostradas nas Listagens 3 e 4 fazem a mesma coisa (s que em SGBDs diferentes), o resultado obviamente ser idntico, como vemos na Tabela 1. Existem vises que usam recursos especiais para melhorar a performance, por exemplo, no caso de vises que manipulam grandes volumes de dados. Estas vises costumam combinar a gravao de dados (fisicamente) num objeto especial, separado das tabelas fonte, e criar uma estratgia de indexao destes dados. O nome deste tipo de viso varia conforme o fornecedor do SGBD, mas as estratgias de melhoria de performance so parecidas: no DB2, elas so chamadas de Materialized Query Tables, no ORACLE so Materialized Views e no SQL SERVER so Indexed Views. A sintaxe de implementao destas vises varia conforme o SGBD e por esta razo no iremos nos estender neste assunto. O leitor interessado pode consultar os links apresentados na seo REFERNCIAS.

[abrir im age m e m jane la]

Tabela 1. Resultado da consulta das Listagens 3 e 4.

Consultas aninhadas na clusula WHERE


Quando usamos consultas dentro de outras consultas, damos a elas o nome de consultas aninhadas ou tambm subconsultas. Este um recurso largamente utilizado em SQL e multiplica consideravelmente o poder da linguagem. Pode-se usar consultas aninhadas em praticamente todas as clusulas SQL. Como nosso objetivo aqui a gerao de relatrios, vamos nos ater ao uso de consultas aninhadas em declaraes de SELECT, mas fica subentendido que estes recursos tambm podem ser usados em declaraes de INSERT, UPDATE e mesmo DELETE. Vamos a um primeiro exemplo, usando uma consulta aninhada na clusula WHERE. Considere que faremos um relatrio que identifica quais cidades tiveram demanda na data de 24/dezembro/2010 exclusivamente para os trs produtos mais vendidos nos ltimos 30 dias. Precisamos montar este SQL agrupando os dados de demanda por cidade. Para isso, vemos
http://www.devmedia.com.br/websys.5/webreader_print.asp?cat=2&artigo=4194&revista=impressao_95#a-4194 6/14

8/4/2014

DevMedia - Verso para impresso

na Figura 1 que precisaremos das tabelas de demanda, brick e cidade (j que a tabela de demanda no tem dados por cidade e sim por brick, como explicamos no ltimo artigo). A entra o problema: no queremos TODA demanda ocorrida nestas cidades, mas sim s a demanda dos trs produtos mais vendidos. Identificar estes produtos fcil, basta usar a viso vwDemandaProdutoMesPassado que criamos anteriormente e ela nos retorna a lista de cdigos de produto desejados. O que precisamos fazer usar esta lista como um novo filtro na clusula WHERE (veja Listagem 5).
Listagem 5. Usando consulta aninhada para filtrar produtos com maior demanda.
S E L E C TC . C i d a d e ,S U M ( T . V a l o r R e a l )A SD e m a n d a F R O Mt b l D e m a n d aT I N N E RJ O I Nt b l B r i c kBO NT . f k B r i c k=B . p k B r i c k I N N E RJ O I Nt b l C i d a d eCO NB . f k C i d a d e=C . p k C i d a d e W H E R ET . D a t a=' 2 0 1 0 1 2 2 4 ' A N DT . f k P r o d u t oI N( S E L E C Tp k P r o d u t o F R O Mv w D e m a n d a P r o d u t o M e s P a s s a d o O R D E RB YD e m a n d aD E S C F E T C HF I R S T3R O W SO N L Y ) G R O U PB YC . C i d a d e O R D E RB Y1

Como se v na Listagem 5, temos uma consulta dentro da outra, mas muito fcil identificlas. Eu usei a sintaxe do DB2 para seleo dos 3 melhores produtos (FETCH FIRST n ROWS ONLY), mas a converso desta sintaxe para outros SGBDs bastante simples, como mostramos no primeiro artigo da srie. Vamos a outro exemplo. No primeiro artigo da srie, mostramos uma consulta SQL para criao de um relatrio de demanda dos produtos Eupressin Cpr 20 Mg X 30 e o Norvasc Cpr 10 Mg X 30 por estado da regio Sul no primeiro trimestre de 2011. Observe que temos trs filtros, um para as datas do 1 trimestre/2011, outro para os produtos Eupressin Cpr 20 Mg X 30 e o Norvasc Cpr 10 Mg X 30 e o terceiro que queremos um relatrio de demanda por Estado, mas s aqueles que pertencem regio Sul. Como explicamos anteriormente, precisaremos de seis tabelas (veja Figura 1): de demanda, produtos, bricks, cidades, estados e regies. Na clusula SELECT, precisamos apenas dos campos Estado, Produto e da somatria da demanda. Mas existe um detalhe interessante neste relatrio que no apresentamos naquela oportunidade. Como o relatrio deve exibir um agrupamento por estado e por produto, precisamos destas duas tabelas como parte da clusula FROM. Mas no precisamos da tabela de regies ali, porque esta tabela s usada para filtro e no na clusula SELECT. Portanto, este um exemplo perfeito de quando podemos substituir junes por consultas aninhadas e obter um resultado mais eficaz. Esta declarao mostrada na Listagem 6.
Listagem 6. Demanda por estado, usando consultas aninhadas.
S E L E C TE . E s t a d o ,P . P r o d u t o ,S U M ( T . V a l o r R e a l )A SD e m a n d a F R O Mt b l D e m a n d aT I N N E RJ O I Nt b l B r i c kBO NT . f k B r i c k=B . p k B r i c k I N N E RJ O I Nt b l C i d a d eCO NB . f k C i d a d e=C . p k C i d a d e I N N E RJ O I Nt b l E s t a d oEO NC . f k E s t a d o=E . p k E s t a d o I N N E RJ O I Nt b l P r o d u t oPO NT . f k P r o d u t o=P . p k P r o d u t o W H E R ET . D a t aB E T W E E N' 2 0 1 1 0 1 0 1 'A N D' 2 0 1 1 0 3 3 1 ' A N DE . f k R e g i a o=( S E L E C TR . p k R e g i a o

http://www.devmedia.com.br/websys.5/webreader_print.asp?cat=2&artigo=4194&revista=impressao_95#a-4194

7/14

8/4/2014

DevMedia - Verso para impresso


F R O Mt b l R e g i a oR W H E R ER . R e g i a o=' S U L ' ) A N DP . P r o d u t oI N( ' E U P R E S S I NC P R2 0M GX3 0 ' , ' N O R V A S CC P R1 0M GX3 0 ' ) G R O U PB YE . E s t a d o ,P . P r o d u t o ;

Consultas aninhadas na clusula FROM


Em muitos relatrios, necessrio cruzar os dados de uma consulta com os dados de outro objeto, como uma tabela ou viso. Nestes casos, uma soluo usar consultas aninhadas na clusula FROM. Para decidir se voc deve criar a consulta aninhada no FROM ou em outra clusula qualquer, voc tem que analisar se a consulta aninhada precisa retornar campos que sero usados na clusula SELECT. Neste caso, ela tem que fazer parte da clusula FROM. Vamos ver um exemplo onde precisamos de um relatrio que tenha a demanda total no ms passado para os 5 principais produtos, que vamos chamar de Demanda, a demanda total do ms passado, chamada DemandaTotal, e a participao do produto na demanda total, que demos o nome de Participacao. Este ltimo campo calculado como a razo entre demanda do produto e demanda total (que nos d a frmula Participacao = Demanda/DemandaTotal * 100). A estratgia aqui usar a viso vwDemandaProdutoMesPassado para termos a demanda dos 5 principais produtos e combin-la com uma subconsulta para termos a demanda total de todos os produtos. E por que necessrio usarmos uma consulta aninhada na clusula FROM? Ora, porque precisamos destes dois campos para calcularmos a participao dos produtos na demanda total! Veja a seguir como fica esta declarao (Listagem 7) e o seu resultando (Tabela 2) .
Listagem 7. Participao dos 5 principais produtos na demanda total.
S E L E C TS . P r o d u t o ,S . D e m a n d a ,Q . D e m a n d a T o t a l , S . D e m a n d a / Q . D e m a n d a T o t a l*1 0 0A SP a r t i c i p a c a o F R O Mv w D e m a n d a P r o d u t o M e s P a s s a d oS , ( S E L E C TS U M ( X . D e m a n d a )A SD e m a n d a T o t a l F R O Mv w D e m a n d a P r o d u t o M e s P a s s a d oX )Q O R D E RB YS . D e m a n d aD E S C F E T C HF I R S T5R O W SO N L Y ;

[abrir im age m e m jane la]

Tabela 2. Resultado da consulta da Listagem 7.

Com um pouco de ateno, muito fcil entender o que faz a consulta da Listagem 7. A sintaxe clara, as informaes esto todas no lugar certo e a declarao em si razoavelmente simples (ou curta, se preferir). Veja que usamos a viso vwDemandaProdutoMesPassado duas vezes na clusula FROM,
http://www.devmedia.com.br/websys.5/webreader_print.asp?cat=2&artigo=4194&revista=impressao_95#a-4194 8/14

8/4/2014

DevMedia - Verso para impresso

uma diretamente e a segunda como parte de um subconsulta. Agora imagine como ficaria esta declarao (Listagem 7) se ns no tivssemos criado esta viso (veja novamente a Listagem 2)! A simplicidade e facilidade de leitura que mencionamos seriam totalmente perdidas. Esta consulta ilustra bem o uso de consultas aninhadas na clusula FROM, mas esta no a nica maneira de escrev-la. Existem outras estratgias para se criar este relatrio e voltaremos a falar deste exemplo ao longo desta srie de artigos.

Consultas aninhadas na clusula SELECT


Tambm possvel usar subconsultas na clusula SELECT, mas este um caso bastante especial e deve ser usado com muito cuidado. Em geral, usamos a subconsulta nesta clusula quando precisamos execut-la tomando como parmetros valores que so retornados pela consulta mais externa. Ou seja, a subconsulta na clusula SELECT reexecutada para registro da consulta externa! Portanto, fica evidente que essa estratgia um tanto perigosa e tem potencial para "derrubar" o seu servidor de banco de dados. Vejamos um exemplo mostrado por Joe Celko no seu livro "SQL for Smarties" (veja seo REFERNCIAS). Ele mostra uma tcnica de clculo de ranqueamento de registros usando uma consulta aninhada na clusula SELECT. A subconsulta faz uma contagem do nmero de registros que tem valor maior ou igual ao valor do registro da consulta principal. A Listagem 8 adapta a declarao SQL da Listagem 7, incluindo a coluna "Ranking". E na Tabela 3 temos o relatrio correspondente.
Listagem 8. Participao dos 5 principais produtos com Ranking.
S E L E C TS . P r o d u t o ,S . D e m a n d a ,Q . D e m a n d a T o t a l , S . D e m a n d a / Q . D e m a n d a T o t a l*1 0 0A SP a r t i c i p a c a o , ( S E L E C TC O U N T ( * ) F R O Mv w D e m a n d a P r o d u t o M e s P a s s a d oX W H E R EX . D e m a n d a> =S . D e m a n d a )A SR a n k i n g F R O Mv w D e m a n d a P r o d u t o M e s P a s s a d oS , ( S E L E C TS U M ( X . D e m a n d a )A SD e m a n d a T o t a l F R O Mv w D e m a n d a P r o d u t o M e s P a s s a d oX )Q O R D E RB YS . D e m a n d aD E S C F E T C HF I R S T5R O W SO N L Y ;

[abrir im age m e m jane la]

Tabela 3. Resultado da consulta da Listagem 8.

Note que a Listagem 8 traz duas consultas aninhadas, uma na clusula FROM, que j usamos na Listagem 7, mais a nova subconsulta na clusula SELECT. Observe tambm que esta subconsulta usa um filtro, comparando o valor de demanda do registro da consulta aninhada, identificado com o apelido X, com o valor do registro atual da consulta externa, identificado
http://www.devmedia.com.br/websys.5/webreader_print.asp?cat=2&artigo=4194&revista=impressao_95#a-4194 9/14

8/4/2014

DevMedia - Verso para impresso

com o apelido S. Esta comparao quem garante a contagem correta dos registros, identificando assim a ordenao que desejamos. Mas lembre-se: a contagem, isto , a subconsulta, repetida para cada registro da consulta externa. Esta tcnica de ranqueamento antiga, usada com recursos padro ANSI SQL-92. Atualmente temos outros recursos para conseguir estes resultados. Mas, como voc j deve ter desconfiado, voltaremos a falar desta questo num dos prximos artigos desta srie. Um segundo exemplo: relatrio para calcular saldo em estoque. Para este exemplo, vamos usar uma tabela especial: a tabela de movimentos de estoque, definida na Listagem 9, onde os valores positivos indicam entradas no estoque e os valores negativos so as sadas do estoque.
Listagem 9. Criao da tabela de Movimento de Estoque
C R E A T ET A B L Ep r o d . t b l M o v t o E s t o q u e( f k P r o d u t oI N T D a t a Q t d N O TN U L L ,

I D A T EN O TN U L L , I N T N O TN U L L ,

C O N S T R A I N Tp k M o v t o E s t o q u eP R I M A R YK E Y( f k P r o d u t o ,D a t a ) ) ;

I N S E R TI N T Op r o d . t b l M o v t o E s t o q u eV A L U E S ( 2 2 1 7 2 0 ,' 2 0 1 0 0 1 0 1 ' ,1 0 0 0 ) , ( 2 2 1 7 2 0 ,' 2 0 1 0 0 1 0 2 ' ,1 0 0 ) , ( 2 2 1 7 2 0 ,' 2 0 1 0 0 1 0 3 ' ,1 5 0 ) , ( 2 2 1 7 2 0 ,' 2 0 1 0 0 1 0 4 ' ,2 0 0 ) , ( 2 2 1 7 2 0 ,' 2 0 1 0 0 1 0 5 ' ,5 0 ) , ( 2 2 1 7 2 0 ,' 2 0 1 0 0 1 0 6 ' ,1 0 0 ) , ( 5 7 8 8 4 0 ,' 2 0 1 0 0 1 0 5 ' ,1 0 0 0 ) , ( 5 7 8 8 4 0 ,' 2 0 1 0 0 1 0 6 ' ,8 0 ) , ( 5 7 8 8 4 0 ,' 2 0 1 0 0 1 0 7 ' ,1 5 0 ) , ( 5 7 8 8 4 0 ,' 2 0 1 0 0 1 0 8 ' ,2 5 0 ) , ( 5 7 8 8 4 0 ,' 2 0 1 0 0 1 0 9 ' ,5 0 0 ) , ( 5 7 8 8 4 0 ,' 2 0 1 0 0 1 1 0 ' ,3 5 0 ) ;

Como a inteno calcular o saldo dirio por produto, a consulta precisa identificar todas as entradas e sadas de cada produto at a data em questo. E no podemos esquecer que os dados precisam obrigatoriamente estar ordenados na forma desejada. Considerando tudo isso, usamos uma consulta aninhada que calcula a coluna Saldo, como se v na declarao SQL da Listagem 10. A seguir, temos o resultado desta consulta na Tabela 4, em que destacamos em negrito as linhas que identificam o incio do balano para cada produto.
Listagem 10. Saldo em Estoque por Produto
S E L E C Tf k P r o d u t o ,D a t a ,Q t d ,( S E L E C TS U M ( Q t d ) F R O Mp r o d . t b l M o v t o E s t o q u eS W H E R ES . f k P r o d u t o=T . f k P r o d u t o A N DS . D a t a< =T . D a t a )A SS a l d o F R O Mp r o d . t b l M o v t o E s t o q u eT O R D E RB Y1 ,2 ;

[abrir im age m e m jane la]

http://www.devmedia.com.br/websys.5/webreader_print.asp?cat=2&artigo=4194&revista=impressao_95#a-4194

10/14

8/4/2014

DevMedia - Verso para impresso

Tabela 4. Resultado da consulta da Listagem 10.

De maneira geral, quando voc imaginar que precisa usar consultas aninhadas na clusula SELECT, fique atento a trs condies: se sua subconsulta precisa mesmo interagir com os registros da consulta externa; atendida a condio anterior, verifique se esta subconsulta pode ou no ser substituda por uma juno de tabelas; se passar nos dois primeiros testes, fique atento com o nmero de registros retornados pela consulta externa. Lembre-se que uma consulta aninhada na clusula SELECT ser executada para cada registro retornado pela consulta externa. Ento imagine, por exemplo, uma consulta que retorne 10.000 registros. Mesmo que o otimizador de consultas do seu SGBD seja muito bom, muito provvel que esta consulta cause impacto significativo no seu servidor!

Consideraes sobre performance


Quando criamos relatrios, alguns cuidados especiais precisam ser tomados para garantir que os ndices existentes nas tabelas sejam usados adequadamente. Muitas vezes um pequeno deslize pode ter efeitos catastrficos. Por exemplo: a incluso de um campo com cdigo do produto na viso que definimos parece algo irrelevante, mas no . Todos os cdigos deste banco so indexados, o que uma boa prtica em termos de manuteno de bancos de dados. Graas existncia do campo cdigo nesta viso, qualquer juno ou filtro poder usar diretamente ndices existentes no banco, melhorando a performance. Vamos analisar mais um destes casos. Voltemos definio da viso que vimos no incio deste artigo. L, o filtro dos dados era feito atravs do campo data, com algo parecido com "Data >= 01/MesAnterior AND Data < ; 01/MesAtual". Vamos fazer trs testes aqui mudando apenas a clusula WHERE e veremos como isso afeta a performance da consulta. Observe que os trs casos estudados so verses de uma mesma consulta, ou seja, elas vo retornar exatamente o mesmo resultado, selecionando dados em uma tabela com pouco mais de 2 milhes de registros. Eu executei estes testes no SQL SERVER 2008 e mostraremos a seguir o grfico do plano de execuo de cada uma das
http://www.devmedia.com.br/websys.5/webreader_print.asp?cat=2&artigo=4194&revista=impressao_95#a-4194 11/14

8/4/2014

DevMedia - Verso para impresso

consultas. No primeiro caso, faremos a consulta usando parmetros fixos (ou escalares se preferir). A Listagem 11 mostra esta declarao. Esta consulta no deve ser salva como uma viso, j que ela traz datas fixas. Mas este exemplo ilustra bem a questo de performance. Veja na Figura 2 o plano de execuo e no destaque o custo estimado desta rvore, que de 0,865938. No segundo teste, vamos considerar a verso parametrizada que usamos inicialmente, fazendo uso do registro de sistema CURRENT_TIMESTAMP e outras funes padro ANSI SQL, apresentadas novamente na Listagem 12. Note que a consulta da Listagem 12 sempre busca dados do ms anterior ao ms corrente e isso que precisamos.

[abrir im age m e m jane la]

Figura 2. Plano de execuo da consulta da Listagem 11.

Listagem 11. Datas fixas


S E L E C TP . P r o d u t o ,S U M ( T . V a l o r R e a l )A SD e m a n d a F R O Mt b l D e m a n d aT I N N E RJ O I Nt b l P r o d u t oPO NT . f k P r o d u t o=P . p k P r o d u t o W H E R ET . D a t a> =' 0 8 / 0 1 / 2 0 1 1 ' A N DT . D a t a<' 0 9 / 0 1 / 2 0 1 1 ' G R O U PB YP . P r o d u t o

Listagem 12. Datas parametrizadas


S E L E C TP . P r o d u t o ,S U M ( T . V a l o r R e a l )A SD e m a n d a F R O Mt b l D e m a n d aT I N N E RJ O I Nt b l P r o d u t oPO NT . f k P r o d u t o=P . p k P r o d u t o W H E R ET . D a t a> =C A S T ( Y E A R ( C U R R E N T _ T I M E S T A M P )A SV A R C H A R ) +R I G H T ( ' 0 ' + C A S T ( M O N T H ( C U R R E N T _ T I M E S T A M P )-1A SV A R C H A R ) ,2 ) +' 0 1 ' A N DT . D a t a<C A S T ( Y E A R ( C U R R E N T _ T I M E S T A M P )A SV A R C H A R ) +R I G H T ( ' 0 '+C A S T ( M O N T H ( C U R R E N T _ T I M E S T A M P )A SV A R C H A R ),2 ) +' 0 1 ' G R O U PB YP . P r o d u t o

Ela at parece um pouco complexa, mas no final das contas estamos comparando os valores do campo DATA com dois valores calculados. Note na Figura 3 que o plano de execuo bastante parecido com o da Figura 2, apesar dela ter um custo bem maior: 1,77682 (105% maior que o custo da primeira consulta). Mas claro que o filtro usado no a nica opo de parametrizao. No prximo teste, filtramos os dados comparando o ms e o ano de cada registro. Parece uma melhoria, j que a lgica do filtro bem mais simples, como se v na Listagem 13.

http://www.devmedia.com.br/websys.5/webreader_print.asp?cat=2&artigo=4194&revista=impressao_95#a-4194

12/14

8/4/2014

DevMedia - Verso para impresso


[abrir im age m e m jane la]

Figura 3. Plano de execuo da consulta da Listagem 12.

Listagem 13. Comparao por ms


S E L E C TP . P r o d u t o ,S U M ( T . V a l o r R e a l )A SD e m a n d a F R O Mt b l D e m a n d aT I N N E RJ O I Nt b l P r o d u t oPO NT . f k P r o d u t o=P . p k P r o d u t o W H E R EM O N T H ( T . D a t a )=( M O N T H ( C U R R E N T _ T I M E S T A M P )-1) A N DY E A R ( T . D a t a )=( Y E A R ( C U R R E N T _ T I M E S T A M P )) G R O U PB YP . P r o d u t o

Esta aparente simplicidade terrivelmente enganosa, porque aqui fazemos duas operaes para cada registro: calcular o ms e o ano do campo DATA. Considerando que a tabela grande (mais de 2 milhes de registros), esta operao certamente vai ter um custo alto. E de fato isso que acontece, pois o custo total de execuo desta rvore sobe para 9,94425 (veja no quadro em destaque da Figura 4)! Este nmero 5,5 vezes maior do que o custo da consulta anterior e 11,5 vezes maior que a consulta com datas fixas. Para concluir esta seo, apresentamos a compilao de todos os testes na Tabela 5.

[abrir im age m e m jane la]

Figura 4. Plano de execuo da consulta da Listagem 13.

[abrir im age m e m jane la]

Tabela 5. Compilao dos testes de performance.

http://www.devmedia.com.br/websys.5/webreader_print.asp?cat=2&artigo=4194&revista=impressao_95#a-4194

13/14

8/4/2014

DevMedia - Verso para impresso

Pode parecer redundante este comentrio, mas a importncia do tema o permite: sempre tome cuidado com as declaraes SQL que escreve. Pequenas alteraes podem ter grandes impactos em matria de performance!

Concluso
Vimos aqui como criar e usar vises e como lidar com consultas aninhadas. Estes so recursos muito poderosos e que esto disponveis h muito tempo. Mas eles ampliam em muito a gama de relatrios que podemos criar com declaraes SQL e o leitor interessado precisa aprender a us-los corretamente. No prximo artigo, vamos estudar recursos programveis da linguagem SQL, como funes definidas pelo usurio (UDFs), discutindo tanto as funes escalares como as tabulares. Espero que tenha gostado das informaes apresentadas. At breve!

Wagner Crivelini
Engenheiro formado pela UNICAMP, consultor em TI com 15 anos de experincia, particularmente em projetos de Business Intelligence. Atualmente trabalha na IBM, onde atua como DBA em projeto internacional.

http://www.devmedia.com.br/websys.5/webreader_print.asp?cat=2&artigo=4194&revista=impressao_95#a-4194

14/14

Potrebbero piacerti anche