INTERSECT y EXCEPT: comparar conjuntos de filas
Cuando necesitamos saber qué elementos comparten dos consultas o cuáles aparecen solamente en una, podemos expresar la comparación directamente como una operación entre conjuntos.
INTERSECT conserva las filas presentes en ambos resultados. EXCEPT conserva las de la primera consulta que no aparecen en la segunda.
INTERSECT conserva la región compartida por ambos conjuntos. EXCEPT conserva las filas del primer conjunto que no aparecen en el segundo.
Filas presentes en ambos conjuntos
INTERSECT conserva las filas completas que aparecen en los dos resultados y elimina duplicados.
Consulta1
INTERSECT
Consulta2
SELECT IdCliente
FROM dbo.Cliente
WHERE Activo = 1
INTERSECT
SELECT IdCliente
FROM dbo.Pedido
WHERE FechaPedido >= '20260101';
El resultado contiene clientes activos que también realizaron al menos un pedido desde la fecha indicada. Como operación de conjuntos, elimina duplicados.
La misma intención puede expresarse con EXISTS. La elección depende de si estamos comparando filas completas o correlacionando una consulta con otra.
Filas que existen solamente en el primero
EXCEPT conserva las filas completas de la primera consulta que no aparecen en la segunda. Cambiar el orden de las consultas cambia la pregunta.
Consulta1
EXCEPT
Consulta2
SELECT IdProducto
FROM dbo.Producto
WHERE Activo = 1
EXCEPT
SELECT IdProducto
FROM dbo.DetallePedido;
Esta consulta muestra productos activos que nunca aparecen en el detalle de un pedido.
El orden de los conjuntos es decisivo. Si invertimos las consultas, la pregunta cambia: obtendríamos identificadores presentes en detalles que no aparecen entre los productos activos.
Comparar más de una columna
SELECT
IdProducto,
Nombre,
Precio
FROM dbo.Producto
EXCEPT
SELECT
IdProducto,
Nombre,
Precio
FROM dbo.ProductoImportado;
Una fila se considera igual solamente cuando coinciden todas las columnas seleccionadas. Esto puede ayudar a validar una importación, pero no indica por sí mismo qué columna cambió.
Reglas de forma
Ambas consultas deben devolver el mismo número de columnas en el mismo orden, con tipos compatibles: tipos que SQL Server puede convertir a un tipo común. Los nombres finales provienen de la primera consulta.
Para esta comparación, dos valores NULL se consideran iguales. NULL representa un valor ausente o desconocido. Este comportamiento merece atención porque no es idéntico a escribir NULL = NULL en una condición.
El ORDER BY, si lo necesitamos, se escribe una sola vez al final del conjunto completo:
SELECT IdCliente
FROM dbo.Cliente
WHERE Activo = 1
EXCEPT
SELECT IdCliente
FROM dbo.Pedido
ORDER BY IdCliente;
Frente a JOIN y NOT EXISTS
INTERSECT y EXCEPT son expresivos cuando únicamente queremos las filas comunes o diferentes. Un JOIN es más apropiado si necesitamos columnas de ambos lados, y EXISTS o NOT EXISTS permite correlaciones y condiciones más detalladas.
Las operaciones eliminan duplicados. Si necesitamos conservar multiplicidad, debemos modelar explícitamente la comparación; no existe un INTERSECT ALL o EXCEPT ALL equivalente en SQL Server.
Qué conviene comprobar
Revisamos el orden de las columnas, conversiones implícitas y reglas de intercalación, que determinan cómo se compara y ordena el texto. También medimos el costo de eliminar duplicados. En conjuntos grandes, los índices —estructuras que organizan valores para facilitar el acceso— sobre las columnas comparadas pueden cambiar sustancialmente el trabajo requerido.
Antes de usar EXCEPT para reconciliar datos —comparar dos fuentes para localizar diferencias—, comprobamos si buscamos filas completas distintas o cambios por clave. Una clave es el valor o conjunto de valores que identifica una entidad. Son preguntas distintas y producen resultados distintos.
