Home - www.devmedia.com.br


Subqueries Parte II: Queries correlatas

por Paulo Ribeiro

No artigo anterior – Subqueries Parte I – vimos que uma subquery é um comando SELECT que foi "embutido" noutro comando SELECT, UPDATE, DELETE ou dentro de outra subquery. Vimos também que a finalidade da subquery é retornar um conjunto de linhas para a query principal.

Subqueries Correlatas

Quando uma subquery referencia colunas da query principal, recebe o nome de Subquery Correlata.

Diferentemente das subqueries convencionais, a Subquery Correlata será executada tantas vezes quantas forem as linhas de output da query principal, num processo de Nested Loop Join.

Exemplos de utilização de Subqueries Correlatas

Os exemplos a seguir foram executados no database-exemplo NorthWind tendo por base as tabelas Orders e Order Details.

·         Subquery Correlata na linha do SELECT: na query a seguir será listado, junto com os dados da header do pedido (=tabela Orders), a totalização de itens (=tabela Order Details).

PS: Note a relação de dependência com a query principal no filtro da subquery (... where od.orderId = o.orderId ...)

SELECT
  customerId,
  orderId,
  qtde_itens_orderId = (select sum(quantity) from [order details] od     whereod.orderId = o.orderId )
from Orders o
---------------------------------------------------------------------customerId orderId     qtde_itens_orderId
---------- ----------- ------------------
ALFKI      10643       38
ALFKI      10692       20
ALFKI      10702       21
ALFKI      10835       17
ALFKI      10952       18
ALFKI      11011       60
ANATR      10308       6
ANATR      10625       18
ANATR      10759       10
.
...
.....


·         Subquery Correlata no filtro WHERE: serão listados somente os pedidos cuja quantidade total de itens supere 250 unidades.

SELECT
  customerId,
  orderId,
  qtde_itens_orderId = (select sum(quantity) from [order details] od     where
od.orderId = o.orderId )
from Orders owhere (select sum(quantity) from [order details] od   where od.orderId = o.orderId ) > 250
order by 3
---------------------------------------------------------------------customerId orderId     qtde_itens_orderId
---------- ----------- ------------------
QUICK      10658       255
ERNSH      10990       256
SAVEA      10612       263
SAVEA      10678       280
QUICK      10515       286
SAVEA      10847       288
SAVEA      11030       330
ERNSH      10895       346

(8 row(s) affected)

·         Subquery Correlata na cáusula HAVING: no batch a seguir o total de vendas/ano é confrontado com um valor previamente armazenado numa tabela de metas de venda (=projecao). Note que a comparação acontece na cláusule HAVING, comparando o totalizador com o resultado da subquery.

create table projecao_
(
  ano int,
  vlr_total_vendas dec(10,2)
)
insert into projecao_values (1996,250000)
insert into projecao_values (1997,630000)
insert into projecao_values (1998,500000)
select Ano=year(orderdate), vlr_total_vendas=sum(unitprice *   quantity)
from orders o
inner join
     [order details] od
on o.orderId = od.orderId
group by year(orderdate)
having sum(unitprice * quantity) >=

        ( select vlr_total_vendas from projecao_where                ano=year(orderdate) )
---------------------------------------------------------------------
Ano         vlr_total_vendas     
----------- ---------------------
1997        658388.7500
(1 row(s) affected)

·         Subquery Correlata no comando UPDATE: a coluna vlr_total, criada na tabela Orders será atualizada a partir da totalização dos itens.

alter table orders drop column vlr_total
go
alter table orders add vlr_total dec(10,2)
go
update orders
   set vlr_total=
   ( select sum(unitprice * quantity)
     from [order details] od
     where od.OrderId = orders.orderId
     group by od.orderId
   )
go
--------------------------------------------------------------------(830 row(s) affected)

Conclusão

Subqueries correlatas agregam versatilidade às queries, permitindo que joins complexos sejam resolvidos com apenas um comando, sem a criação de tabelas temporárias. Um único detalhe: subqueries correlatas muitas vezes podem ser executadas como um join convencional; nesses casos vale a pena olhar o plano de execução dos dois formatos (subquery correlata X join), optando pelo mais eficiente.

Bem, essa foi a dica de hoje.

Até a próxima!

 

 

Paulo Ribeiro (psribeiro@hotmail.com) é Microsoft MCDBA e membro da equipe editorial da SQL Magazine. Atua como DBA sênior em SQL Server na Livraria e Papelaria Saraiva S/A.

  Monitorando deadlocks com Trace Flags    
  Monitorando deadlocks com o Profiler    
  Variáveis tipo TABLE    
  Tabelas Temporárias    
  Subqueries Parte II: Queries correlatas    
  Subqueries – Parte I    
  Gerenciando Bloqueios–Parte II    
  Gerenciando Bloqueios–Parte I    
  Porque qualificar o owner na chamada de stored-procedures    
  Explorando os Tipos de Join – Parte II    
  Explorando os Tipos de Join – Parte I    
  Versões existentes do SQL Server 2000    
  Tuning - Plano de Execução no SQL Server - Parte 4    
  Tuning - Plano de Execução no SQL Server - Parte 3    
  Tuning - Plano de Execução no SQL Server - Parte 2    
  Tuning - Plano de Execução no SQL Server - Parte 1    
  Tuning - Estatísticas de I/O    
  Desfragmentando Índices no SQL Server    
  Procedures Não Documentadas
no SQL Server 2000 Parte 2
   
  Procedures Não Documentadas
no SQL Server 2000.
   
  SQL Server 2005 - YUKON    
  SQL Server 2000: o Contra-Ataque.    
  Boas-Vindas    
     

 

Todos os direitos reservados: DevMedia Group
SQL Magazine - 2004