SQL UNION
A Ana quer saber em quais cidades a Loja Aurora tem alguém: um cliente ou um fornecedor. Os clientes estão numa tabela, os fornecedores em outra. Ela poderia rodar duas consultas e juntar as listas à mão, riscando as cidades repetidas. O UNION (em inglês, "união") faz isso por ela: empilha o resultado de duas consultas numa lista só e tira as linhas repetidas.
- O que o
UNIONfaz e como ele é diferente de umJOIN. - As regras: o mesmo número de colunas, na mesma ordem, e os nomes vindos do primeiro
SELECT. - Por que o
UNIONtira as repetições, até as de dentro de uma mesma consulta. - Onde vai o
ORDER BY(só no fim) e oLIMIT. - Como marcar de onde veio cada linha com uma coluna de "origem".
- Quando um
ORresolve e quando só oUNIONresolve. - Os erros reais do SQLite: colunas a mais,
ORDER BYno meio, parênteses.
Todos os exemplos rodam de verdade no seu navegador, no banco da Loja Aurora (veja O Banco da Loja Aurora).
A ideia: duas listas de convidados
A Ana e o irmão vão dar uma festa e cada um fez a sua lista de convidados. Para mandar os convites, ela põe uma folha embaixo da outra e passa a limpo, escrevendo cada nome uma vez só: quem estava nas duas listas não ganha dois convites. Isso é o UNION.
Repare na diferença para o JOIN, que você viu nas aulas anteriores:
| JOIN | UNION | |
|---|---|---|
| O que junta | Tabelas, lado a lado | Resultados de consultas, um embaixo do outro |
| O resultado ganha | Mais colunas | Mais linhas |
| Precisa de | Uma regra de ligação (ON) | O mesmo número de colunas nas duas consultas |
| Na festa | Pôr ao lado de cada convidado o telefone dele | Juntar as duas listas de convidados numa só |
1. As duas listas
Primeiro, cada lista sozinha. As cidades dos clientes, sem repetir (aula SELECT DISTINCT):
SELECT DISTINCT cidade FROM clientes;
E as cidades dos fornecedores:
SELECT cidade FROM fornecedores;
São 8 cidades de clientes e 6 linhas de fornecedores, com Teresina duas vezes (a loja tem dois fornecedores lá). Algumas cidades estão nas duas listas: Teresina, Fortaleza e São Paulo.
2. O primeiro UNION
Agora as duas listas numa só:
SELECT cidade FROM clientes UNION SELECT cidade FROM fornecedores;
- SELECT cidade FROM clientes
- A primeira consulta: uma consulta completa, que funcionaria sozinha.
- UNION
- "Junte com o resultado da próxima consulta e tire as linhas repetidas." Ele fica entre as duas consultas, sem ponto e vírgula antes: é tudo um comando só.
- SELECT cidade FROM fornecedores
- A segunda consulta, também completa. O
;vem só no fim de tudo.
O resultado tem 10 cidades. Faça a conta: 8 de clientes + 6 de fornecedores = 14 linhas, menos as repetidas. Teresina, Fortaleza e São Paulo, que estavam nas duas listas, aparecem uma vez só, e o Teresina repetido dos fornecedores também sumiu. As duas cidades novas vêm dos fornecedores estrangeiros: Porto e Buenos Aires.
Aqui as cidades saíram em ordem alfabética, mas isso foi efeito do jeito como o SQLite tirou as repetições, e não uma promessa. Sem ORDER BY, nenhum banco garante a ordem. Quer em ordem? Peça (seção 4).
3. As regras das colunas
O UNION empilha linhas, então as linhas das duas consultas precisam "encaixar" uma embaixo da outra:
- O mesmo número de colunas. Se a primeira consulta tem 2 colunas, a segunda também tem de ter 2. Senão o SQLite recusa (veja Quando dá errado).
- Na mesma ordem. A 1ª coluna de uma vai embaixo da 1ª coluna da outra, a 2ª embaixo da 2ª. O banco não olha os nomes, só a posição.
- Os nomes vêm da primeira consulta. O cabeçalho do resultado é o da primeira consulta; os nomes (e os
AS) das outras são ignorados.
Um exemplo com duas colunas. A Ana quer a lista de contatos de Teresina: clientes e fornecedores. Para saber quem é quem, ela cria uma coluna com um texto fixo:
SELECT nome, 'cliente' AS tipo FROM clientes WHERE cidade = 'Teresina' UNION SELECT nome, 'fornecedor' FROM fornecedores WHERE cidade = 'Teresina' ORDER BY nome;
- 'cliente' AS tipo
- Um texto fixo, que se repete em toda linha dessa consulta. Ele vira a 2ª coluna, com o nome
tipo. - 'fornecedor'
- A 2ª coluna da segunda consulta. Não precisa de
AS: o nometipojá veio da primeira. - WHERE … em cada parte
- Cada consulta tem o seu próprio
WHERE. O primeiro filtra os clientes; o segundo, os fornecedores. - ORDER BY nome
- Ordena a lista inteira, já unida. Ele vem uma vez só, no fim.
São 10 clientes de Teresina e 2 fornecedores, 12 contatos misturados em ordem alfabética. Essa coluna de "origem" com texto fixo é um truque muito usado com UNION, porque sem ela não dá para saber de qual tabela veio cada linha.
4. ORDER BY e LIMIT: só no fim
O ORDER BY e o LIMIT valem para o resultado já unido, por isso só podem aparecer uma vez, depois da última consulta. Você pode ordenar pelo nome da coluna (o nome da primeira consulta) ou pelo número da posição:
SELECT nome FROM funcionarios UNION SELECT nome FROM fornecedores ORDER BY 1 LIMIT 3;
ORDER BY 1 quer dizer "pela 1ª coluna". O LIMIT 3 (aula LIMIT e OFFSET) pegou as 3 primeiras da lista toda, e não 3 de cada tabela: funcionários e fornecedores estão misturados.
Missão: a Ana quer uma lista só com os nomes de todos os funcionários e de todos os fornecedores, em ordem alfabética. Hoje a consulta só tem os funcionários. Acrescente os fornecedores com UNION e mantenha a ordem alfabética da lista inteira.
SELECT nome FROM funcionarios ORDER BY nome;
SELECT nome FROM funcionarios UNION SELECT nome FROM fornecedores ORDER BY nome;
5. O UNION tira toda repetição
O UNION não tira só o que se repete entre as consultas. Ele tira qualquer linha igual a outra no resultado final, mesmo que as duas tenham vindo da mesma consulta. Veja o caso extremo, a mesma tabela duas vezes:
SELECT cidade FROM clientes UNION SELECT cidade FROM clientes;
Saíram as 8 cidades, sem repetição, igual ao SELECT DISTINCT cidade FROM clientes da seção 1. Os 30 clientes, duas vezes, viraram 8 linhas.
"Linha repetida" quer dizer todas as colunas iguais. Na lista de contatos de Teresina, se existisse um fornecedor chamado "Tiago Fontes", ele não seria repetição do cliente Tiago Fontes, porque a coluna tipo é diferente (fornecedor × cliente).
Às vezes você quer as repetições: para contar, por exemplo. Para isso existe o UNION ALL, que empilha tudo sem tirar nada. Ele tem aula própria, a próxima: UNION ALL.
6. Três consultas ou mais
Dá para encadear quantos UNION você quiser. Aqui, uma lista com três origens diferentes: os clientes de Recife, os fornecedores estrangeiros e a funcionária que não tem chefe (a gerente):
SELECT nome, 'cliente' AS origem FROM clientes WHERE cidade = 'Recife' UNION SELECT nome, 'fornecedor' FROM fornecedores WHERE pais <> 'Brasil' UNION SELECT nome, 'funcionária' FROM funcionarios WHERE chefe_id IS NULL ORDER BY origem, nome;
Três tabelas diferentes, uma lista só, ordenada primeiro pela origem e depois pelo nome. As três consultas têm 2 colunas cada uma, e o ORDER BY continua uma vez só, no fim.
7. UNION × OR
Quando as duas listas vêm da mesma tabela, um OR (aula OR) costuma dar o mesmo resultado. Os clientes de Pernambuco ou VIP, dos dois jeitos:
SELECT nome FROM clientes WHERE estado = 'PE' UNION SELECT nome FROM clientes WHERE vip = 1;
SELECT nome FROM clientes WHERE estado = 'PE' OR vip = 1;
Os mesmos 7 clientes, em ordem diferente. Com uma tabela só, o OR é mais simples e o banco lê a tabela uma vez. Mas o OR não sabe juntar duas tabelas diferentes numa lista; aí só o UNION resolve.
| Você quer… | Use |
|---|---|
| Linhas da mesma tabela que atendem a uma condição ou a outra | WHERE … OR … (ou IN) |
| Uma lista só com linhas de tabelas diferentes, sem repetição | UNION |
| A mesma coisa, mas mantendo as repetições (para contar, somar) | UNION ALL |
| Colunas de outra tabela ao lado de cada linha | JOIN, não UNION |
O SQL tem mais dois operadores que juntam consultas do mesmo jeito. INTERSECT ("interseção") mostra só o que está nas duas listas; EXCEPT ("exceto") mostra o que está na primeira e não está na segunda. As mesmas regras de colunas valem para eles.
SELECT cidade FROM clientes INTERSECT SELECT cidade FROM fornecedores;
Teresina, Fortaleza e São Paulo: as cidades que têm cliente e fornecedor. E as cidades que só têm fornecedor:
SELECT cidade FROM fornecedores EXCEPT SELECT cidade FROM clientes;
Quando dá errado
A primeira consulta tem 2 colunas e a segunda, 1:
SELECT nome, cidade FROM clientes UNION SELECT nome FROM fornecedores;
A mensagem: SELECTs to the left and right of UNION do not have the same number of result columns, "os SELECTs à esquerda e à direita do UNION não têm o mesmo número de colunas no resultado". É o erro mais comum com UNION. No terminal do sqlite3, a mesma mensagem vem com um prefixo:
$ sqlite3 loja.db SQLite version 3.50.4 2025-07-30 19:33:53 Enter ".help" for usage hints. sqlite> SELECT nome, cidade FROM clientes UNION SELECT nome FROM fornecedores; Parse error: SELECTs to the left and right of UNION do not have the same number of result columns
Como consertar: conte as colunas de cada consulta e deixe iguais: acrescente a coluna que falta (SELECT nome, cidade FROM fornecedores) ou tire a que sobra.
ORDER BY no meio
SELECT nome FROM clientes ORDER BY nome UNION SELECT nome FROM fornecedores;
A mensagem: ORDER BY clause should come after UNION not before, "a cláusula ORDER BY deve vir depois do UNION, não antes". O SQLite até explica o que fazer.
Como consertar: mova o ORDER BY para depois da última consulta. Ele vai ordenar a lista inteira, que é quase sempre o que você queria.
SELECT cidade FROM clientes UNION SELECT cidade FROM fornecedores ORDER BY nome;
A mensagem: 1st ORDER BY term does not match any column in the result set, "o 1º termo do ORDER BY não corresponde a nenhuma coluna do resultado". Numa consulta simples, você pode ordenar por uma coluna que não mostra; com UNION, não: o ORDER BY só enxerga as colunas do resultado unido.
Como consertar: ordene por uma coluna que está no SELECT (ORDER BY cidade) ou pela posição (ORDER BY 1).
(SELECT nome FROM funcionarios) UNION (SELECT nome FROM fornecedores);
A mensagem: near "(": syntax error, "erro de sintaxe perto de (". Em outros bancos essa escrita é aceita (veja a nota abaixo), por isso ela aparece em muito tutorial; o SQLite não aceita.
Como consertar: tire os parênteses. Se você queria um ORDER BY ou LIMIT só numa das partes, ponha essa parte como subconsulta no FROM:
SELECT nome FROM (SELECT nome FROM funcionarios ORDER BY salario DESC LIMIT 2) UNION SELECT nome FROM fornecedores WHERE pais <> 'Brasil';
Os 2 funcionários de maior salário (Marta e Luana) e os 2 fornecedores estrangeiros. Subconsultas têm aula própria: Subconsultas.
SELECT nome, cidade FROM clientes WHERE cidade = 'Recife' UNION SELECT cidade, nome FROM fornecedores WHERE pais <> 'Brasil';
O que acontece: nenhum erro, mas "Buenos Aires" e "Porto" foram parar na coluna nome, e os nomes dos fornecedores na coluna cidade. O UNION encaixa por posição, não por nome. E o SQLite não confere se o tipo combina: ele aceita até empilhar um número embaixo de um texto.
Como consertar: escreva as colunas na mesma ordem em todas as consultas: SELECT nome, cidade FROM fornecedores.
No MySQL, no PostgreSQL e no SQL Server o UNION funciona do mesmo jeito: mesmo número de colunas, repetições removidas, nomes vindos da primeira consulta e ORDER BY no fim. Duas diferenças:
- Tipos. O PostgreSQL e o SQL Server exigem que as colunas de mesma posição tenham tipos compatíveis; o SQLite não confere.
- Parênteses. O MySQL e o PostgreSQL aceitam cada consulta entre parênteses, e é assim que eles põem um
ORDER BYouLIMITnuma parte só. Este trecho é ilustrativo (não roda no SQLite):
(SELECT nome FROM funcionarios ORDER BY salario DESC LIMIT 2) UNION (SELECT nome FROM fornecedores WHERE pais <> 'Brasil');
Referência rápida
| Escrita | O que faz |
|---|---|
SELECT … UNION SELECT … | Empilha os dois resultados e tira as linhas repetidas |
SELECT … UNION SELECT … UNION SELECT … | Três ou mais consultas numa lista só |
'cliente' AS origem | Coluna de texto fixo para saber de onde veio cada linha |
… ORDER BY nome / ORDER BY 1 | Ordena a lista inteira; só no fim, uma vez |
… LIMIT 3 | Limita a lista inteira; só no fim |
UNION ALL | Empilha sem tirar repetições (próxima aula) |
INTERSECT / EXCEPT | O que está nas duas listas / o que está só na primeira |
| Mensagem do SQLite | Quer dizer |
|---|---|
SELECTs to the left and right of UNION do not have the same number of result columns | As consultas têm números de colunas diferentes |
ORDER BY clause should come after UNION not before | O ORDER BY está no meio; mova para o fim |
1st ORDER BY term does not match any column in the result set | O ORDER BY usa uma coluna que não está no resultado |
near "(": syntax error | Parênteses em volta das consultas: o SQLite não aceita |
Exercícios
1. A palavra que junta
Complete para empilhar os nomes dos clientes e dos fornecedores, sem repetição:
2. Contando colunas
A primeira consulta é SELECT nome, cidade, estado FROM clientes. Quantas colunas a segunda consulta do UNION precisa ter?
3. Onde vai o ORDER BY num UNION?
4. Os clientes estão em 8 cidades e os fornecedores em 5 cidades diferentes; 3 cidades aparecem nas duas listas. Quantas linhas saem do SELECT cidade FROM clientes UNION SELECT cidade FROM fornecedores?
5. De onde vêm os nomes das colunas do resultado de um UNION?
6. A Ana quer, numa lista só, os clientes VIP e os funcionários. O que ela deve usar?
Missão final: os contatos de Fortaleza
Missão: a Ana vai visitar Fortaleza e quer a lista de todos os contatos de lá: os clientes e os fornecedores, com a coluna origem dizendo quem é quem, tudo em ordem alfabética de nome. A consulta abaixo só traz os clientes. Complete-a.
SELECT nome, 'cliente' AS origem FROM clientes WHERE cidade = 'Fortaleza' ORDER BY nome;
SELECT nome, 'cliente' AS origem FROM clientes WHERE cidade = 'Fortaleza' UNION SELECT nome, 'fornecedor' FROM fornecedores WHERE cidade = 'Fortaleza' ORDER BY nome;
Resumo
UNIONempilha o resultado de duas ou mais consultas numa lista só e tira as linhas repetidas (todas as colunas iguais), até as de dentro de uma mesma consulta.JOINacrescenta colunas;UNIONacrescenta linhas.- Todas as consultas precisam do mesmo número de colunas, na mesma ordem. O encaixe é pela posição; os nomes vêm da primeira consulta.
ORDER BYeLIMITvêm uma vez só, no fim, e valem para a lista inteira.- Uma coluna de texto fixo (
'cliente' AS origem) mostra de onde veio cada linha. - Na mesma tabela, um
ORcostuma bastar; para juntar tabelas diferentes, useUNION. Para manter as repetições, UNION ALL.