Este é um recurso muito útil na linguagem SQL permitindo colocar o resultado de consultas inteiras em uma coluna fazendo parte das linhas de uma consulta maior. Uma consulta pode ter quantas sub consultas forem necessárias, mas, existem alguns pontos de atenção:
- O resultado da sub consulta deve ser sempre escalar, ou seja, um valor único, nunca um conjunto de linhas e colunas (rowset). Pode ser necessário usar a cláusula TOP em alguns casos.
- Para evitar problemas, a sub consulta deve estar amarrada com alguma coluna da consulta principal.
- Verificar os índices das tabelas envolvidas se estão apropriados. As sub consultas têm um custo muito alto de processamento e afetam em muito o desempenho caso sejam muito complexas.
Para exemplificar vamos considerar as tabelas PERSON.PERSON, SALES.SALESORDERHEADER – armazena informações sobre vendas e SALES.CUSTOMER – Clientes para o qual a venda foi feita. O diagrama de relacionamentos pode ser conferido a seguir.
O objetivo é ter o resultado da somatória do total das vendas (SALES.SALESORDERHEADER.TotalDue) dos anos 2005 a 2007 agrupados por nome de cliente (PERSON.PERSON.FirstName e PERSON,PERSON.LastName). A instrução SQL para executar isto, trabalhando com sub consultas está demonstrada a seguir.
select concat(p.FirstName, ' ', p.LastName) as CompleteName ,( select isnull(sum(soh.TotalDue), 0) as TotalVenda from Sales.SalesOrderHeader soh join Sales.Customer cus on cus.CustomerID=soh.CustomerID join person.Person per on per.BusinessEntityID=cus.PersonID where per.BusinessEntityID=p.BusinessEntityID and year(OrderDate)=2005 ) as [2005] ,( select isnull(sum(soh.TotalDue), 0) as TotalVenda from Sales.SalesOrderHeader soh join Sales.Customer cus on cus.CustomerID=soh.CustomerID join person.Person per on per.BusinessEntityID=cus.PersonID where per.BusinessEntityID=p.BusinessEntityID and year(OrderDate)=2006 ) as [2006] ,( select isnull(sum(soh.TotalDue), 0) as TotalVenda from Sales.SalesOrderHeader soh join Sales.Customer cus on cus.CustomerID=soh.CustomerID join person.Person per on per.BusinessEntityID=cus.PersonID where per.BusinessEntityID=p.BusinessEntityID and year(OrderDate)=2007 ) as [2007] from Person.Person p
No exemplo, note que está sendo usada a função CONCAT(). Esta permite concatenar dados do tipo string (ou nvarchar, ou varchar...) de forma mais eficiente e organizada do que simplesmente usar o operador “+”. É importante observar que esta função só está disponível a partir da versão 2012 do SQL Server.
Cada sub consulta além de possuir suas joins e cláusulas de filtros próprias também está ligada com a tabela principal PERSON.PERSON através da seguinte linha:
where per.BusinessEntityID=p.BusinessEntityID
que está presente nas três sub consultas. O resultado desta consulta pode ser conferido a seguir.
Outros bons artigos sobre sub consultas podem ser conferidos nos links abaixo: