Lecciones SQL‎ > ‎

T11 Conjuntos

Operaciones de conjuntos y MySQL

Un operador sobre conjuntos combina el resultado de dos sentencias select en un único resultado. Dependiendo del tipo de operación esas sentencias deberán cumplir unos requisitos en cuanto al resultado que dan.

Los operadores de conjuntos definidos para el álgebra relacional, base sobre la que se cimenta SQL, son la unión, intersección, diferencia, producto cartesiano y división. En otros motores de base de datos se dispone de algunos operadores como UNION, INTERSECT y MINUS.

En MySQL solo está disponible el operador UNION, aunque la operativa de los otros puede simularse con otros operadores de los que ya hemos visto unos cuantos.


Unión

Al utilizar el operador UNION entre dos sentencias select, el resultado final estará compuesto por todas aquellas filas que aparecen en el resultado de como mínimo una de las select. El operador UNION elimina filas duplicadas en el resultado final. El operador UNION ALL opera de igual modo que el operador UNION, pero no elimina filas duplicadas en el resultado final. 

Supongamos que queremos saber el nombre de los profesores que son ASO6 o imparten asignaturas de 6 créditos. Veamos primero el resultado de cada consulta por separado.


1) Nombre de los profesores cuya categoría es ASO6.

select nombre from profesores where categoria='ASO6';


2) Nombre de los profesores que imparten asignaturas de 6 créditos.

select nombre
from profesores p, imparte i, asignaturas
where p.dni=i.dni and asignatura=codigo and creditos=6;




Nombre de los profesores que son ASO6 o imparten asignaturas de 6 créditos.

select nombre from profesores where categoria='ASO6'
UNION
select nombre
from profesores p, imparte i, asignaturas
where p.dni=i.dni and asignatura=codigo and creditos=6;

nombre
RAFAEL ROMERO
EVA GOMEZ



La misma consulta pero solucionada con UNION ALL

select nombre from profesores where categoria='ASO6'
UNION ALL
select nombre
from profesores p, imparte i, asignaturas
where p.dni=i.dni and asignatura=codigo and creditos=6;

nombre
RAFAEL ROMERO
EVA GOMEZ
EVA GOMEZ
RAFAEL ROMERO


Intersección

Aunque no existe tal operador en MySQL, normalmente se puede sustituir por consultas ya conocidas.

DNI de los profesores que imparten y preparan.

IMPARTE[dni]

(COORDINADORES[dni])

Lo que debería solucionarse como

select dni from imparte
INTERSECT
select dni from prepara;

en realidad, en MySQL, debemos expresarlo como:

select distinct i.dni
from imparte i, prepara pp
where pp.dni=i.dni;

dni
21111222
21333444

Se usa el modificador distinct para que la expresión sustituya realmente la operativa de la intersección: las operaciones de conjuntos no devuelven duplicados (al igual que union all es una extensión para que se puedan resolver cierto tipo de consultas que sí necesitan los duplicados). No obstante, lo usaremos o no dependiendo de si lo necesitamos o no.



Diferencia

El operador MINUS tampoco está implementado en MySQL pero es fácilmente sustituible por expresiones NOT IN. En todo caso, el resultado final estará compuesto sólo por aquellas filas que aparecen en el resultado de la primera select y no aparecen en el resultado de la segunda.


Nombre de los profesores que son TEU y no imparten asignaturas de 6 créditos.

PROFESORES donde categoría='TEU' [nombre]

-

(PROFESORES x IMPARTE x ASIGNATURA
donde (PROFESORES.dni = IMPARTE.dni y codigo=asignatura y créditos=6)
[nombre])

Lo que debería solucionarse como

select nombre from profesores where categoria='TEU'
MINUS

select nombre

from profesores p, imparte i, asignaturas

where p.dni=i.dni and asignatura=codigo and creditos=6;


se soluciona así:

select nombre from profesores where categoria='TEU'
and nombre NOT IN 
(select nombre
 from profesores p, imparte i, asignaturas
 where p.dni=i.dni and asignatura=codigo and creditos=6);

nombre
MANUEL PALOMAR

