Voltar para a lista de artigos Artigos
10 minutos de leitura

O operador SQL EXISTS

O uso da cláusula SQL EXISTS nos permite criar consultas complexas de forma simples. Conheça os prós e os contras do operador EXISTS neste artigo.

No SQL, o operador EXISTS nos ajuda a criar condições lógicas em nossas consultas. Essencialmente, ele verifica se há alguma linha em uma subconsulta. Mostraremos a você a sintaxe do EXISTS, forneceremos alguns exemplos de uso e faremos vários exercícios para você praticar.

Se estiver começando a usar SQL ou precisar de uma atualização em SQL, recomendo o curso SQL para Iniciantes. Ele inclui tópicos de SQL que vão desde SELECTs básicos até tópicos complexos como junções, agregações e subconsultas. É uma ótima maneira de desenvolver, atualizar ou expandir suas habilidades em SQL.

Sintaxe do operador EXISTS

Você provavelmente conhece os operadores SQL como =, >, < e LIKE. Todos esses operadores podem ser usados para criar condições lógicas que retornarão TRUE ou FALSE. Exemplos de condições comuns incluem:

WHERE Employee_id = 10345
WHERE Price < 1000
WHERE Name LIKE ‘John%’

Os operadores =, < e LIKE comparam dois elementos ou operandos. Essa é a razão pela qual são chamados de operadores binários.

				WHERE EXISTS ( subquery )

Agora vamos ver a consulta SQL inteira para determinar onde a condição EXISTS pode ser colocada:

SELECT columns
FROM table1
WHERE EXISTS (SELECT columns FROM table2);

O operador EXISTS é usado para criar condições booleanas para verificar se uma subconsulta retorna linha(s) ou um conjunto vazio. Quando a subconsulta retorna pelo menos uma linha, EXISTS retorna TRUE. Não importa quantas linhas são retornadas ou quantas colunas estão na lista da subconsulta SELECT. Somente quando a subconsulta retorna 0 linhas é que EXISTS retorna FALSE. É importante observar que nenhuma das linhas retornadas pela subconsulta é mostrada no resultado final.

Exemplo de banco de dados: Barcos e carros de luxo

Vamos examinar vários exemplos de consultas com base em um banco de dados de amostra de uma empresa que vende carros e barcos de luxo. A empresa mantém o controle dos carros e barcos na tabela product, que tem as colunas product_id, product_name, product_price, product_type.

product_idproduct_nameproduct_priceproduct_type
100Ferrari F203000000Car
101Lamborghini AX3600000Car
102Pagani Zonda4300000Car
200VanDutch 582100000Boat
201Lamborghini B93400000Boat
202VanDutch 561800000Boat
300Boat Engine Yamei 1001000000Boat

O banco de dados também tem uma tabela Client tabela com as colunas client_id, client_name e country.

client_idclient_namecountry
10John F.United States
11Samid A,Kuwait
12Majal H.Brunei
13Pierre B.France
14Abdul E.Kuwait

Por fim, há a tabela sale com as colunas product_id, client_id, sale_date. (Para simplificar, omito a ideia de ter uma tabela para pedidos de compra; nesse tipo de empresa, um cliente normalmente compra apenas um produto por vez).

client_idproduct_idcountry
102002020-03-05
101012024-04-05
112022023-03-05
121022021-03-07
121002023-03-05
122022024-04-09
133002022-03-05
103002020-07-19
133002023-11-25

Exemplos do operador SQL EXISTS

Exemplo 1: Localizando produtos vendidos

Para o primeiro exemplo de consulta, suponha que o gerente de marketing queira saber quais carros e barcos foram vendidos entre 1º e 15 de abril de 2024. A consulta abaixo faz isso:

SELECT product_name 
FROM product p1
WHERE EXISTS ( SELECT * FROM sale s 
               WHERE  s.product_id = p1.product_id 
               AND    s.sale_date >= ‘2024-04-01’ 
               AND    s.sale_date <= ‘2024-04-15’
             )

