Este primeiro exemplo demonstra como podemos colocar uma subquery no lugar de uma coluna que será retornada na instrução SELECT:
SELECT C1 , ( SELECT C2 FROM Tabela2 ) AS C2 , C3
FROM Tabela1
No exemplo acima, as coluna C1 e C3 pertencem à Tabela1 e o campo C2 é um campo calculado através de uma subquery. A subquery obtém o campo C2 da Tabela2.
Aqui já podemos observar alguns pontos importantes:
– O primeiro deles é que sempre devemos colocar uma subquery entre parênteses, pois assim o SQL Server consegue saber que estamos nos referindo a uma subquery.
– Outro ponto importante é que mesmo se a Tabela2 (a que está sendo utilizada na subquery) possuir mais de um campo, somente poderemos retornar um campo, pois a query mais externa somente irá receber o conteúdo de um campo.
– Também podemos perceber que não correlacionamos de nenhuma maneira a Tabela2 com a Tabela1.
Também podemos utilizar o resultado de uma subquery na cláusula WHERE da instrução SELECT como no exemplo abaixo:
SELECT ProductName, QuantityPerUnit
FROM Products
WHERE UnitPrice = ( SELECT MAX(UnitPrice) FROM Products )
Primeiramente o que a instrução SELECT mais interna (Subquery) faz é retornar o preço máximo de todos o produtos da tabela Products, através da função de agregação MAX(). Feito isto, este valor é comparado com todos os produtos e somente aqueles que possuírem o valor máximo serão retornados pela query mais externa.
Com as subquerys também podemos retornar uma lista de valores, dependendo de qual operador é utilizado. Veja alguns exemplos:
/* Aqui somente é retornado os clientes que fizeram compras antes da data atual */
SELECT CompanyName,ContactName FROM customers
WHERE CustomerID IN (SELECT CustomerID from orders WHERE OrderDate < GETDATE())
/* Aqui é retornado todos os clientes que já fizeram algum pedido.*/
SELECT CompanyName,ContactName FROM customers
WHERE EXISTS (SELECT CustomerID from orders)
Para os exemplos vistos até agora não nos preocupamos em correlacionar as tabelas que são utilizadas tanto na query mais interna (subquery) como na mais externa (a query final). Para fazer isto, devemos primeiramente dar um alias para cada tabela e fazer a relação entre estes alias na subquery pois os alias da query mais externa são “enxergados” na query mais interna. Exemplo:
SELECT P.PED_COD , P.PED_DATA , P.COD_CLI ,
FROM PEDIDO AS P
WHERE P.COD_CLI
IN ( SELECT C.COD_CLI FROM CLIENTE C WHERE P.COD_CLI = C.COD_CLI )
SELECT ShipName,ShippedDate FROM orders O
WHERE CustomerID IN (SELECT CustomerID FROM Customers C WHERE O.CustomerID=C.CustomerID)
No exemplo acima estamos filtrando a tabela Orders de acordo com a relação feita através da coluna CustomerID tanto da tabela Orders como da tabela Customers. Perceba que utilizamos os alias O e C para identificar as tabelas, pois ambas possuem uma coluna CustomerID.
Agora observem a query abaixo:
SELECT OrderID,OrderDate, CustomerID,
(SELECT CompanyName FROM Customers C WHERE O.CustomerID=C.CustomerID)AS CompanyName
FROM orders O
Nesta subquery estamos retornando o campo CompanyName da tabela Customers. Porém, não estamos filtrando a tabela Orders. Desse modo, se houver algum CustomerID na tabela Orders que não se encontre na tabela Customers o valor NULL será retornado para o campo CompanyName calculado através da subquery.
Alguns detalhes quando utilizarmos subquerys:
1. Sempre feche as subqueys com parênteses para que as mesmas funcionem corretamente
2. Subquerys não podem trabalhar com colunas quem contém o tipo de dados TEXT ou IMAGE. Uma idéia é converter estes dados para outro tipo (como VARCHAR ) através das funções CONVERT() ou CAST() e depois retorná-los na subquery. Exemplo:
SELECT COD, ( SELECT CAST( TXT AS VARCHAR ) FROM BLOB ) AS X
FROM BLOB
3. Sempre que possível procure montar a Subquery antes de colocá-las na instrução SELECT final. Isto ajuda a dividir uma instrução SELECT complexa em pequenos passos. Após obter a subquery correta, coloque-a na query oficial lembrando sempre que para cada registro da query mais externa, a subquery vai ser executada uma vez.
4. Caso precisar correlacionar a subquery interna com a query externa e tanto a query como a subquery utilizarem a mesma tabela, procure colocar um alias para a tabela diferente em cada uma. Por exemplo:
SELECT T1A.C3,
( SELECT T1B.C3 FROM TABELA1 AS T1B WHERE T1A.C1 = T1B.C2 ) AS CALCULADO
FROM TABELA1 AS T1A
5. Quando a instrução SELECT que possuir a subquery ficar muito grande, pense em criar uma view. Desta forma a complexidade da query ficará encapsulada e o usuário final somente utilizará a view.
6. Subquerys geralmente podem ser convertidas em JOINS. Por exemplo:
SELECT * FROM Orders
WHERE CustomerID IN (SELECT CustomerID FROM Customers)
A query acima pode ser convertida para:
SELECT * FROM Orders O , Customers C
WHERE O.CustomerID = C.CustomerID
Ou ainda
SELECT * FROM Orders O INNER JOIN Customers C
ON O.CustomerID = C.CustomerID
As três query´s acima são equivalentes, sendo preferível a última.
Outros exemplos: as duas querys abaixo
SELECT * FROM Customers
WHERE CustomerID NOT IN (SELECT CustomerID FROM Orders)
SELECT * FROM Customers C
WHERE NOT EXISTS (SELECT CustomerID FROM Orders O WHERE C.CustomerID=O.CustomerID)
São equivalentes à seguinte query:
SELECT C.*
FROM Customers C LEFT OUTER JOIN Orders O
ON C.CustomerID = O.CustomerID
WHERE O.CustomerID IS NULL
Lembrem-se, sempre que possível é preferível que utilizemos um JOIN ao invés de uma subquery, pois o Query Otimizer (o mecanismo que otimiza as instruções enviada para o banco) pode executar algumas operações a mais quando se utiliza subquerys, degradando assim a performance da execução.
7. Do mesmo modo que nas views, somente podemos colocar a cláusula ORDER BY em uma subquery se utilizarmos a cláusula TOP na subquery.

