Blog Navicat

SQL Anti Join Oct 21, 2024 by Robert Gravelle

Una de las funciones más potentes de SQL es la operación JOIN, la cual proporciona un medio elegante y sencillo de combinar con cada una de las filas de una tabla y con cada fila de otra tabla. Sin embargo, hay ocasiones en la que es posible que queramos encontrar valores de una tabla que NO están presentes en otra tabla. Como veremos en el artículo del blog de hoy, las “joins” también pueden ser utilizadas para este propósito, incluyendo un predicado sobre el cual se unen las tablas. Conocidas como antijoins, estas pueden ser útiles para responder una variedad de preguntas relacionadas con los negocios, como:

  • ¿Qué clientes no hicieron un pedido?
  • ¿A qué empleados no se les ha asignado un departamento?
  • ¿Qué vendedores no cerraron un contrato de venta esta semana?

Este blog ofrecerá una introducción a los tipos existentes de “antijoins” y cómo escribirlos utilizando algunos ejemplos basados en la base de datos PostgreSQL dvdrental database. Escribiremos y ejecutaremos las consultas en Navicat Premium Lite 17.

Dos tipos de antijoins

Existen dos tipos de antijoins:

  • 1. left anti join: devuelve filas en la tabla izquierda que no coinciden en la tabla de la derecha
  • 2. right anti join: devuelve filas en la tabla derecha que no coinciden en la tabla de la izquierda

A continuación, las filas devueltas se muestran en azul en el diagrama a continuación:

anti-join_venn_diagram (56K)

En la siguiente sección, analizaremos algunas sintaxis diferentes que podemos utilizar para crear una “anti join”, como ejemplo utilizaremos una “left anti join”.

Left Anti Join usando EXISTS

Digamos que queremos encontrar todos los actores de la base de datos dvdrental que no aparecen en ninguna película. Lamentablemente, SQL no tiene una sintaxis incorporada para esta operación, pero podemos emularla utilizando EXISTS o, más específicamente, NOT EXISTS. Así es como se visualizaría esta consulta:

SELECT *
FROM actor a
WHERE NOT EXISTS (
  SELECT * FROM film_actor fa
  WHERE a.actor_id = fa.actor_id
)

Si la ejecutamos en Navicat Premium Lite 17, obtenemos los siguientes resultados:

left_anti-join (85K)

Cuidado con el “NOT IN”!

Dado que EXISTS e IN son equivalentes, puede llevar a la confusion de que NOT EXISTS y NOT IN también son equivalentes, pero cuidado, no siempre es así. Solamente son equivalentes si la tabla correcta (en este caso, film_actor) tiene una restricción NOT NULL en la clave externa (actor_id).

film_actor_table_design (82K)

En este caso específico, la consulta NOT IN devuelve los mismos resultados debido a la restricción NOT NULL en la columna actor_id:

left_anti-join_using_not_in (78K)

Si la columna actor_id permitiera valores nulos, se devolvería un conjunto de resultados vacío. Podemos verificar esto mediante la siguiente consulta:

SELECT *
FROM actor
WHERE actor_id NOT IN (1, 2, 3, 4, 5, NULL)
no_results_using_not_in (57K)

La consulta anterior no devuelve ninguna fila porque NULL representa un valor DESCONOCIDO en SQL. Como no podemos estar seguros de si “actor_id” está en un conjunto de valores de los cuales un valor es DESCONOCIDO, ¡todo el predicado se convierte en desconocido (UNKNOWN)!

La forma más fácil de evitar este “peligro” que plantea la sintaxis NOT IN, es quedarse con NOT EXISTS. En realidad, ni siquiera vale la pena apostar por la presencia de una restricción NOT NULL, ya que el administrador de bases de datos podría desactivar temporalmente la restricción para cargar algunos datos, lo que haría que su consulta quedara inutilizada durante esa desactivación.

Sintaxis alternativa

Como se mencionó en la introducción, también es posible realizar una “Anti Join” utilizando LEFT y RIGHT JOIN. Para que esto funcione, deberá agregar una cláusula WHERE con el predicado IS NULL. Aquí podemos ver la versión LEFT JOIN de esta sintaxis:

SELECT a.*
FROM actor a
  LEFT JOIN film_actor fa
	  ON a.actor_id = fa.actor_id
WHERE fa.actor_id IS NULL
left_anti-join_using_left_join (80K)

Tenga en cuenta que la sintaxis LEFT/RIGHT JOIN puede ejecutarse de forma más lenta porque el optimizador de consultas no la reconoce como una operación ANTI JOIN.

Conclusión

En el blog de hoy hemos aprendido a emular una operación Left Anti Join utilizando tres variaciones de la sintaxis SQL. De estas, NOT EXISTS debería ser la primera opción, ya que comunica mejor la intención de una operación ANTI JOIN y tiende ha ejecutarse más rápida.

¿Está interesado en probar Navicat Premium Lite 17? Puede descargar una versión con todas las funcionalidades para 14 días GRATIS. Está disponible para los sistemas operativos Windows, macOS y Linux.

Compartir
Archivos del Blog