El operador EXCEPT en SQL se utiliza para devolver las filas de la primera consulta SELECT que no aparecen en la segunda.
Es decir, compara dos conjuntos de resultados y devuelve la diferencia entre ambos, eliminando duplicados por defecto.
Se trata de un operador de conjuntos, similar a UNION ALL e INTERSECT, y es especialmente útil cuando queremos saber qué registros existen en una tabla pero no en otra.
Sintaxis básica de EXCEPT
SELECT columnas
FROM tabla1
EXCEPT
SELECT columnas
FROM tabla2;
- Ambas consultas deben:
- Tener el mismo número de columnas.
- Tener tipos de datos compatibles en cada columna correspondiente.
👉 El resultado será el conjunto de filas devueltas por la primera consulta que no estén presentes en la segunda.
Ejemplos prácticos de EXCEPT
1. Valores en una tabla que no están en otra
SELECT email FROM clientes
EXCEPT
SELECT email FROM suscriptores;
👉 Devuelve los correos de clientes que no están suscritos al boletín.
2. Comparar listas de IDs
SELECT id FROM empleados
EXCEPT
SELECT empleado_id FROM nominas;
👉 Devuelve los empleados que no tienen nómina asignada.
3. Comparar con condiciones
SELECT producto_id FROM ventas WHERE fecha >= '2025-01-01'
EXCEPT
SELECT producto_id FROM devoluciones WHERE fecha >= '2025-01-01';
👉 Muestra los productos vendidos en 2025 que no han sido devueltos. Uso combinado con WHERE.
4. EXCEPT en múltiples columnas
SELECT nombre, apellido FROM clientes
EXCEPT
SELECT nombre, apellido FROM empleados;
👉 Devuelve los nombres y apellidos de clientes que no figuran como empleados.
5. Usar EXCEPT dentro de subconsultas
SELECT * FROM pedidos
WHERE cliente_id IN (
SELECT id FROM clientes
EXCEPT
SELECT cliente_id FROM bloqueados
);
👉 Devuelve pedidos de clientes que no están bloqueados. Ejemplo dentro de una subconsulta.
Diferencia entre EXCEPT, NOT IN y NOT EXISTS
Aunque parecen similares, hay diferencias importantes:
- EXCEPT: compara conjuntos completos de resultados. Elimina duplicados por defecto.
- NOT IN: compara valores de una columna contra una lista, pero puede fallar con
NULL. - NOT EXISTS: más flexible y eficiente en algunos casos, especialmente con subconsultas correlacionadas.
Ejemplo equivalente con NOT IN:
SELECT email FROM clientes
WHERE email NOT IN (SELECT email FROM suscriptores);
Ejemplo equivalente con NOT EXISTS:
SELECT email FROM clientes c
WHERE NOT EXISTS (
SELECT 1 FROM suscriptores s WHERE s.email = c.email
);
👉 EXCEPT es más legible cuando se comparan conjuntos de resultados completos.
Diferencias entre EXCEPT y EXCEPT ALL
- EXCEPT (por defecto): elimina duplicados en el resultado final.
- EXCEPT ALL (soportado en algunos motores como PostgreSQL): mantiene los duplicados de la primera consulta que no estén en la segunda.
Ejemplo:
SELECT valor FROM tabla1
EXCEPT ALL
SELECT valor FROM tabla2;
👉 Aquí se devuelven todos los valores que no tienen correspondencia en la segunda consulta, manteniendo repeticiones.
Motores de base de datos y soporte de EXCEPT
- PostgreSQL: soporta
EXCEPTyEXCEPT ALL. - SQL Server: soporta
EXCEPT. - Oracle: no tiene
EXCEPT, pero se puede usarMINUS(equivalente). - MySQL/MariaDB: no soportan
EXCEPT. Se puede emular conLEFT JOINyNOT IN/NOT EXISTS.
Ejemplo equivalente en MySQL:
SELECT c.email
FROM clientes c
LEFT JOIN suscriptores s ON c.email = s.email
WHERE s.email IS NULL;
Casos de uso comunes de EXCEPT
- Comparación de tablas: detectar registros que existen en una tabla pero no en otra.
- Control de integridad: encontrar inconsistencias entre tablas relacionadas.
- Migración de datos: verificar qué filas faltan en una tabla destino.
- Reportes de diferencias: listar usuarios activos que no están en un grupo, productos vendidos que no fueron facturados, etc.
Errores comunes con EXCEPT
- Número de columnas distinto en ambas consultas.
SELECT id, nombre FROM empleados EXCEPT SELECT id FROM nominas; -- ❌ Error - Tipos de datos incompatibles entre columnas correspondientes.
- Confundir EXCEPT con INTERSECT:
EXCEPT: devuelve lo que está en la primera consulta y no en la segunda.INTERSECT: devuelve lo que está en ambas consultas.
- Intentar usarlo en MySQL: no está soportado, se debe emular con otras técnicas.
Buenas prácticas con EXCEPT
- Verificar siempre que ambas consultas devuelvan el mismo número de columnas y tipos compatibles.
- Usar
EXCEPTen consultas de validación y auditoría de datos. - Si trabajás con MySQL, tener preparado el equivalente con
LEFT JOINoNOT EXISTS. - Usar alias descriptivos en columnas para mayor claridad.
- En conjuntos grandes, verificar índices en las columnas clave para mejorar la performance.
Ejemplo avanzado: auditoría de migración
-- Registros en la tabla origen que no se migraron a destino
SELECT id, nombre, email FROM clientes_origen
EXCEPT
SELECT id, nombre, email FROM clientes_destino;
👉 Permite validar qué registros faltaron en la migración de datos.
Preguntas frecuentes (FAQ)
1. ¿EXCEPT elimina duplicados?
Sí, por defecto elimina duplicados. Para mantenerlos, se usa EXCEPT ALL (si está soportado).
2. ¿EXCEPT funciona en MySQL?
No. Debe reemplazarse por LEFT JOIN, NOT IN o NOT EXISTS.
3. ¿Qué diferencia hay entre EXCEPT y MINUS?
Son equivalentes. Oracle usa MINUS en lugar de EXCEPT.
4. ¿Puedo usar EXCEPT con múltiples columnas?
Sí, siempre que ambas consultas devuelvan el mismo número y tipo de columnas.
5. ¿Cuál es más eficiente, EXCEPT o NOT EXISTS?
Depende del motor y del caso. NOT EXISTS suele ser más optimizado en subconsultas correlacionadas, mientras que EXCEPT es más legible en comparaciones de conjuntos completos.
Conclusión
El operador EXCEPT en SQL es una herramienta muy útil para comparar conjuntos de resultados y obtener diferencias entre ellos. Permite detectar registros faltantes, inconsistencias y generar reportes de auditoría con gran claridad.
Aunque no todos los motores lo soportan, sus equivalentes (MINUS en Oracle, LEFT JOIN/NOT EXISTS en MySQL) permiten replicar su funcionalidad.
Dominar EXCEPT te permitirá escribir consultas más limpias y eficientes para análisis comparativos y control de datos.
Revisa fundamentos para combinar y comparar conjuntos en SELECT y FROM y visita el Glosario SQL completo.