SQL suporta operações de conjunto equivalentes às da álgebra relacional: união, interseção e diferença. Essas operações combinam os resultados de duas consultas e exigem que ambas retornem o mesmo número de colunas, com tipos compatíveis.
Os Três Operadores
Operador SQL
Álgebra Relacional
Descrição
UNION
\(\cup\) (união)
Linhas que aparecem em pelo menos uma das consultas
INTERSECT
\(\cap\) (interseção)
Linhas que aparecem nas duas consultas
EXCEPT
\(-\) (diferença)
Linhas da primeira consulta que não aparecem na segunda
Por padrão, todas as três operações eliminam duplicatas do resultado. Para manter duplicatas, adicione ALL: UNION ALL, INTERSECT ALL, EXCEPT ALL.
Exemplos com as Disciplinas da UnDF
Para demonstrar as operações, usamos dois conjuntos:
Conjunto A: disciplinas de Pedagogia (id_curso = 211) — 8 disciplinas
Conjunto B: disciplinas com carga horária ≥ 60 horas — 22 disciplinas (todas exceto as duas de PED com 40 h e 50 h)
UNION: Disciplinas de PED ou com carga horária ≥ 60 h
-- Conjunto A: disciplinas de PedagogiaSELECT id_disciplina, nome_disciplina, carga_horariaFROM disciplinaWHERE id_curso =211UNION-- Conjunto B: disciplinas com carga horária >= 60 horasSELECT id_disciplina, nome_disciplina, carga_horariaFROM disciplinaWHERE carga_horaria >=60ORDERBY id_disciplina;
Displaying records 1 - 10
id_disciplina
nome_disciplina
carga_horaria
1110201
História Econômica Geral
75
1110202
Culturas Digitais
60
1110401
Microeconomia 2
75
1110402
Macroeconomia 2
95
1110601
Economia Brasileira
75
1110602
Orçamento e Finanças Públicas
75
1110801
Monografia
100
1110802
Desenvolvimento Econômico
90
2110201
Desenvolvimento Humano
60
2110202
Didática Geral
60
Nota
Várias disciplinas de PED pertencem aos dois conjuntos, mas aparecem apenas uma vez no resultado — a união elimina duplicatas automaticamente. As disciplinas de PED com menos de 60 h são adicionadas via conjunto A.
INTERSECT: Disciplinas de PED E com carga horária ≥ 60 h
-- Disciplinas de PED que também têm carga horária >= 60 horasSELECT id_disciplina, nome_disciplina, carga_horariaFROM disciplinaWHERE id_curso =211INTERSECTSELECT id_disciplina, nome_disciplina, carga_horariaFROM disciplinaWHERE carga_horaria >=60ORDERBY id_disciplina;
6 records
id_disciplina
nome_disciplina
carga_horaria
2110201
Desenvolvimento Humano
60
2110202
Didática Geral
60
2110401
Eletiva I
80
2110402
Fundamentos e Orientações Metodológicas - Ed. Infantil - BNCC
80
2110601
Eletiva II
80
2110801
Tecnologia Educacional - Design
60
As disciplinas de PED com 40 h e 50 h satisfazem apenas o primeiro lado — são excluídas do resultado.
EXCEPT: Disciplinas de PED que NÃO têm carga horária ≥ 60 h
-- Disciplinas de PED com carga horária inferior a 60 horasSELECT id_disciplina, nome_disciplina, carga_horariaFROM disciplinaWHERE id_curso =211EXCEPTSELECT id_disciplina, nome_disciplina, carga_horariaFROM disciplinaWHERE carga_horaria >=60;
2 records
id_disciplina
nome_disciplina
carga_horaria
2110802
Estatística Aplicada
50
2110602
Educação do Campo, Indígena e Quilombola
40
Apenas as disciplinas de PED com 40 h e 50 h pertencem ao conjunto A mas não ao conjunto B.
UNION ALL: Mantendo Duplicatas
-- Todos os id_curso de disciplinas e alunos (com repetição)SELECT id_curso FROM disciplinaUNIONALLSELECT id_curso FROM alunoORDERBY id_curso;
Displaying records 1 - 10
id_curso
111
111
111
111
111
111
111
111
111
111
O resultado tem 24 + 18 = 42 linhas, com muitas repetições. Use UNION ALL quando a presença de duplicatas é intencional (por exemplo, ao contar ocorrências totais).
Compatibilidade de Esquema
As duas consultas combinadas por UNION, INTERSECT ou EXCEPT devem ter:
O mesmo número de colunas no SELECT
Tipos de dados compatíveis em cada posição correspondente
Os nomes das colunas no resultado final são determinados pela primeira consulta.
Para Praticar
-- EXCEPT: disciplinas que possuem pré-requisito mas nenhum aluno cursou-- (aparece em prereq, mas não em matricula_disciplina)SELECT d.id_disciplina, d.nome_disciplinaFROM disciplina dWHERE d.id_disciplina IN (SELECT id_disciplina FROM prereq)EXCEPTSELECT d.id_disciplina, d.nome_disciplinaFROM disciplina dWHERE d.id_disciplina IN (SELECTDISTINCT id_disciplina FROM matricula_disciplina)ORDERBY id_disciplina;
6 records
id_disciplina
nome_disciplina
1110601
Economia Brasileira
1110602
Orçamento e Finanças Públicas
1110801
Monografia
2110801
Tecnologia Educacional - Design
3110801
Bases da Eng. de Software 8
3110802
Projeto Aplicado 8 - Sistema em Tempo Real
-- INTERSECT: disciplinas que têm pré-requisito E foram cursadas por algum alunoSELECT id_disciplina FROM prereqINTERSECTSELECTDISTINCT id_disciplina FROM matricula_disciplinaORDERBY id_disciplina;
7 records
id_disciplina
1110401
2110401
2110601
3110401
3110402
3110601
3110602
-- UNION ALL vs UNION: efeito das duplicatas-- UNION ALL conta todas as ocorrências; UNION apenas valores distintosSELECT'UNION (sem dup.)'AS operacao, COUNT(*) AS n_linhasFROM (SELECT id_curso FROM cursoUNIONSELECT id_curso FROM disciplina) tUNIONALLSELECT'UNION ALL (com dup.)', COUNT(*)FROM (SELECT id_curso FROM cursoUNIONALLSELECT id_curso FROM disciplina) t;