Resultados:

Product_name
Lamborghini AX
VanDutch 56

Há outras maneiras de escrever essa consulta sem usar o operador EXISTS. Entretanto, para explicar como o operador EXISTS funciona, esse é um bom exemplo de nível básico.

A consulta principal SELECT é muito fácil; ela vai para a tabela product para obter a coluna product_name. Entretanto, não queremos todos os product_names na tabela. Queremos apenas os produtos que retornam TRUE para a seguinte condição:

WHERE EXISTS ( SELECT * FROM sale s 
               WHERE  s.product_id = p1.product_id 
               AND     s.sale_date >= ‘2024-04-01’ 
               AND     s.sale_date <= ‘2024-04-15’
             )

Se analisarmos a condição, a subconsulta retornará todos os registros de vendas de um determinado produto (p1.product_id) e de um período específico (2024-04-01 a 2024-04-15). Se a subconsulta retornar registros, então EXISTS retornará TRUE. Se a subconsulta não retornar nenhum registro, EXISTS retornará FALSE. Observe que a subconsulta é executada várias vezes - uma vez para cada linha lida pela consulta externa.

Esses tipos de subconsultas que são executadas uma vez para cada linha processada na consulta principal são chamadas de "subconsultas correlacionadas" e têm suas particularidades. Se você quiser se aprofundar nesse tópico, sugiro o artigo Correlated Subquery in SQL: Um guia para iniciantes.

Exemplo 2: usando o operador NOT EXISTS

Agora, suponha que o gerente queira os nomes dos veículos que não foram vendidos no mesmo período. Esse tipo de consulta - em que buscamos registros que não existem no banco de dados - é excelente para o operador NOT EXISTS. Afinal de contas, estamos pesquisando elementos que não existem no banco de dados. A consulta é a seguinte:

SELECT * FROM product p1
WHERE p1.product_type = ‘Car’
AND   NOT EXISTS ( SELECT * FROM sale s
                   WHERE s.product_id = p1.product_id
                   AND   s.sale_date >= ‘2024-04-01’ 
                   AND   s.sale_date <= ‘2024-04-15’
                 )

Resultados:

Product_idProduct_nameProduct_priceProduct_type
100Ferrari F203000000Car
102Pagani Zonda4300000Car

Depois de entendermos como o operador EXISTS funciona no SQL, entender NOT EXISTS é muito simples; é o oposto. Se EXISTS retornar TRUE, então NOT EXISTS retornará FALSE e vice-versa.

Neste exemplo, a consulta principal tem uma cláusula WHERE com duas condições. A primeira condição é solicitar produtos do tipo "veículo". A segunda condição usa NOT EXISTS para manter apenas os produtos que não tiveram vendas durante o período de 2024-04-01 a 2024-04-15. Em outras palavras, procuramos produtos para os quais a subconsulta retorna um conjunto de resultados vazio, ou seja, para os quais não há vendas nesse período.

Em alguns casos, podemos resolver esse tipo de consulta usando NOT IN com uma subconsulta. Nessa consulta específica, podemos colocar essa cláusula WHERE:

WHERE p1.product_type = ‘Car’
AND   p1.product_id NOT IN (SELECT s.product_id 
                            FROM  sale s
               WHERE s.sale_date >= ‘2024-04-01’ 
                            AND   s.sale_date <= ‘2024-04-15’
                           )

Entretanto, há uma diferença na forma como a consulta é executada internamente no banco de dados. A condição da subconsulta NOT IN é executada uma vez, enquanto a condição da subconsulta NOT EXISTS é executada uma vez por cada linha. É isso mesmo; NOT EXISTS é uma subconsulta correlacionada. Leia os artigos 5 exemplos de subconsultas SQL e Operador SQL IN para saber mais sobre esses operadores.

Exemplo 3: Usando EXISTS com NOT EXISTS

Em seguida, precisamos de uma lista dos clientes que não compraram um barco durante o verão de 2023, mas compraram um barco durante o inverno anterior (ou seja, de dezembro de 2022 a março de 2023). A consulta para obter esse relatório é:

