UNION
El operador UNION combina los resultados de dos o más sentencias SELECT en un único conjunto de resultados. Es útil cuando necesitas mezclar datos de diferentes tablas, combinar filtros que no se expresan fácilmente en una sola consulta, o construir informes que consolidan información de varias fuentes.
UNION elimina las filas duplicadas del resultado combinado. Si quieres mantener los duplicados, usas UNION ALL.
Sintaxis
SELECT columnas FROM tabla1
UNION [ALL]
SELECT columnas FROM tabla2
[ORDER BY columna]
[LIMIT n];Cada SELECT debe devolver el mismo número de columnas. Los nombres de las columnas del resultado final se toman del primer SELECT. El ORDER BY y el LIMIT, si los hay, se aplican al resultado combinado.
UNION básico
Un directorio de contactos que mezcle clientes y empleados:
SELECT nombre, email, 'cliente' AS tipo
FROM clientes
UNION
SELECT nombre, email, 'empleado'
FROM empleados
ORDER BY tipo, nombre;| nombre | tipo | |
|---|---|---|
| Alejandro | alejandro.serrano@email.com | cliente |
| Ana | ana.martinez@email.com | cliente |
| Andrés | andres.vega@email.com | cliente |
| Carlos | carlos.rodriguez@email.com | cliente |
| ... | ... | cliente |
| Alberto | alberto.prieto@tienda.com | empleado |
| Cristina | cristina.guerrero@tienda.com | empleado |
| Daniel | daniel.vargas@tienda.com | empleado |
| ... | ... | empleado |
El resultado combina las 20 filas de clientes con las 10 de empleados. La columna tipo es una constante literal que añadimos para identificar el origen de cada fila. El ORDER BY ordena el resultado final (primero todos los clientes, luego los empleados, ambos grupos ordenados por nombre).
UNION ALL vs UNION
La diferencia entre UNION y UNION ALL es el tratamiento de duplicados:
-- Productos con etiqueta 'premium'
SELECT p.nombre, p.precio
FROM productos p
JOIN etiquetas_producto ep ON p.id = ep.producto_id
WHERE ep.etiqueta = 'premium'
UNION ALL
-- Productos con etiqueta 'más vendido'
SELECT p.nombre, p.precio
FROM productos p
JOIN etiquetas_producto ep ON p.id = ep.producto_id
WHERE ep.etiqueta = 'más vendido';| nombre | precio |
|---|---|
| iPhone 15 Pro | 1299.99 |
| MacBook Air M3 | 1399.00 |
| ASUS ROG Zephyrus | 1899.99 |
| Sofá 3 plazas | 599.00 |
| iPhone 15 Pro | 1299.99 |
| Samsung Galaxy S24 | 899.99 |
| Xiaomi 14 | 599.99 |
| Camiseta algodón básica | 24.99 |
| Robot de cocina | 249.99 |
Con UNION ALL, el iPhone 15 Pro aparece dos veces porque tiene ambas etiquetas. Si cambiamos UNION ALL por UNION:
-- Misma consulta pero con UNION (sin ALL)
SELECT p.nombre, p.precio
FROM productos p
JOIN etiquetas_producto ep ON p.id = ep.producto_id
WHERE ep.etiqueta = 'premium'
UNION
SELECT p.nombre, p.precio
FROM productos p
JOIN etiquetas_producto ep ON p.id = ep.producto_id
WHERE ep.etiqueta = 'más vendido';| nombre | precio |
|---|---|
| iPhone 15 Pro | 1299.99 |
| MacBook Air M3 | 1399.00 |
| ASUS ROG Zephyrus | 1899.99 |
| Sofá 3 plazas | 599.00 |
| Samsung Galaxy S24 | 899.99 |
| Xiaomi 14 | 599.99 |
| Camiseta algodón básica | 24.99 |
| Robot de cocina | 249.99 |
Ahora son 8 filas: el iPhone solo aparece una vez. UNION compara todas las columnas de cada fila para determinar si es duplicada. Si todas las columnas coinciden, se elimina.
UNION ALL es más rápido que UNION porque no necesita comprobar duplicados. Usa UNION ALL cuando sepas que no habrá duplicados o cuando no te importe que los haya.
Reglas de compatibilidad
Para que un UNION funcione, las consultas deben cumplir una regla fundamental: todas deben devolver el mismo número de columnas. Si los tipos de datos no coinciden, MySQL intenta convertirlos automáticamente:
-- ERROR: diferente número de columnas
SELECT nombre, precio FROM productos
UNION
SELECT nombre FROM categorias;ERROR 1222 (21000): The used SELECT statements have a different number of columns
Los nombres de las columnas del resultado siempre vienen del primer SELECT. Si el primer SELECT tiene AS producto y el segundo AS categoria, la columna del resultado se llamará producto.
UNION con ORDER BY y LIMIT
El ORDER BY y el LIMIT se aplican al resultado combinado, no a las consultas individuales:
SELECT nombre, precio, 'caro' AS rango
FROM productos
WHERE precio > 1000
UNION ALL
SELECT nombre, precio, 'barato'
FROM productos
WHERE precio < 25
ORDER BY precio DESC
LIMIT 8;| nombre | precio | rango |
|---|---|---|
| ASUS ROG Zephyrus | 1899.99 | caro |
| Lenovo ThinkPad X1 | 1549.00 | caro |
| MacBook Air M3 | 1399.00 | caro |
| iPhone 15 Pro | 1299.99 | caro |
| Camiseta algodón básica | 24.99 | barato |
| Cable USB-C a Lightning | 19.99 | barato |
| Banda elástica set x5 | 19.99 | barato |
| El nombre del viento | 16.99 | barato |
Si necesitas ordenar o limitar una consulta individual antes del UNION, envuélvela en paréntesis:
(SELECT nombre, precio FROM productos WHERE precio > 1000 ORDER BY precio DESC LIMIT 2)
UNION ALL
(SELECT nombre, precio FROM productos WHERE precio < 20 ORDER BY precio ASC LIMIT 2);UNION para informes consolidados
Un caso de uso habitual es construir informes que resumen datos de diferentes periodos:
SELECT 'Q4 2025' AS periodo, COUNT(*) AS pedidos, SUM(total) AS ingresos
FROM pedidos
WHERE fecha_pedido BETWEEN '2025-10-01' AND '2025-12-31'
UNION ALL
SELECT 'Q1 2026', COUNT(*), SUM(total)
FROM pedidos
WHERE fecha_pedido BETWEEN '2026-01-01' AND '2026-03-31';| periodo | pedidos | ingresos |
|---|---|---|
| Q4 2025 | 22 | 11080.69 |
| Q1 2026 | 3 | 244.96 |
Cada SELECT calcula sus propias agregaciones y el UNION ALL combina los resultados en una tabla compacta. Esto es equivalente a usar GROUP BY con CASE, pero a veces resulta más legible, especialmente cuando los periodos requieren filtros complejos.
UNION de la misma tabla con distintos filtros
Otra aplicación práctica: combinar filas de la misma tabla que cumplen criterios diferentes, añadiendo una columna que identifique el criterio:
SELECT id, estado, total, 'tiene notas' AS motivo
FROM pedidos
WHERE notas IS NOT NULL
UNION
SELECT id, estado, total, 'cancelado'
FROM pedidos
WHERE estado = 'cancelado'
ORDER BY id;| id | estado | total | motivo |
|---|---|---|---|
| 2 | entregado | 899.99 | tiene notas |
| 5 | entregado | 1899.99 | tiene notas |
| 10 | procesando | 599.99 | tiene notas |
| 16 | cancelado | 699.00 | cancelado |
| 17 | cancelado | 49.99 | cancelado |
| 25 | cancelado | 149.99 | cancelado |
Los pedidos 16 y 25 cumplen ambos criterios (están cancelados y tienen notas), pero UNION los muestra una sola vez. El motivo que aparece depende de cuál de las dos consultas los encontró primero. Si necesitaras que aparecieran dos veces (una por cada motivo), usarías UNION ALL.
Cuándo usar UNION
Usa UNION cuando necesites combinar resultados de tablas diferentes con estructura similar, consolidar datos con distintos filtros en un solo resultado, o construir informes que agreguen datos por separado. Prefiere UNION ALL cuando los duplicados no sean un problema, ya que es más eficiente.
Practica con UNION
Usa el editor para combinar resultados de varias consultas:
En el siguiente artículo veremos INTERSECT, que devuelve solo las filas que aparecen en ambas consultas.
Escrito por Eduardo Lázaro
