Volver a la lista de artículos Artículos
Lectura de 11 minutos

El Operador SQL EXISTS

El uso de la cláusula SQL EXISTS nos permite crear consultas complejas de forma sencilla. Conozca los pros y los contras del operador EXISTS en este artículo.

En SQL, el operador EXISTS nos ayuda a crear condiciones lógicas en nuestras consultas. Esencialmente, comprueba si hay alguna fila en una subconsulta. Te mostraremos la sintaxis de EXISTS, te daremos algunos ejemplos de uso y te propondremos varios ejercicios para que practiques.

Si estás empezando con SQL o necesitas un repaso de SQL, te recomiendo el curso SQL para principiantes. Incluye temas de SQL que van desde los SELECT básicos hasta temas complejos como uniones, agregaciones y subconsultas. Es una buena forma de desarrollar, refrescar o ampliar tus conocimientos de SQL.

Sintaxis del operador EXISTS

Probablemente esté familiarizado con operadores SQL como =, >, < y LIKE. Todos estos operadores se pueden utilizar para crear condiciones lógicas que devolverán TRUE o FALSE. Algunos ejemplos de condiciones comunes son:

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

Los operadores =, <, y LIKE comparan dos elementos u operandos. Esta es la razón por la que se llaman operadores binarios.

				WHERE EXISTS ( subquery )

Ahora veamos la consulta SQL completa para determinar dónde se puede colocar la condición EXISTS:

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

El operador EXISTS se utiliza para crear condiciones booleanas para verificar si una subconsulta devuelve fila(s) o un conjunto vacío. Cuando su subconsulta devuelve al menos una fila, EXISTS devuelve TRUE. No importa cuántas filas se devuelvan ni cuántas columnas haya en la lista de la subconsulta SELECT. Sólo cuando la subconsulta devuelve 0 filas, EXISTS devuelve FALSE. Es importante señalar que ninguna de las filas devueltas por la subconsulta se muestra en el resultado final.

Ejemplo de base de datos: Barcos y coches de lujo

Examinemos varias consultas de ejemplo basadas en una base de datos de ejemplo de una empresa que vende coches y barcos de lujo. La empresa lleva un registro de los coches y barcos en la tabla product, que tiene las columnas 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

La base de datos también tiene una tabla Client con las columnas client_id, client_name y country.

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

Por último, existe la tabla sale tabla con las columnas product_id, client_id, sale_date. (Para simplificar, omito la idea de tener una tabla para las órdenes de compra; en este tipo de empresa, un cliente normalmente compra sólo un producto a la 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

Ejemplos del operador EXISTS de SQL

Ejemplo 1: Búsqueda de productos vendidos

Para el primer ejemplo de consulta, supongamos que el director de marketing quiere saber qué coches y barcos se vendieron entre el 1 y el 15 de abril de 2024. La siguiente consulta lo hace:

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

Hay otras formas de escribir esta consulta sin utilizar el operador EXISTS. Sin embargo, para explicar cómo funciona el operador EXISTS, éste es un buen ejemplo básico.

El SELECT principal es muy sencillo; va a la tabla product para obtener la columna product_name. Sin embargo, no queremos todos los product_names de la tabla. Queremos sólo aquellos productos que devuelvan TRUE para la siguiente condición:

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’
             )

Si analizamos la condición, la subconsulta devuelve todos los registros de ventas de un producto determinado (p1.product_id) y para un periodo de tiempo concreto (2024-04-01 a 2024-04-15). Si la subconsulta devuelve registros, entonces EXISTS devolverá TRUE. Si la subconsulta no devuelve ningún registro, EXISTS devolverá FALSE. Tenga en cuenta que la subconsulta se ejecuta varias veces, una por cada fila leída por la consulta externa.

Este tipo de subconsultas que se ejecutan una vez por cada fila procesada en la consulta principal se denominan "subconsultas correlacionadas" y tienen sus particularidades. Si quieres profundizar en este tema, te sugiero el artículo Correlated Subquery in SQL: Guía para principiantes.

Ejemplo 2: Uso del Operador NOT EXISTS

Supongamos ahora que el gestor quiere los nombres de los vehículos que no se vendieron durante el mismo periodo. Este tipo de consulta -en la que buscamos registros que no existen en la base de datos- es excelente para el operador NOT EXISTS. Al fin y al cabo, estamos buscando elementos que no existen en la base de datos. La consulta es la siguiente

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

Una vez que entendemos cómo funciona el operador EXISTS en SQL, entender NOT EXISTS es muy sencillo; es lo contrario. Si EXISTS devuelve TRUE, entonces NOT EXISTS devuelve FALSE y viceversa.

En este ejemplo, la consulta principal tiene una cláusula WHERE con dos condiciones. La primera condición es pedir productos del tipo "vehículo". La segunda condición utiliza NOT EXISTS para mantener sólo los productos que no tuvieron ventas durante el periodo 2024-04-01 a 2024-04-15. En otras palabras, buscamos los productos para los que la subconsulta devuelve un conjunto de resultados vacío, es decir, para los que no hay ventas en ese periodo.

En algunos casos, podemos resolver este tipo de consulta utilizando NOT IN con una subconsulta. En esta consulta en particular, podemos poner esta 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’
                           )

Sin embargo, hay una diferencia en la forma en que la consulta se ejecuta internamente en la base de datos. La condición de la subconsulta NOT IN se ejecuta una vez, mientras que la condición de la subconsulta NOT EXISTS se ejecuta una vez por cada fila. Así es; NOT EXISTS es una subconsulta correlacionada. Lea los artículos 5 Ejemplos de Subconsultas SQL y Operador SQL IN para más información sobre estos operadores.