SELECT * 
FROM   client c1
WHERE  EXISTS ( SELECT * FROM sale s1 
                JOIN  product p1 ON p1.product_id = s1.product_id
                WHERE c1.client_id = s1.client_id
                AND p1.product_type = 'Boat'
                AND s1.sale_date >= '2022-12-21' 
                AND s1.sale_date <= '2023-03-20' -- winter
              )
AND    NOT EXISTS ( SELECT * FROM sale s2
                   JOIN  product p1 ON p1.product_id = s2.product_id 
                   WHERE c1.client_id = s2.client_id
                   AND p1.product_type = 'Boat' 
                   AND s2.sale_date >= '2023-6-21' 
                   AND s2.sale_date <= '2023-09-20' -- summer
                  ) ;

Results (Resultados):

client_idClient_nameCountry
11Samid A.Kuwait

Após os dois exemplos anteriores, este exemplo não deve ser muito difícil de entender; é a combinação de ambos. A ideia é selecionar o registro inteiro (SELECT *) da tabela client e, em seguida, usar um EXISTS para verificar se um barco foi comprado no inverno passado. Depois disso, usamos NOT EXISTS para verificar se um barco não foi comprado no verão passado. Observe que ambas as subconsultas têm um JOIN entre o sale e product porque precisamos usar as colunas product_type e sale_date nas condições WHERE.

Neste ponto, gostaria de esclarecer algo sobre subconsultas correlacionadas. Já mencionamos que as subconsultas correlacionadas são executadas uma vez por cada candidato a linha. Esse fato pode afetar o desempenho de toda a consulta, especialmente quando trabalhamos com tabelas grandes.

Em resumo, o operador EXISTS (e as subconsultas correlacionadas) é um recurso SQL poderoso para determinados tipos de consultas. No entanto, devemos evitar subconsultas correlacionadas se estivermos trabalhando com tabelas grandes.

Praticando o operador EXISTS

Como em muitas outras linguagens de computador, aprender SQL fazendo exercícios é uma das melhores maneiras de adquirir habilidades. Portanto, nesta seção, mostrarei três exercícios do operador EXISTS de diferentes complexidades.

Exercício 1: Pedidos antigos

Exercício: O proprietário da empresa quer saber quais produtos (carros ou barcos) não foram pedidos nos últimos 365 dias.

Solução:

	 SELECT p1.product_name
       FROM  product p1
       WHERE NOT EXISTS ( SELECT 1 FROM sale s
                          WHERE  s.product_id = p1.product_id
                          AND    s.sale_date >= CURRENT_DATE - 365
                        );

Resultados:

Product_name
Ferrari F20
Pagani Zonda
Lamborghini B9
VanDutch 58

Explicação: A consulta principal usa a tabela product para obter a coluna product_name. A cláusula WHERE dessa consulta é a parte principal. Ela tem uma condição NOT EXISTS que é avaliada como TRUE para os produtos que não foram vendidos no último ano. A condição s.sale_date >= CURRENT_DATE - 365 na subconsulta obtém todas as linhas do último ano.

Observe que a subconsulta retorna uma constante ( 1 ). Isso ocorre porque o fato importante sobre a subconsulta é quantas linhas ela retorna, não o conteúdo das linhas retornadas; portanto, podemos colocar uma coluna ou uma constante como 1.

Exercício 2: Compradores de motores de barcos

Exercício: Nossa empresa é famosa por fabricar um motor para barcos e temos alguns clientes que só compram esse produto. O departamento de marketing quer identificar os clientes que só compram motores para barcos, para que possa segmentar esses clientes em uma campanha de marketing.

Solução:

SELECT * FROM client c1
WHERE EXISTS ( SELECT * FROM sale s1  -- they buy boat engines
		   JOIN  product p1 ON p1.product_id = s1.product_id 
                WHERE c1.client_id = s1.client_id
                AND   p1.product_name = 'Boat engine'   
               )