Esta sería la consulta exactamente equivalente a la diferencia de conjuntos tal y como está definida en el álgebra relacional, con relaciones compatibles, pero esto es SQL, podemos simplificar la consulta y obtendremos el mismo resultado:


select nombre from profesores
where categoria='TEU'

  and dni NOT IN
(select dni
 from imparte i, asignaturas
 where asignatura=codigo and creditos=6);



Producto cartesiano

En SQL, y como ya se ha dicho anteriormente, el producto cartesiano se realiza con una select "sin where". 

select dni, codigo
from profesores, asignaturas

dni codigo
21111222 DGBD
21222333 DGBD
21333444 DGBD
21111222 FBD
21222333 FBD
21333444 FBD
21111222 FP
21222333 FP
21333444 FP
21111222 HI
21222333 HI
21333444 HI
21111222 PC
21222333 PC
21333444 PC

No obstante, el producto cartesiano, como cualquier otro tipo de consulta, puede filtrar las filas resultado a nuestra conveniencia.

Dni de los profesores que imparten 2 o más asignaturas

select distinct i1.dni
from imparte i1, imparte i2
where i1.dni = i2.dni
    and i1.asignatura != i2.asignatura;

Del producto cartesiano de una tabla por sí misma solo nos interesan las filas en las que el profesor "de la izquierda" es el mismo que el "de la derecha"; sí, además, las asignaturas son diferentes, la conclusión no puede ser otra que ese profesor cumple con la condición.

Aunque para el ejemplo que hemos propuesto hay una forma más amigable de solucionar este enunciado, la que mostramos a continuación, el producto cartesiano es una opción que podemos utilizar cuando creamos conveniente

select dni from imparte group by dni having count(*) >= 2;


Nombre de los profesores que imparten asignaturas de 6 créditos y no son TEU.

PROFESORES x IMPARTE x ASIGNATURA
donde (PROFESORES.dni = IMPARTE.dni y codigo=asignatura y créditos=6)
[nombre]
-
(PROFESORES donde categoría='TEU' [nombre])

select nombre

from profesores p, imparte i, asignaturas
where p.dni=i.dni and asignatura=codigo and creditos=6
and nombre NOT IN 
(select nombre from profesores where categoria='TEU');

nombre
RAFAEL ROMERO


Concatenación natural

Este operador está implementado en MySQL y Oracle Database pero no es seguro que otros SGBD lo tengan implementado igualmente. Igual que en álgebra relacional, este operador asume que hay columnas comunes en dos tablas diferentes (en principio, que se llamen igual) y automatiza la reunión (join) en base a la igualdad de valores en estas columnas comunes. Dicho de otra forma:

Todos los datos de profesores que imparten alguna asignatura y códigos de esas asignaturas.

select p.dni, p.nombre, p.categoria, p.ingreso, i.asignatura
from profesores p, imparte i
where p.dni=i.dni;

obtiene el mismo resultado que

select * from profesores NATURAL JOIN imparte;


En ambos casos la salida es la que se muestra a continuación. Nótese que solo se muestra una columna de "dni" (concretamente la de PROFESORES, la tabla a la izquierda del operador).

dni nombre categoria ingreso asignatura
21111222 EVA GOMEZ TEU 1993-10-01 DGBD
21111222 EVA GOMEZ TEU 1993-10-01 FBD
21333444 RAFAEL ROMERO ASO6 1992-06-16 PC


Su expresión en álgebra relacional sería:

PROFESORES ∞ IMPARTE

A pesar de la posible comodidad de uso de este operador hay que tener mucho cuidado, si no existen columnas comunes se devolverá un producto cartesiano. Otra fuente de resultados no esperados es que haya más columnas con idéntico nombre de las deseadas.

Material adicional

Aunque es un operador que se comporta de manera diferente a los anteriores también podríamos incluir EXISTS dentro de la categoría de operadores SQL de conjuntos. Además, es la base a una de las simulaciones clásicas del operador DIVISIÓN del álgebra relacional. Ambos se comentan en una lección complementaria.


Subpáginas (1): Conjuntos 2