Capítulo 2
4-Operações em Conjunto
A SQL oferece suporte as seguintes operações de conjunto.
UNION (União)
UNION ALL (União Completa)
INTERSECT (União)
MINUS (diferença)
União - UNION
Quando realizamos junções entre tabelas, formamos uma relação resultante com as colunas que contêm as colunas das tabelas originais.
Porém podem existir situações em que seja necessário recuperar outras linhas (que não as da junções), por exemplo.
Podemos ter ainda situações que requerem resultados de consultas que não são relacionadas mas que o resultado de ambas sejam importantes.
Em situações como essas usamos as Uniões.
O predicado UNION é utilzado posicionado entre dois comandos de consulta:
SELECT col1,col2
from tabela1
UNION [all]
select col3,col4
from tabela2
A operação de conjunto UNION é usada para combinar as saídas de duas ou mais instruções SELECT.
Ele elimina saídas duplicadas.
(se desejarmos que linhas repetidas apareçam, devemos utilizar o predicado ALL logo após o UNION, veja na próxima seção)
Existem somente duas regras para o UNION:
os comandos devem retornar o mesmo número de colunas;
as colunas correspondentes em cada comando devem possuir os mesmos tipos de dados
Exemplo 1
Exemplo 1
mysql> create database conjuntos;
Query OK, 1 row affected (0,10 sec)
mysql> use conjuntos
Database changed
mysql> create table tab1 (id int, valor int);
Query OK, 0 rows affected (0,49 sec)
mysql> create table tab2 (id int, valor int);
Query OK, 0 rows affected (0,40 sec)
mysql> insert into tab1 values (1 ,1),(2,1),(3,2),(4,3),(5,3),(6,4);
Query OK, 6 rows affected (0,05 sec)
Records: 6 Duplicates: 0 Warnings: 0
mysql> select * from tab1;
+------+-------+
| id | valor |
+------+-------+
| 1 | 1 |
| 2 | 1 |
| 3 | 2 |
| 4 | 3 |
| 5 | 3 |
| 6 | 4 |
+------+-------+
6 rows in set (0,00 sec)
mysql> insert into tab2 values (1,0),(2,1),(3,2),(4,3),(5,4),(6,5);
Query OK, 6 rows affected (0,08 sec)
Records: 6 Duplicates: 0 Warnings: 0
mysql> select * from tab2;
+------+-------+
| id | valor |
+------+-------+
| 1 | 0 |
| 2 | 1 |
| 3 | 2 |
| 4 | 3 |
| 5 | 4 |
| 6 | 5 |
+------+-------+
6 rows in set (0,00 sec)
mysql> select * from tab1
-> union
-> select * from tab2;
+------+-------+
| id | valor |
+------+-------+
| 1 | 1 |
| 2 | 1 |
| 3 | 2 |
| 4 | 3 |
| 5 | 3 |
| 6 | 4 |
| 1 | 0 |
| 5 | 4 |
| 6 | 5 |
+------+-------+
mysql> select * from tab1 union select * from tab2
-> order by id;
+------+-------+
| id | valor |
+------+-------+
| 1 | 1 |
| 1 | 0 |
| 2 | 1 |
| 3 | 2 |
| 4 | 3 |
| 5 | 3 |
| 5 | 4 |
| 6 | 4 |
| 6 | 5 |
+------+-------+
9 rows in set (0,00 sec)
Repare que as linhas iguais não aparecem na união
Exemplo2
Vamos usar o banco de dados livraria para esse segundo exemplo com UNION
Liste os títulos dos livros cujo assunto é "Banco de Dados" ou que foram lançados por editoras que contenham "Mirandela" no nome.
Exemplo 2
Select titulo
from livro
INNER JOIN ASSUNTO
on ASSUNTO = SIGLA
where descricao = 'banco de dados'
UNION
select titulo
from livro
INNER JOIN editora E
on editora = e.codigo
where nome LIKE '%mirandela'
-------------------------------------------------
mysql> select titulo from livro inner join assunto on assunto = sigla
where descricao = "banco de dados"
union
select titulo from livro
inner join editora E on editora = E.codigo
where nome LIKE "mirandela%";
+-----------------------------------+
| titulo |
+-----------------------------------+
| Banco de Dados para Web |
| Banco de Dados na Bioinformática |
| Programando em Linguagem C |
+-----------------------------------+
3 rows in set (0.00 sec)
UNION ALL
Esta operação é semelhante à Union. Mas também mostra as linhas duplicadas.
Veja o exemplo a seguir, com nosso banco "conjuntos" criado no exemplo 1.
Exemplo 3
mysql> select * from tab1 union ALL select * from tab2 order by id;
+------+-------+
| id | valor |
+------+-------+
| 1 | 1 |
| 1 | 0 |
| 2 | 1 |
| 2 | 1 |
| 3 | 2 |
| 3 | 2 |
| 4 | 3 |
| 4 | 3 |
| 5 | 3 |
| 5 | 4 |
| 6 | 4 |
| 6 | 5 |
+------+-------+
12 rows in set (0,00 sec)
mysql> select valor from tab1 union select valor from tab2;
+-------+
| valor |
+-------+
| 1 |
| 2 |
| 3 |
| 4 |
| 0 |
| 5 |
+-------+
6 rows in set (0,00 sec)
mysql> select valor from tab1 union ALL select valor from tab2;
+-------+
| valor |
+-------+
| 1 |
| 1 |
| 2 |
| 3 |
| 3 |
| 4 |
| 0 |
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
+-------+
12 rows in set (0,00 sec)
Interseção - INTERSECT(SQL, Intersect)
O operador INTERSECT é um operador de conjunto que retorna apenas linhas distintas de duas ou mais consultas.
O operador INTERSECT compara os conjuntos de resultados de duas consultas e retorna as linhas distintas que são geradas por ambas as consultas.
Para usar o operador INTERSECT para duas consultas, siga estas regras:
A ordem e o número de colunas na lista de seleção das consultas devem ser iguais.
Os tipos de dados das colunas correspondentes devem ser compatíveis.
O diagrama a seguir ilustra o operador INTERSECT.
Apesar de existir na estrutura da linguagem SQL, no mysql não existe a cláusula intersect. Para obter uma interseção, temos que usar os recursos já vistos. Acompanhe o exemplo a seguir.
Exemplo 4: Intersect no mysql
CREATE TABLE t1 (
id INT PRIMARY KEY
);
CREATE TABLE t2 LIKE t1;
INSERT INTO t1(id) VALUES(1),(2),(3);
INSERT INTO t2(id) VALUES(2),(3),(4);
mysql> show tables;
+----------------------+
| Tables_in_intersect1 |
+----------------------+
| t1 |
| t2 |
+----------------------+
2 rows in set (0.00 sec)
mysql> select * from t1;
+----+
| id |
+----+
| 1 |
| 2 |
| 3 |
+----+
3 rows in set (0.00 sec)
mysql> select * from t2;
+----+
| id |
+----+
| 2 |
| 3 |
| 4 |
+----+
3 rows in set (0.00 sec)
Criando o INTERSECT no mysql a partir de INNER JOIN
Exemplo 4, continuação
mysql> SELECT DISTINCT id FROM t1 INNER JOIN t2 USING(id);
+----+
| id |
+----+
| 2 |
| 3 |
+----+
2 rows in set (0.00 sec)
Essa forma de gerar a interseção se dá assim:
A cláusula INNER JOIN retorna linhas das tabelas da esquerda e da direita.
O operador DISTINCT remove as linhas duplicadas.
Lembrando que USING substiu o ON para o JOIN.
USING é útil quando ambas as tabelas compartilham uma coluna com o mesmo nome exato na junção.
Como USING executa uma junção de igualdade e só pode ser usado quando os nomes das colunas são idênticos, não é necessário incluir a coluna duas vezes. Disso resulta que quando usamos USING, não precisamos prefixar o nome da coluna com o nome da tabela!
Criando o INTERSECT Usando IN e subquery
Podemos criar a interseção usando uma subconsulta. Veja a continuação do exemplo 4 a seguir:
Exemplo 4, continuação
mysql> SELECT DISTINCT id FROM t1 WHERE id IN (SELECT id FROM t2);
+----+
| id |
+----+
| 2 |
| 3 |
+----+
2 rows in set (0.00 sec)
Essa forma de criar o intersect funciona assim:
A subconsulta retorna o primeiro conjunto de resultados.
- A consulta externa usa o operador IN para selecionar apenas os valores que existem no primeiro conjunto de resultados.
O operador DISTINCT garante que apenas valores distintos sejam selecionados.
Exemplo 5
No exemplo a seguir criamos o INTERSECT no banco "conjuntos", na coluna valor.
Exemplo 5
mysql> select distinct valor from tab1
-> inner join tab2
-> using(valor);
+-------+
| valor |
+-------+
| 1 |
| 2 |
| 3 |
| 4 |
+-------+
4 rows in set (0,00 sec)
Exemplo de INTERSECT no Banco de Dados livraria
Liste os títulos dos livros cujo assunto é "Programação" e que foram lançados por uma editora que contenha a palavra "Mirandela" no nome, sem repetições.
NA SQL:
Select titulo
from livro
INNER JOIN ASSUNTO
on assunto = sigla
where descricao = "programação"
INTERSECT
select titulo
from livro
INNER JOIN editora E
on editora = e.codigo
where nome like "%mirandela"
No mysql
Exemplo 6
select distinct titulo from livro
inner join assunto on assunto = sigla
where descricao = 'programação'
and titulo in
(
select titulo from livro
inner join editora E on editora = E.codigo
where nome like '%mirandela%'
);
+----------------------------+
| titulo |
+----------------------------+
| Programando em Linguagem C |
+----------------------------+
1 row in set (0.00 sec)
Diferença (EXCEPT/MINUS/NOT IN)
As cláusulas EXCEPT e MINUS da SQL são duas maneiras de se obter a diferença entre dois conjuntos (ambas fazem a mesma coisa).
A diferença é que EXCEPT está disponível no banco de dados PostgreSQL, enquanto MINUS está disponível em Oracle e SQL Server.
No mysql usamos NOT IN junto com uma subquery.
A figura abaixo ilustra o resultado de uma operação de diferença entre em conjuntos.
Na linguagem SQL podemos usar:
SELECT id FROM t1
MINUS
SELECT id FROM t2;
ou
SELECT id FROM t1
EXCEPT
SELECT id FROM t2;
Mas no mysql temos que usar NOT IN, como mostrado a seguir.
Exemplo: Encontre os valores que estão na tabela 1 e NÃO ESTÃO na tabela 2:
Exemplo 7
mysql> select id from t1 where id not in (select id from t2);
+----+
| id |
+----+
| 1 |
+----+
1 row in set (0,00 sec)
mysql> select id from t2 where id not in (select id from t1);
+----+
| id |
+----+
| 4 |
+----+
1 row in set (0,00 sec)