Subconsultas (SQL Server)
Aplica-se a: SQL Server Banco de Dados SQL do Azure Instância Gerenciada de SQL do Azure Azure Synapse Analytics Analytics Platform System (PDW)
Uma subconsulta é uma consulta que está aninhada dentro de uma instrução SELECT
, INSERT
, UPDATE
ou DELETE
ou em outra subconsulta.
Os exemplos de código do Transact-SQL deste artigo usa o banco de dados de exemplo AdventureWorks2022
ou AdventureWorksDW2022
, que pode ser baixado da home page Microsoft SQL Server Samples and Community Projects.
Uma subconsulta pode ser usada em qualquer lugar em que é permitida uma expressão. Neste exemplo, utiliza-se uma subconsulta como uma expressão de coluna denominada MaxUnitPrice em uma instrução SELECT
.
USE AdventureWorks2022;
GO
SELECT Ord.SalesOrderID, Ord.OrderDate,
(SELECT MAX(OrdDet.UnitPrice)
FROM Sales.SalesOrderDetail AS OrdDet
WHERE Ord.SalesOrderID = OrdDet.SalesOrderID) AS MaxUnitPrice
FROM Sales.SalesOrderHeader AS Ord;
GO
Noções básicas sobre subconsultas
Uma subconsulta também é chamada de uma consulta interna ou seleção interna, enquanto a instrução que contém uma subconsulta também é chamada de uma consulta externa ou seleção externa.
Muitas instruções Transact-SQL que incluem subconsultas podem ser alternativamente formuladas como junções. Outras perguntas só podem ser feitas com subconsultas. No Transact-SQL, normalmente não há diferença de desempenho entre uma instrução que inclui uma subconsulta e uma versão equivalente semanticamente que não inclui. Veja informações de arquitetura sobre como o SQL Server processa consultas em Processamento de instruções SQL. Entretanto, em alguns casos em que a existência deve ser verificada, uma junção tem um desempenho melhor. Em outros casos, a consulta aninhada deve ser processada para cada resultado da consulta externa para assegurar a eliminação de duplicatas. Em tais casos, uma abordagem de junção geraria resultados melhores.
Este exemplo mostra uma subconsulta SELECT
e uma junção SELECT
que retornam o mesmo conjunto de resultados e plano de execução:
USE AdventureWorks2022;
GO
/* SELECT statement built using a subquery. */
SELECT [Name]
FROM Production.Product
WHERE ListPrice =
(SELECT ListPrice
FROM Production.Product
WHERE [Name] = 'Chainring Bolts' );
GO
/* SELECT statement built using a join that returns
the same result set. */
SELECT Prd1.[Name]
FROM Production.Product AS Prd1
JOIN Production.Product AS Prd2
ON (Prd1.ListPrice = Prd2.ListPrice)
WHERE Prd2.[Name] = 'Chainring Bolts';
GO
Uma subconsulta aninhada na instrução SELECT externa tem os seguintes componentes:
- Uma consulta regular
SELECT
incluindo os componentes regulares de lista de seleção. - Uma cláusula regular
FROM
que inclui um ou mais nomes de tabela ou de exibição. - Uma cláusula
WHERE
opcional. - Uma cláusula
GROUP BY
opcional. - Uma cláusula
HAVING
opcional.
A consulta SELECT de uma subconsulta sempre é inclusa em parênteses. Não pode incluir uma cláusula COMPUTE
ou FOR BROWSE
e pode incluir somente uma cláusula ORDER BY
quando uma cláusula TOP também for especificada.
Uma subconsulta pode ser aninhada na cláusula WHERE
ou HAVING
de uma instrução SELECT
, INSERT
, UPDATE
ou DELETE
externa ou em outra subconsulta. Até 32 níveis de aninhamento são possíveis, embora o limite varie com base na memória disponível e na complexidade de outras expressões da consulta. Consultas individuais não ofereçam suporte a aninhamento até 32 níveis. Uma subconsulta pode aparecer em qualquer lugar em que uma expressão possa ser usada, se retornar um único valor.
Se uma tabela só aparecer em uma subconsulta e não na consulta externa, não será possível incluir colunas dessa tabela na saída (a lista de seleção da consulta externa).
Instruções que incluem uma subconsulta normalmente têm um destes formatos:
WHERE expression [NOT] IN (subquery)
WHERE expression comparison_operator [ANY | ALL] (subquery)
WHERE [NOT] EXISTS (subquery)
Em algumas instruções Transact-SQL, a subconsulta pode ser avaliada como se fosse uma consulta independente. Conceitualmente, os resultados da subconsulta são substituídos na consulta externa (embora isso não seja necessariamente como o SQL Server processa de fato instruções Transact-SQL com subconsultas).
Há três tipos básicos de subconsultas. Aquelas que:
- Funcionam em listas introduzidas com
IN
, ou aquelas em que um operador de comparação modificou porANY
ouALL
. - São introduzidas com um operador de comparação inalterado e devem retornar um único valor.
- São testes de existência introduzidos com
EXISTS
.
Regras de subconsulta
Uma subconsulta está sujeita às seguintes restrições:
- A lista de seleção de uma subconsulta introduzida com um operador de comparação pode incluir apenas uma expressão ou um nome de coluna (exceto que
EXISTS
eIN
operam emSELECT *
ou em uma lista, respectivamente). - Se a cláusula
WHERE
de uma consulta externa incluir um nome de coluna, ela deverá ser compatível com junção com a coluna na lista de seleção da subconsulta. - Não é possível usar tipos de dados ntext, text e image na lista de seleção de subconsultas.
- Como devem retornar um único valor, as subconsultas introduzidas por um operador de comparação inalterado (não seguido da palavra-chave
ANY
ouALL
) não podem incluir as cláusulasGROUP BY
eHAVING
. - A palavra-chave
DISTINCT
não pode ser usada com subconsultas que incluemGROUP BY
. - Não é possível especificar as cláusulas
COMPUTE
eINTO
. ORDER BY
só pode ser especificado quandoTOP
também for especificado.- Não é possível atualizar uma exibição criada usando uma subconsulta.
- A lista de seleção de uma subconsulta introduzida com
EXISTS
, por convenção, tem um asterisco (*
), em vez de um único nome de coluna. As regras para uma subconsulta introduzida comEXISTS
são iguais àquelas para uma lista de seleção padrão, porque uma subconsulta introduzida comEXISTS
cria um teste de existência e retorna TRUE ou FALSE, em vez de dados.
Qualificar nomes de coluna em subconsultas
No exemplo a seguir, a coluna BusinessEntityID
na cláusula WHERE
da consulta externa está implicitamente qualificada pelo nome da tabela na cláusula FROM
da consulta externa (Sales.Store
). A referência a CustomerID
na lista de seleção da subconsulta está qualificada pela cláusula FROM
da subconsulta, ou seja, pela tabela Sales.Customer
.
USE AdventureWorks2022;
GO
SELECT [Name]
FROM Sales.Store
WHERE BusinessEntityID NOT IN
(SELECT CustomerID
FROM Sales.Customer
WHERE TerritoryID = 5);
GO
A regra geral é que os nomes de coluna em uma instrução sejam implicitamente qualificados pela tabela referenciada na cláusula FROM
no mesmo nível. Se a coluna não existir na tabela referenciada na cláusula FROM
de uma subconsulta, ela será qualificada implicitamente pela tabela referenciada na cláusula FROM
da consulta externa.
A consulta com as suposições implícitas especificadas é assim:
USE AdventureWorks2022;
GO
SELECT [Name]
FROM Sales.Store
WHERE Sales.Store.BusinessEntityID NOT IN
(SELECT Sales.Customer.CustomerID
FROM Sales.Customer
WHERE TerritoryID = 5);
GO
Nunca é errado declarar o nome da tabela explicitamente e sempre é possível substituir as suposições implícitas sobre nomes da tabela com qualificações explícitas.
Importante
Se uma coluna for referenciada em uma subconsulta que não existe na tabela referenciada da cláusula FROM
da subconsulta, mas existir em uma tabela referenciada pela consulta externa FROM
cláusula, a consulta será executada sem erro. O SQL Server implicitamente qualifica a coluna na subconsulta com o nome da tabela na consulta externa.
Vários níveis de aninhamento
Uma subconsulta pode incluir uma ou mais subconsultas. Qualquer número de subconsultas pode ser aninhado em uma instrução.
A seguinte consulta localiza os nomes de funcionários que também são vendedores.
USE AdventureWorks2022;
GO
SELECT LastName, FirstName
FROM Person.Person
WHERE BusinessEntityID IN
(SELECT BusinessEntityID
FROM HumanResources.Employee
WHERE BusinessEntityID IN
(SELECT BusinessEntityID
FROM Sales.SalesPerson)
);
GO
Veja a seguir o conjunto de resultados.
LastName FirstName
-------------------------------------------------- -----------------------
Jiang Stephen
Abbas Syed
Alberts Amy
Ansman-Wolfe Pamela
Campbell David
Carson Jillian
Ito Shu
Mitchell Linda
Reiter Tsvi
Saraiva Jos
Vargas Garrett
Varkey Chudukatil Ranjit
Valdez Rachel
Tsoflias Lynn
Pak Jae
Blythe Michael
Mensa-Annan Tete
(17 row(s) affected)
A consulta mais interna retorna a ID dos vendedores. A consulta no nível superior próximo é avaliada com essa ID de vendedor e retorna os números de ID de contato dos funcionários. Finalmente, a consulta externa usa a ID de contato para localizar os nomes dos funcionários.
Você também pode expressar esta consulta como uma junção:
USE AdventureWorks2022;
GO
SELECT LastName, FirstName
FROM Person.Person c
INNER JOIN HumanResources.Employee e
ON c.BusinessEntityID = e.BusinessEntityID
JOIN Sales.SalesPerson s
ON e.BusinessEntityID = s.BusinessEntityID;
GO
Subconsultas correlacionadas
Muitas consultas podem ser avaliadas pela execução de uma subconsulta, uma vez, e pela substituição do valor ou dos valores resultantes na cláusula WHERE
da consulta externa. Em consultas que incluem uma subconsulta correlacionada (também conhecida como uma subconsulta repetitiva), a subconsulta depende da consulta externa para obter seus valores. Isso significa que a subconsulta é executada repetidamente, uma vez para cada linha que pode ser selecionada pela consulta externa.
Essa consulta recupera uma instância de nome e sobrenome de cada funcionário para o qual o bônus na tabela SalesPerson
é 5.000 e para o qual os números de identificação de funcionário correspondem nas tabelas Employee
e SalesPerson
.
USE AdventureWorks2022;
GO
SELECT DISTINCT c.LastName, c.FirstName, e.BusinessEntityID
FROM Person.Person AS c JOIN HumanResources.Employee AS e
ON e.BusinessEntityID = c.BusinessEntityID
WHERE 5000.00 IN
(SELECT Bonus
FROM Sales.SalesPerson sp
WHERE e.BusinessEntityID = sp.BusinessEntityID) ;
GO
Veja a seguir o conjunto de resultados.
LastName FirstName BusinessEntityID
-------------------------- ---------- ------------
Ansman-Wolfe Pamela 280
Saraiva José 282
(2 row(s) affected)
A subconsulta anterior dessa instrução não pode ser avaliada de maneira independente da consulta externa. É necessário um valor de Employee.BusinessEntityID
, mas esse valor é alterado à medida que o SQL Server examina diferentes linhas em Employee
.
Essa é exatamente a forma como a consulta é avaliada: o SQL Server considera cada linha da tabela Employee
para inclusão nos resultados, substituindo o valor de cada uma das linhas na consulta interna.
Por exemplo, quando o SQL Server primeiro examina a linha de Syed Abbas
, a variável Employee.BusinessEntityID
usa o valor 285
, que o SQL Server substitui na consulta interna. Essas duas amostras de consulta representam uma decomposição do exemplo anterior com a subconsulta correlacionada.
USE AdventureWorks2022;
GO
SELECT Bonus
FROM Sales.SalesPerson
WHERE BusinessEntityID = 285;
GO
O resultado é 0.00 (Syed Abbas
não recebeu bônus porque não é vendedor), então a consulta externa avalia:
USE AdventureWorks2022;
GO
SELECT LastName, FirstName
FROM Person.Person AS c JOIN HumanResources.Employee AS e
ON e.BusinessEntityID = c.BusinessEntityID
WHERE 5000 IN (0.00);
GO
Como isso é falso, a linha de Syed Abbas
não é incluída nos resultados da consulta de exemplo anterior com a subconsulta correlacionada. Siga o mesmo procedimento com a linha para Pamela Ansman-Wolfe
. Você verá que essa linha está incluída nos resultados, pois WHERE 5000 IN (5000)
inclui resultados.
As subconsultas correlacionadas também podem incluir funções com valor de tabela na cláusula FROM
, fazendo referência a colunas de uma tabela na consulta externa como argumento da função com valor de tabela. Nesse caso, para cada linha da consulta externa, a função com valor de tabela é avaliada segundo a subconsulta.
Tipos de subconsulta
As subconsultas podem ser especificadas em muitos lugares:
- Com aliases. Para obter mais informações, veja Subconsultas com aliases de tabela.
- Com
IN
ouNOT IN
. Para obter mais informações, veja Subconsultas com IN e Subconsultas com NOT IN. - Nas instruções
UPDATE
,DELETE
eINSERT
. Para obter mais informações, veja Subconsultas em instruções UPDATE, DELETE e INSERT. - Com operadores de comparação. Para obter mais informações, confira Subconsultas com operadores de comparação.
- Com
ANY
,SOME
ouALL
. Para obter mais informações, confira Operadores de comparação modificados por ANY, SOME ou ALL. - Com
IS [NOT] DISTINCT FROM
. Para obter mais informações, confira IS [NOT] DISTINCT FROM (Transact-SQL). - Com
EXISTS
ouNOT EXISTS
. Para obter mais informações, veja Subconsultas com EXISTS e Subconsultas com NOT EXISTS. - No lugar de uma expressão. Para obter mais informações, confira Subconsultas usadas no lugar de uma expressão.
Subconsultas com aliases de tabela
Várias instruções nas quais a subconsulta e a consulta externa se referem à mesma tabela podem ser especificadas como autojunções (associando uma tabela a ela mesma). Por exemplo, você pode localizar endereços de funcionários de um estado específico usando uma subconsulta:
USE AdventureWorks2022;
GO
SELECT StateProvinceID, AddressID
FROM Person.Address
WHERE AddressID IN
(SELECT AddressID
FROM Person.Address
WHERE StateProvinceID = 39);
GO
Veja a seguir o conjunto de resultados.
StateProvinceID AddressID
----------- -----------
39 942
39 955
39 972
39 22660
(4 row(s) affected)
Ou você pode usar uma autojunção:
USE AdventureWorks2022;
GO
SELECT e1.StateProvinceID, e1.AddressID
FROM Person.Address AS e1
INNER JOIN Person.Address AS e2
ON e1.AddressID = e2.AddressID
AND e2.StateProvinceID = 39;
GO
São necessários aliases de tabela e1
e e2
porque a tabela que é unida a ela mesma aparece em duas diferentes funções. Os aliases também podem ser utilizados em consultas aninhadas que se referem à mesma tabela em uma consulta interna e externa.
USE AdventureWorks2022;
GO
SELECT e1.StateProvinceID, e1.AddressID
FROM Person.Address AS e1
WHERE e1.AddressID IN
(SELECT e2.AddressID
FROM Person.Address AS e2
WHERE e2.StateProvinceID = 39);
GO
Os aliases de tabela explícitos deixam claro que a referência a Person.Address
na subconsulta não tem o mesmo significado que a referência da consulta externa.
Subconsultas com IN
O resultado de uma subconsulta apresentada com IN
(ou com NOT IN
) é uma lista com zero ou mais valores. Depois dos resultados da subconsulta retornarem, a consulta exterior os utiliza.
A consulta a seguir encontra os nomes de todos os produtos de roda Adventure Works Cycles fabrica.
USE AdventureWorks2022;
GO
SELECT [Name]
FROM Production.Product
WHERE ProductSubcategoryID IN
(SELECT ProductSubcategoryID
FROM Production.ProductSubcategory
WHERE [Name] = 'Wheels');
GO
Veja a seguir o conjunto de resultados.
Name
----------------------------
LL Mountain Front Wheel
ML Mountain Front Wheel
HL Mountain Front Wheel
LL Road Front Wheel
ML Road Front Wheel
HL Road Front Wheel
Touring Front Wheel
LL Mountain Rear Wheel
ML Mountain Rear Wheel
HL Mountain Rear Wheel
LL Road Rear Wheel
ML Road Rear Wheel
HL Road Rear Wheel
Touring Rear Wheel
(14 row(s) affected)
Esta instrução é avaliada em dois passos. Primeiro, a consulta interna retorna o número de identificação da subcategoria que corresponde ao nome Wheel
(17
). Depois, esse valor é substituído na consulta exterior a qual acha o nome do produto que vai com os números de identificação da subcategoria em Production.Product
.
USE AdventureWorks2022;
GO
SELECT [Name]
FROM Production.Product
WHERE ProductSubcategoryID IN ('17');
GO
Uma diferença ao usar uma junção em vez de uma subconsulta para esse e outros problemas semelhantes é que a junção o deixa mostrar colunas de mais de uma tabela no resultado. Por exemplo, se você quiser incluir o nome da subcategoria do produto no resultado, deverá usar uma versão de junção.
USE AdventureWorks2022;
GO
SELECT p.[Name], s.[Name]
FROM Production.Product p
INNER JOIN Production.ProductSubcategory s
ON p.ProductSubcategoryID = s.ProductSubcategoryID
AND s.[Name] = 'Wheels';
GO
Veja a seguir o conjunto de resultados.
Name
LL Mountain Front Wheel Wheels
ML Mountain Front Wheel Wheels
HL Mountain Front Wheel Wheels
LL Road Front Wheel Wheels
ML Road Front Wheel Wheels
HL Road Front Wheel Wheels
Touring Front Wheel Wheels
LL Mountain Rear Wheel Wheels
ML Mountain Rear Wheel Wheels
HL Mountain Rear Wheel Wheels
LL Road Rear Wheel Wheels
ML Road Rear Wheel Wheels
HL Road Rear Wheel Wheels
Touring Rear Wheel Wheels
(14 row(s) affected)
A consulta a seguir encontra o nome de todos os fornecedores cuja avaliação de crédito é boa, os nomes daqueles dos quais a Adventure Works Cycles comprou no mínimo 20 itens e prazo de entrega médio é menor que 16 dias.
USE AdventureWorks2022;
GO
SELECT [Name]
FROM Purchasing.Vendor
WHERE CreditRating = 1
AND BusinessEntityID IN
(SELECT BusinessEntityID
FROM Purchasing.ProductVendor
WHERE MinOrderQty >= 20
AND AverageLeadTime < 16);
GO
Veja a seguir o conjunto de resultados.
Name
--------------------------------------------------
Compete Enterprises, Inc
International Trek Center
First National Sport Co.
Comfort Road Bicycles
Circuit Cycles
First Rate Bicycles
Jeff's Sporting Goods
Competition Bike Training Systems
Electronic Bike Repair & Supplies
Crowley Sport
Expert Bike Co
Team Athletic Co.
Compete, Inc.
(13 row(s) affected)
A consulta interna é avaliada, produzindo os números de ID dos fornecedores que atendam às qualificações da subconsulta. A consulta exterior é então avaliada. Você pode incluir mais de uma condição na cláusula WHERE
tanto da consulta interna quanto da exterior.
Usando uma junção, a mesma consulta é expressada assim:
USE AdventureWorks2022;
GO
SELECT DISTINCT [Name]
FROM Purchasing.Vendor v
INNER JOIN Purchasing.ProductVendor p
ON v.BusinessEntityID = p.BusinessEntityID
WHERE CreditRating = 1
AND MinOrderQty >= 20
AND AverageLeadTime < 16;
GO
Uma junção sempre pode ser expressada como uma subconsulta. Uma subconsulta pode frequentemente, mas não sempre, ser expressada como uma junção. Isso se deve ao fato de as junções serem simétricas: você pode unir as tabelas A
e B
em qualquer ordem e obter a mesma resposta. O mesmo não se aplicará se houver uma subconsulta envolvida.
Subconsultas com NOT IN
Subconsultas introduzidas com a palavra-chave NOT IN
também retornam uma lista com zero ou outros valores.
A consulta a seguir encontra os nomes de produtos que não são bicicletas acabadas.
USE AdventureWorks2022;
GO
SELECT [Name]
FROM Production.Product
WHERE ProductSubcategoryID NOT IN
(SELECT ProductSubcategoryID
FROM Production.ProductSubcategory
WHERE [Name] = 'Mountain Bikes'
OR [Name] = 'Road Bikes'
OR [Name] = 'Touring Bikes');
GO
Não é possível converter essa instrução em uma junção. A junção análoga não igual tem um significado diferente: ela acha os nomes de produtos que estão em alguma subcategoria que não é uma bicicleta acabada.
Subconsultas nas instruções UPDATE, DELETE e INSERT
Subconsultas podem ser aninhadas nas instruções UPDATE
, DELETE
, INSERT
e SELECT
de DML (manipulação de dados).
O exemplo a seguir dobra o valor na coluna ListPrice
da tabela Production.Product
. A subconsulta na cláusula WHERE
faz referência à tabela Purchasing.ProductVendor
para restringir as linhas atualizadas na tabela Product somente àquelas fornecidas pela BusinessEntity
1540
.
USE AdventureWorks2022;
GO
UPDATE Production.Product
SET ListPrice = ListPrice * 2
WHERE ProductID IN
(SELECT ProductID
FROM Purchasing.ProductVendor
WHERE BusinessEntityID = 1540);
GO
Esta é uma instrução UPDATE
equivalente usando uma junção:
USE AdventureWorks2022;
GO
UPDATE Production.Product
SET ListPrice = ListPrice * 2
FROM Production.Product AS p
INNER JOIN Purchasing.ProductVendor AS pv
ON p.ProductID = pv.ProductID AND BusinessEntityID = 1540;
GO
Para maior clareza, caso a mesma tabela seja referenciada em outras subconsultas, use o alias da tabela de destino:
USE AdventureWorks2022;
GO
UPDATE p
SET ListPrice = ListPrice * 2
FROM Production.Product AS p
INNER JOIN Purchasing.ProductVendor AS pv
ON p.ProductID = pv.ProductID AND BusinessEntityID = 1540;
GO
Subconsultas com operadores de comparação
As subconsultas podem ser introduzidas com um dos operadores de comparação (=
, < >
, >
, > =
, <
, ! >
, ! <
ou < =
).
Uma subconsulta introduzida com um operador de comparação não modificado (um operador de comparação não seguido por ANY
ou ALL
) deve retornar um valor único, em vez de uma lista de valores, como subconsultas introduzidas com IN
. Se uma subconsulta desse tipo retornar mais de um valor, o SQL Server exibirá uma mensagem de erro.
Para usar uma subconsulta introduzida com um operador de comparação não modificado, você deve estar bastante familiarizado com seus dados e com a natureza do problema para saber que a subconsulta retornará exatamente um valor.
Por exemplo, quando você pressupõe que cada vendedor cobre apenas um território de vendas e quer encontrar os clientes localizados no território coberto por Linda Mitchell
, pode gravar uma instrução com uma subconsulta introduzida com o operador de comparação =
simples.
USE AdventureWorks2022;
GO
SELECT CustomerID
FROM Sales.Customer
WHERE TerritoryID =
(SELECT TerritoryID
FROM Sales.SalesPerson
WHERE BusinessEntityID = 276);
GO
No entanto, se Linda Mitchell
cobrisse mais de um território de vendas, então uma mensagem de erro seria gerada. Em vez do operador de comparação =
, poderia ser usada uma formulação IN
(=ANY
também funciona).
Subconsultas introduzidas com operadores de comparação não modificados incluem frequentemente funções de agregação, porque elas retornam um único valor. Por exemplo, a instrução apresentada a seguir encontra os nomes de todos os produtos cujo preço da lista seja maior que o preço médio da lista.
USE AdventureWorks2022;
GO
SELECT [Name]
FROM Production.Product
WHERE ListPrice >
(SELECT AVG (ListPrice)
FROM Production.Product);
GO
Como as subconsultas introduzidas com operadores de comparação não modificados devem retornar um único valor, elas não podem incluir cláusulas GROUP BY
ou HAVING
, a menos que você saiba que a própria cláusula GROUP BY
ou HAVING
retorna um valor único. Por exemplo, a consulta a seguir encontra os produtos cujo preço é mais alto que o produto de preço mais baixo que está na ProductSubcategoryID
14
.
USE AdventureWorks2022;
GO
SELECT [Name]
FROM Production.Product
WHERE ListPrice >
(SELECT MIN (ListPrice)
FROM Production.Product
GROUP BY ProductSubcategoryID
HAVING ProductSubcategoryID = 14);
GO
Operadores de comparação modificados por ANY
, SOME
ou ALL
Os operadores de comparação que introduzem uma subconsulta podem ser modificados pelas palavras-chave ALL
ou ANY
. SOME
é um padrão ISO equivalente para ANY
. Para obter mais informações sobre esses operadores de comparação, confira SOME | ANY.
As subconsultas introduzidas por um operador de comparação modificado retornam uma lista com zero ou mais valores e podem incluir uma cláusula GROUP BY
ou HAVING
. Essas subconsultas podem ser declaradas novamente com EXISTS
.
Usando o operador de comparação > como um exemplo, > ALL
significa maior do que todos os valores. Em outras palavras, significa maior do que o valor máximo. Por exemplo, > ALL (1, 2, 3)
significa maior que 3. > ANY
significa maior do que pelo menos um valor, isto é, maior do que o mínimo. Portanto, > ANY (1, 2, 3)
significa maior do que 1.
Para uma linha em uma subconsulta com > ALL
satisfazer a condição especificada na consulta externa, o valor na coluna que introduz a subconsulta deve ser maior do que cada valor na lista de valores retornada pela subconsulta.
De modo semelhante, > ANY
significa que, para uma linha satisfazer a condição especificada na consulta exterior, o valor na coluna que introduz a subconsulta deve ser maior do que pelo menos um dos valores na lista de valores retornada pela subconsulta.
A consulta a seguir fornece um exemplo de uma subconsulta introduzido com um operador de comparação modificado por ANY
. Encontra os produtos cujos preços de tabela são maiores ou iguais ao preço máximo de tabela de qualquer subcategoria de produto.
USE AdventureWorks2022;
GO
SELECT [Name]
FROM Production.Product
WHERE ListPrice >= ANY
(SELECT MAX (ListPrice)
FROM Production.Product
GROUP BY ProductSubcategoryID);
GO
Para cada subcategoria de produto, a consulta interna encontra o preço máximo de tabela. A consulta exterior procura todos esses valores e determina quais os preços de tabela do produto individual são maiores ou iguais ao preço máximo de tabela de qualquer subcategoria de produto. Se ANY
for alterado para ALL
, a consulta retornará apenas os produtos cujo preço de lista é maior ou igual a todos os preços de tabela retornados na consulta interna.
Se a subconsulta não retornar valores, a consulta inteira não retornará valores.
O operador = ANY
é equivalente a IN
. Por exemplo, para localizar os nomes de todos os produtos de roda que a Adventure Works Cycles fabrica, você pode usar o IN
ou = ANY
.
--Using = ANY
USE AdventureWorks2022;
GO
SELECT [Name]
FROM Production.Product
WHERE ProductSubcategoryID = ANY
(SELECT ProductSubcategoryID
FROM Production.ProductSubcategory
WHERE Name = 'Wheels');
GO
--Using IN
USE AdventureWorks2022;
GO
SELECT [Name]
FROM Production.Product
WHERE ProductSubcategoryID IN
(SELECT ProductSubcategoryID
FROM Production.ProductSubcategory
WHERE Name = 'Wheels');
GO
Este é o conjunto de resultados para ambas as consultas:
Name
--------------------------------------------------
LL Mountain Front Wheel
ML Mountain Front Wheel
HL Mountain Front Wheel
LL Road Front Wheel
ML Road Front Wheel
HL Road Front Wheel
Touring Front Wheel
LL Mountain Rear Wheel
ML Mountain Rear Wheel
HL Mountain Rear Wheel
LL Road Rear Wheel
ML Road Rear Wheel
HL Road Rear Wheel
Touring Rear Wheel
(14 row(s) affected)
O operador <> ANY
, no entanto, difere de NOT IN
:
<> ANY
significa diferente de a ou diferente de b ou diferente de cNOT IN
significa diferente de a e diferente de b e diferente de c<> ALL
significa o mesmo queNOT IN
Por exemplo, a consulta a seguir encontra os clientes localizados em um território não coberto por qualquer vendedor.
USE AdventureWorks2022;
GO
SELECT CustomerID
FROM Sales.Customer
WHERE TerritoryID <> ANY
(SELECT TerritoryID
FROM Sales.SalesPerson);
GO
Os resultados incluem todos os clientes, exceto aqueles cujos territórios de vendas são NULL, porque todo território atribuído a um cliente está coberto por um vendedor. A consulta interna encontra todos os territórios de vendas cobertos por vendedores e, para cada território, a consulta externa encontra os clientes que não estão em um.
Pela mesma razão, quando você usa NOT IN
nessa consulta, os resultados não incluem nenhum dos clientes.
Você pode obter os mesmos resultados com o operador <> ALL
, que é equivalente a NOT IN
.
Subconsultas com EXISTS
Quando uma subconsulta é apresentada com a palavra-chave EXISTS
, a subconsulta funciona como um teste de existência. A cláusula WHERE
da consulta externa testa se as linhas retornadas pela subconsulta existem. A subconsulta não produz de fato nenhum dado e retorna um valor TRUE
ou FALSE
.
Uma subconsulta introduzida com EXISTS tem a seguinte sintaxe: WHERE [NOT] EXISTS (subquery)
A consulta a seguir encontra os nomes de todos os produtos que estão na subcategoria Rodas:
USE AdventureWorks2022;
GO
SELECT [Name]
FROM Production.Product
WHERE EXISTS
(SELECT *
FROM Production.ProductSubcategory
WHERE ProductSubcategoryID =
Production.Product.ProductSubcategoryID
AND [Name] = 'Wheels');
GO
Veja a seguir o conjunto de resultados.
Name
--------------------------------------------------
LL Mountain Front Wheel
ML Mountain Front Wheel
HL Mountain Front Wheel
LL Road Front Wheel
ML Road Front Wheel
HL Road Front Wheel
Touring Front Wheel
LL Mountain Rear Wheel
ML Mountain Rear Wheel
HL Mountain Rear Wheel
LL Road Rear Wheel
ML Road Rear Wheel
HL Road Rear Wheel
Touring Rear Wheel
(14 row(s) affected)
Para entender os resultados desta consulta, considere o nome de cada produto individualmente. Esse valor faz a subconsulta retornar pelo menos uma linha? Em outras palavras, a consulta faz com que o teste de existência seja avaliado como TRUE
?
Subconsultas apresentadas com EXISTS são um pouco diferentes de outras subconsultas da seguinte forma:
- A palavra-chave
EXISTS
não é precedida por nome de coluna, constante nem outra expressão. - A lista de seleção de uma subconsulta introduzida por
EXISTS
quase sempre consiste em um asterisco (*). Não há motivo para listar nomes de coluna, pois você está apenas testando se existem linhas que atendem às condições especificadas na subconsulta.
A palavra-chave EXISTS
é importante porque geralmente não há formulação alternativa sem subconsultas. Embora algumas consultas criadas com EXISTS
não possam ser expressadas de nenhum outro modo, muitas consultas podem usar IN
ou um operador de comparação modificado por ANY
ou ALL
para alcançar resultados semelhantes.
Por exemplo, a consulta precedente pode ser expressada usando IN
:
USE AdventureWorks2022;
GO
SELECT [Name]
FROM Production.Product
WHERE ProductSubcategoryID IN
(SELECT ProductSubcategoryID
FROM Production.ProductSubcategory
WHERE [Name] = 'Wheels');
GO
Subconsultas com NOT EXISTS
NOT EXISTS
funciona como EXISTS
, exceto pela cláusula WHERE
se nenhuma linha for retornada pela subconsulta.
Por exemplo, para localizar os nomes de produtos que não estejam na subcategoria rodas:
USE AdventureWorks2022;
GO
SELECT [Name]
FROM Production.Product
WHERE NOT EXISTS
(SELECT *
FROM Production.ProductSubcategory
WHERE ProductSubcategoryID =
Production.Product.ProductSubcategoryID
AND [Name] = 'Wheels');
GO
Subconsultas usadas no lugar de uma expressão
No Transact-SQL, uma subconsulta pode ser substituída em qualquer lugar em que uma expressão pode ser usada em instruções SELECT
, UPDATE
, INSERT
e DELETE
, exceto em uma lista ORDER BY
.
O exemplo a seguir ilustra como você poderia usar esse aprimoramento. Esta consulta encontra os preços de todos os produtos de mountain bike, o preço médio delas e a diferença entre o preço de cada bicicleta mountain bike e o preço médio.
USE AdventureWorks2022;
GO
SELECT [Name], ListPrice,
(SELECT AVG(ListPrice) FROM Production.Product) AS Average,
ListPrice - (SELECT AVG(ListPrice) FROM Production.Product)
AS Difference
FROM Production.Product
WHERE ProductSubcategoryID = 1;
GO
Conteúdo relacionado
- IN (Transact-SQL)
- EXISTS (Transact-SQL)
- ALL (Transact-SQL)
- SOME | ANY (Transact-SQL)
- Junções
- Operadores de comparação (Transact-SQL)
- Guia de arquitetura de processamento de consultas
- Melhores prática com o Repositório de Consultas
- Processamento inteligente de consultas em bancos de dados SQL
- Estimativa de cardinalidade (SQL Server)