Aprende SQL · lección gratuita
Aunque el título menciona tres, en realidad son cuatro operadores de conjuntos: UNION (elimina duplicados), UNION ALL (los conserva), INTERSECT (intersección) y EXCEPT (diferencia). Los operadores de conjuntos combinan los resultados de dos o más SELECT en uno solo, tratándolos como conjuntos de filas. SQLite ofrece UNION (suma, sin duplicados), UNION ALL (suma, conservando duplicados), INTERSECT (filas comunes a ambos) y EXCEPT (filas del primero que no están en el segundo). A diferencia de un JOIN, que combina columnas horizontalmente, los operadores de conjuntos apilan filas verticalmente.
UNION: une ambos resultados y elimina duplicados (implica un ordenamiento/deduplicación interno).UNION ALL: une y conserva todas las filas, incluidos duplicados; es más rápido porque no deduplica.INTERSECT: devuelve solo las filas que aparecen en ambos SELECT (y sin duplicados).EXCEPT: devuelve las filas del primer SELECT que no aparecen en el segundo (diferencia de conjuntos; en otros motores se llama MINUS).SELECT deben tener el mismo número de columnas y tipos compatibles, en el mismo orden; los nombres los toma del primer SELECT.La forma es SELECT ... <operador> SELECT .... Un único ORDER BY se permite al final, aplicándose al resultado combinado (no a cada SELECT por separado). No uses ORDER BY dentro de los SELECT intermedios de una unión.
Precedencia: en SQLite, INTERSECT, UNION, UNION ALL y EXCEPT se evalúan de izquierda a derecha con la misma prioridad. Si combinas varios operadores, usa subconsultas o CTEs entre paréntesis para dejar la intención explícita y evitar sorpresas.
UNION vs JOIN: si quieres más columnas (datos relacionados de otra tabla) usas JOIN; si quieres más filas (apilar resultados del mismo tipo) usas operadores de conjuntos. Errores comunes: número distinto de columnas en cada lado; esperar duplicados con UNION (los quita) o esperar que EXCEPT sea simétrico (no lo es: A EXCEPT B ≠ B EXCEPT A).
WITH dept_stats AS (SELECT departamento_id, COUNT(*) AS n, AVG(salario) AS avg_sal FROM empleados GROUP BY departamento_id) SELECT d.nombre, s.n AS empleados, ROUND(s.avg_sal, 0) AS salario_prom FROM dept_stats s JOIN departamentos d ON d.id = s.departamento_id ORDER BY avg_sal DESC
-- UNION: catálogo de lugares (ciudades de deptos + países de clientes), sin duplicados
SELECT ciudad AS lugar FROM departamentos
UNION
SELECT pais FROM clientes
ORDER BY lugar;
-- UNION ALL vs UNION: conservar vs deduplicar
SELECT pais FROM clientes
UNION ALL -- 18 filas (con repetidos)
SELECT pais FROM clientes;
-- Etiquetar el origen de cada fila en una unión
SELECT 'caro' AS tipo, nombre FROM productos WHERE precio > 10000
UNION ALL
SELECT 'barato', nombre FROM productos WHERE precio < 700
ORDER BY tipo, nombre;
-- INTERSECT: clientes que son a la vez de Perú y del segmento Enterprise (ids)
SELECT id FROM clientes WHERE pais = 'Perú'
INTERSECT
SELECT id FROM clientes WHERE segmento = 'Enterprise';
-- EXCEPT: productos que NUNCA se han vendido (catálogo menos los vendidos)
SELECT id FROM productos
EXCEPT
SELECT producto_id FROM detalle_pedidos
ORDER BY id;
-- EXCEPT: empleados que no son vendedores (no aparecen en pedidos)
SELECT id FROM empleados
EXCEPT
SELECT empleado_id FROM pedidos
ORDER BY id;
💡EXCEPTyNOT INresuelven anti-joins parecidos, peroEXCEPTdeduplica y compara la fila completa; además es inmune al problema de losNULLque tieneNOT IN. Para "lo que está en A pero no en B",EXCEPTsuele ser lo más legible.
| Cláusula / Función | Qué hace |
|---|---|
A UNION B | Filas de A y B, sin duplicados |
A UNION ALL B | Filas de A y B, con duplicados (más rápido) |
A INTERSECT B | Filas presentes en ambos |
A EXCEPT B | Filas de A que no están en B (no simétrico) |
ORDER BY final | Ordena el resultado combinado (una sola vez, al final) |
| Compatibilidad | Mismo nº de columnas y tipos compatibles en orden |
---
← CTEs recursivosFunciones de ventana: OVER y PARTITION BY →