Ejemplo 3: Usando EXISTS con NOT EXISTS

A continuación, necesitamos una lista de aquellos clientes que no compraron un barco durante el verano de 2023 pero sí lo hicieron durante el invierno anterior (es decir, de diciembre de 2022 a marzo de 2023). La consulta para obtener ese informe es

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
                  ) ;

Resultados:

client_idClient_nameCountry
11Samid A.Kuwait

Después de los dos ejemplos anteriores, este ejemplo no debería ser demasiado difícil de entender; es la combinación de ambos. La idea es seleccionar todo el registro (SELECT *) de la tabla client y después utilizar EXISTS para comprobar que se ha comprado un barco el invierno pasado. Después, utilizamos NOT EXISTS para comprobar que no se ha comprado un barco en el verano pasado. Nótese que ambas subconsultas tienen un JOIN entre los caracteres sale y product porque necesitamos utilizar las columnas product_type y sale_date en las condiciones WHERE.

En este punto, me gustaría aclarar algo sobre las subconsultas correlacionadas. Hemos mencionado que las subconsultas correlacionadas se ejecutan una vez por cada fila candidata. Este hecho puede afectar al rendimiento de toda la consulta, especialmente cuando trabajamos con tablas de gran tamaño.

En resumen, el operador EXISTS (y las subconsultas correlacionadas) es un potente recurso SQL para ciertos tipos de consultas. Sin embargo, debemos evitar las subconsultas correlacionadas si trabajamos con tablas grandes.

Practicando el Operador EXISTS

Como muchos otros lenguajes de computación, aprender SQL haciendo ejercicios es una de las mejores formas de adquirir habilidades. Así que en esta sección, mostraré tres ejercicios del operador EXISTS de diferentes complejidades.

Ejercicio 1: Órdenes Antiguas

Ejercicio: El dueño de la empresa quiere saber qué productos (coches o barcos) no se han pedido en los últimos 365 días.

Solución:

	 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

Explicación: La consulta principal utiliza la tabla product para obtener la columna product_name. La cláusula WHERE de esta consulta es la parte clave. Tiene una condición NOT EXISTS que evalúa a TRUE para aquellos productos que no se han vendido en el último año. La condición s.sale_date >= CURRENT_DATE - 365 en la subconsulta obtiene todas las filas del último año.

Observe que la subconsulta devuelve una constante ( 1 ). Esto se debe a que el dato importante de la subconsulta es cuántas filas devuelve, no el contenido de las filas devueltas; por tanto, podemos poner una columna o una constante como 1.

Ejercicio 2: Compradores de motores de barcos

Ejercicio: Nuestra empresa es famosa por fabricar un motor para barcos y tenemos algunos clientes que sólo compran este producto. El departamento de marketing quiere identificar a los clientes que sólo compran motores para barcos para poder dirigirse a ellos en una campaña de marketing.

Solución:

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

Explicación: Este ejercicio tiene una cláusula WHERE con dos condiciones. La primera condición utiliza un operador EXISTS para verificar que el cliente seleccionado por la consulta externa ha comprado un motor de barco. La segunda condición WHERE utiliza NOT EXISTS para verificar que el mismo cliente (el cliente seleccionado por la consulta externa) nunca ha comprado otro tipo de producto.

Si quieres explorar más ejercicios de subconsultas, te recomiendo el artículo SQL Subquery Practice: 15 Exercises with Solutions.

Ejercicio 3: Nunca Comprado

Ejercicio: El dueño de la compañía quiere un reporte de Nunca Comprado . El informe debe tener sólo dos columnas: client_name y product_name. El contenido del informe debe ser el complemento de la tabla sale tabla. En otras palabras, si un cliente nunca compró un producto, entonces el par formado por este client_name y este product_name debe estar en el informe.

Solución: Hay dos enfoques para resolver este ejercicio:

  • Utilizando NOT EXISTS.
  • Utilizando el operador de conjunto EXCEPT (o MINUS).

Mostraremos ambos enfoques.

Solución utilizando 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 parciales de la 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

Explicación: El primer punto a entender es el resultado de esta parte de la consulta:

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

Como no estamos uniendo correctamente las tablas client y productel resultado es un producto cartesiano, es decir, un conjunto de todos los pares posibles de <client_name, product_name>.

Una vez que tenemos todos los pares posibles, procedemos a descartar esos pares en la tabla sale mediante el operador NOT EXISTS.

Solución utilizando 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

Explicación: La primera parte de este enfoque es similar a la solución anterior; creamos todos los pares posibles cliente-producto. A continuación, mediante el operador EXCEPT, eliminamos los pares que se encuentran en la sale tabla. Así obtenemos los pares que buscamos.

He aquí la diferencia: En la segunda parte de EXCEPT, necesitamos JOIN la tabla sale con los operadores product y client tablas.

Continúe Expandiendo sus Habilidades con el Operador SQL EXISTS

En este artículo, cubrimos los operadores EXISTS y NOT EXISTS con varios ejemplos. También explicamos los pros y contras de las subconsultas correlacionadas. A los lectores que deseen ampliar sus conocimientos de SQL, les recomiendo la Ejercicio de SQL pista. Encontrarán cientos de ejercicios sobre temas de SQL como JOINs, GROUP BY, HAVING, subconsultas e incluso el operador EXISTS.

Si acaba de iniciarse en SQL o necesita un repaso, le recomiendo nuestro SQL para principiantes curso. Cuando aumentas tus conocimientos de SQL, ¡inviertes en ti!