El lenguaje SQL como probablemente sabes se basa en la Matemática. Más específicamente en el Cálculo, el Álgebra y la Teoría de Conjuntos.
¿Recuerdas la Teoría de Conjuntos?
Es esa de los diagramas de Venn, seguro que los has visto en el Colegio o en la Universidad.
Diagrama 1. Si haces clic en la imagen lo verás más grande
Si nuestras tablas están bien diseñadas entonces cada fila es única, en ninguna tabla tendremos dos filas que sean exactamente iguales. Entonces, a cada fila podemos imaginarla como un elemento de un conjunto. Además, cuando escribimos un SELECT el resultado que obtenemos también es un conjunto.
Un conjunto puede estar vacío (en ese caso el SELECT no retorna resultados) o puede contener uno o más elementos (cuando el SELECT sí retorna resultados).
Por lo tanto ya tenemos a los conjuntos (todas las filas devueltas por cada SELECT) y a los elementos de los conjuntos (cada una de las filas devueltas por los SELECT). En la literatura SQL leerás que el resultado de ejecutar un SELECT es un conjunto resultado. Ese es el motivo.
¿Qué es una UNION en SQL?
Es la unión de dos conjuntos. Su sintaxis es la siguiente:
SELECT MiColumna1, MiColumna2, ... FROM MiTabla1 UNION SELECT MiColumna1, MiColumna2, ... FROM MiTabla2
La unión de dos conjuntos es siempre otro conjunto. Que puede estar vacío (en el caso que ambos conjuntos originales hubieran estado vacíos) o contener uno o más elementos.
Ejemplo 1:
Tenemos una tabla llamada COMPRASCAB (cabecera de las compras) y otra tabla llamada VENTASCAB (cabecera de las ventas) y deseamos un conjunto resultado que sea la unión de ambas tablas. ¿Para qué? para imprimir un informe que nos muestre todas las compras y todas las ventas. En este ejemplo, para que sea manejable, mostraremos solamente las compras y las ventas del día 9 de abril de 2012 aunque lo normal es que se muestren de varias fechas.
SELECT CMC_FECHAX, CMC_TIPDOC, CMC_NRODOC FROM COMPRASCAB WHERE CMC_FECHAX = '09/APR/2012'
Captura 1. Las compras del día 9 de abril de 2012
SELECT VTC_FECHAX, VTC_TIPDOC, VTC_NRODOC FROM VENTASCAB WHERE VTC_FECHAX = '09/APR/2012'
Captura 2. Las ventas del día 9 de abril de 2012
Y ahora queremos obtener un conjunto resultado que sea la unión entre COMPRASCAB y VENTASCAB y por lo tanto estará compuesto por todas las filas de COMPRASCAB y por todas las filas de VENTASCAB.
SELECT 'ECM' AS TIPMOV, CMC_FECHAX, CMC_TIPDOC, CMC_NRODOC FROM COMPRASCAB WHERE CMC_FECHAX = '09/APR/2012' UNION SELECT 'SVT' AS TIPMOV, VTC_FECHAX, VTC_TIPDOC, VTC_NRODOC FROM VENTASCAB WHERE VTC_FECHAX = '09/APR/2012'
Captura 3. Las compras y las ventas del día 9 de abril de 2012
Algunas observaciones:
- En el conjunto resultado tenemos todas las compras y todas las ventas ocurridas el día 9 de abril de 2012
- Para poder diferenciar a las compras de las ventas hemos agregado una nueva columna llamada TIPMOV la cual puede tener el valor «ECM» cuando es una entrada por compras o un valor «SVT» cuando es una salida por ventas. Agregar una columna para diferenciar a las filas de las tablas puede no ser necesario en otros casos.
Ejemplo 2:
En el Ejemplo 1. hemos visto la unión de dos tablas. Pero si lo necesitamos podemos unir tres o más tablas también, para simular el diagrama de Venn con el que empieza este artículo.
En una institución educativa tenemos las tablas ALUMNOS, PROFESORES, y EMPLEADOS y queremos obtener un conjunto resultado que sea la unión de esas tres tablas. Por lo tanto podríamos escribir:
SELECT "ALU" AS PERSONA, ALU_CEDULA, ALU_APELLD, ALU_NOMBRE FROM ALUMNOS UNION SELECT "PRO" AS PERSONA, PRO_CEDULA, PRO_APELLD, PRO_NOMBRE FROM PROFESORES UNION SELECT "EMP" AS PERSONA, EMP_CEDULA, EMP_APELLD, EMP_NOMBRE FROM EMPLEADOS
En este caso hemos unido tres tablas (ALUMNOS, PROFESORES, EMPLEADOS) para obtener un conjunto resultado compuesto por las filas de esas tres tablas. Para poder diferenciar si una fila corresponde a un alumno, a un profesor, o a un empleado, hemos agregado una columna llamada PERSONA.
Requisitos para poder unir dos conjuntos:
- La cantidad de columnas devueltas por cada conjunto debe ser exactamente la misma (o sea que si el primer SELECT devuelve 4 columnas, el segundo SELECT también debe devolver 4 columnas).
- El tipo de datos debe corresponder columna a columna. Eso significa que si la primera columna del primer conjunto es INTEGER la primera columna del segundo conjunto también debe ser INTEGER. Si la segunda columna del primer conjunto es DATE, la segunda columna del segundo conjunto también debe ser DATE. Y así sucesivamente.
- Los nombres de las columnas no importan, pueden ser iguales o distintos, eso no importa. Lo que sí importa es que los tipos de datos sean idénticos.
Simulando los diagramas de VENN:
La forma usual de simular los diagramas de Venn, como el que se muestra al inicio de este artículo es a través de vistas. De esa manera podríamos unir:
– Vista1 con Vista2
– Vista1 con Vista3
– Vista2 con Vista3
– Vista1 con Vista2 con Vista3
Y así tendríamos todas las posibilidades de unión de tres conjuntos.
Conclusión:
Usar UNION es muy conveniente cuando los datos que necesitamos están en dos o más conjuntos (tablas o vistas o stored procedures seleccionables) y las columnas tienen el mismo tipo de datos. Recuerda que no todas las columnas de ambos conjuntos deben tener el mismo tipo de datos, solamente las que se usarán en la UNION deben ser iguales.
Artículos relacionados:
El índice del blog Firebird21 | Firebird SQL
Jul 25, 2013 @ 22:26:09
Nacho
Ene 17, 2014 @ 11:43:17
Walter, Buen Dia. Leyendo este post entre ayer y hoy no encuentro la forma de implementar una consulta en mi Proyecto.
Tengo una tabla con movimientos de productos aleatorios que van insertandose luego de entradas y salidas de los mismos.
La tabla consta de columnas IdMov(Correlativo), IdProd, Fecha, Etc…
Necesito hacer un select que me devuelva el primer registro anterior y los posteriores a un Producto. Tengo un problema con la clausula order by que me parece no funciona para el primer select del UNION.
Ejemplo:
IdMov IdProd
1 5
2 3
3 5
4 5
5 1
6 2
7 5
8 5
Select First 1 IdMov, IdProd From MovProd Where IdProd = ‘5’ and idmov ‘4’
Esta consulta me trae
IdMov IdProd
1 5
7 5
8 5
Cuando me tendria que traer:
IdMov IdProd
3 5
7 5
8 5
No se si podre hacer una consulta asi. Gracias por leerme.
Nacho
Ene 17, 2014 @ 11:48:12
¿No salio el Select Union que estaba probando? Aca va:
Select First 1 IdMov, IdProd From MovProd Where IdProd = ’5′ and idmov ’4′
wrov
Ene 18, 2014 @ 00:03:30
¿Cuál es tu UNION?
No he visto esa cláusula en tu ejemplo.
La consulta que escribiste solamente te mostrará una fila, la que tiene IDPROD = 5 e IDMOV = 4. Nunca te mostrará las 3 filas que pusiste.
Saludos.
Walter.
Nacho
Ene 18, 2014 @ 10:19:50
No se porque no aparecen Walter si yo pongo todas las oraciones una cosa de locos!!!
Select First 1 IdMov, IdProd From MovProd Where IdProd = ’5′ and idmov ’4′
UNION
Select IdMov, IdProd From MovProd Where IdProd = ’5′ and idmov > ’4′
A ver is ahora sale…
wrov
Ene 18, 2014 @ 12:11:11
Esta consulta te devolverá el resultado que quieres:
Saludos.
Walter.
Juan Carlos Magaña Rodriguez
Abr 17, 2018 @ 16:52:07
Hola Walter, buen dia. Una consulta, yo registro ventas de dos maneras las ventas locales que se hacen en tienda se registran en una tabla y las ventas de ruta se registran en otra tabla, pero se podría decir que las dos tablas son muy similares, hay alguna forma de obtener un total de venta de un articulo donde solo me devuelva la cantidad vendida tanto local como en ruta, pero que me lo devuelva sumado, es decir que no me devuelva dos filas, sino que me devuelva la suma de las dos tablas? no se si me expliqué. Saludos.
wrov
Abr 17, 2018 @ 17:02:12
Sí, claro que se puede, sin problema, hay varias formas de resolverlo. Una de ellas es con un INNER JOIN si puedes relacionar a ambas tablas con alguna columna en común. Otra forma es con subconsultas (hay artículos sobre ese tema en el blog), otra es con CTE (common table expression), también podrías crear un procedimiento almacenado seleccionable, una función, etc.
Saludos.
Walter.
Juan Carlos Magaña Rodriguez
Abr 18, 2018 @ 11:38:23
Hola Walter, buen día. Agradezco tu ayuda, al final lo hice con una UNION dentro de una CTE, funcionó muy bien. Gracias.