AND NOT EXISTS ( SELECT * FROM sale s2  -- they never buy other product
                 JOIN  product p2 ON p2.product_id = s2.product_id 
		    WHERE c1.client_id = s2.client_id
                 AND p2.product_name <> 'Boat engine' 
                );

Resultados:

client_idClient_nameCountry
13Pierre B.France
14Abdul E.Kuwait

Explicação: Este exercício tem uma cláusula WHERE com duas condições. A primeira condição usa um operador EXISTS para verificar se o cliente selecionado pela consulta externa comprou um motor de barco. A segunda condição WHERE usa NOT EXISTS para verificar se o mesmo cliente (o cliente selecionado pela consulta externa) nunca comprou nenhum outro tipo de produto.

Se você quiser explorar mais exercícios de subconsulta, recomendo o artigo SQL Subquery Practice: 15 Exercises with Solutions (Prática de subconsulta SQL: 15 exercícios com soluções).

Exercício 3: Never Bought

Exercício: O proprietário da empresa deseja um relatório Never Bought . O relatório deve ter apenas duas colunas: client_name e product_name. O conteúdo do relatório deve ser o complemento da tabela sale tabela. Em outras palavras, se um cliente nunca comprou um produto, então o par formado por este client_name e este product_name deve estar no relatório.

Solução: Há duas abordagens para resolver este exercício:

  • Usando NOT EXISTS.
  • Usando o operador de conjunto EXCEPT (ou MINUS).

Mostraremos as duas abordagens.

Solução usando NOT EXISTS:

SELECT c1.client_name, p1.product_name
FROM client c1, product p1
WHERE NOT EXISTS ( SELECT 1 FROM sale s 
                   WHERE c1.client_id = s.client_id
                   AND   p1.product_id = s.product_id  
                 )

Resultados parciais da consulta:

Client_nameProduct_name
John F.Ferrari F20
John F.Pagani Zonda
John F.Lamborghini B9
John F.VanDutch 56
Samid A.Lamborghini AX
Samid A.Pagani Zonda
Samid A.VanDutch 56
Samid A.Lamborghini B9
Samid A.Boat Engine Yamei 100
Samid A.Ferrari F20

Explicação: O primeiro ponto a ser entendido é o resultado dessa parte da consulta:

SELECT c1.client_name, p1.product_name
FROM client c1, product p1

Como não estamos unindo corretamente as tabelas client e producto resultado é um produto cartesiano - um conjunto de todos os pares <client_name, product_name> possíveis.

Quando tivermos todos os pares possíveis, continuaremos a descartar esses pares na tabela sale usando o operador NOT EXISTS.

Solução usando EXCEPT:

SELECT c1.client_name, p1.product_name
FROM client c1, product p1
EXCEPT
SELECT client_name, product_name 
FROM sale s
JOIN product p ON p.product_id  = s.product_id
JOIN client c ON c.client_id = s.client_id

Explicação: A primeira parte dessa abordagem é semelhante à solução anterior; criamos todos os pares cliente-produto possíveis. Em seguida, usando o operador EXCEPT, removemos os pares que estão na tabela sale tabela. Isso obtém os pares que estamos procurando.

Aqui está a diferença: Na segunda parte do EXCEPT, precisamos JOIN a tabela sale tabela com os operadores product e client tabelas.

Continue expandindo suas habilidades com o operador EXISTS do SQL

Neste artigo, abordamos os operadores EXISTS e NOT EXISTS com vários exemplos. Também explicamos os prós e os contras das subconsultas correlacionadas. Para os leitores que desejam aumentar suas habilidades em SQL, recomendo o curso Trilha de Práticas em SQL track. Você encontrará centenas de exercícios sobre tópicos de SQL, como JOINs, GROUP BY, HAVING, subconsultas e até mesmo o operador EXISTS.

Se estiver apenas começando a usar SQL ou precisar de uma atualização, recomendo nosso SQL para Iniciantes curso. Ao aumentar suas habilidades em SQL, você investe em você!