sqlpostgresqlunionmysql

UNION e UNION ALL no SQL: combinando resultados de consultas

Como UNION e UNION ALL se diferenciam, quais regras de compatibilidade de colunas seguir e como ordenar o resultado combinado.

2 min de leituraReferencesql · postgresql · union · mysql · clickhouse

UNION e UNION ALL empilham verticalmente os resultados de dois ou mais SELECT: as linhas de uma consulta sao anexadas abaixo das de outra. A diferenca e uma unica palavra-chave, mas e ela que define tanto a correcao quanto o desempenho.

UNION versus UNION ALL

UNION ALL simplesmente concatena os conjuntos de linhas e nao verifica nada quanto a repeticoes. UNION ainda remove duplicatas e, para encontra-las, o motor precisa ordenar ou aplicar hash em todo o resultado.

-- Keeps every row, including duplicates. Fast.
SELECT country FROM users
UNION ALL
SELECT country FROM users;

-- Collapses identical rows into one. Extra dedup pass.
SELECT country FROM users
UNION
SELECT country FROM users;

Regra pratica: se voce ja sabe que as entradas nao se sobrepoem (por exemplo, ao empilhar pedidos de meses diferentes), use UNION ALL. A deduplicacao extra sobre milhoes de linhas custa segundos reais de CPU e memoria para a ordenacao.

  • UNION ALL — sem deduplicacao, a ordem das linhas nao e garantida, mas costuma ser mais barato.
  • UNION — deduplica sobre todo o conjunto de colunas, nao apenas a primeira.
  • Uma duplicata e uma linha que coincide por inteiro; aqui NULL e igual a NULL (ao contrario da comparacao normal).

Regras de compatibilidade de colunas

So da para combinar consultas com o mesmo numero de colunas e tipos compativeis. Os nomes das colunas vem do primeiro SELECT; os demais sao ignorados.

-- OK: same arity, compatible types
SELECT id, email FROM users
UNION ALL
SELECT user_id, status FROM orders;

-- Fails: 2 columns vs 3 columns
SELECT id, email FROM users
UNION ALL
SELECT id, user_id, amount FROM orders;

Se os tipos diferem, alinhe-os de forma explicita com CAST em vez de confiar na conversao implicita. Para que uma pilha heterogenea faca sentido, adicione uma coluna de origem:

SELECT id, name, CAST(NULL AS numeric) AS amount, 'user' AS source
FROM users
UNION ALL
SELECT id, CAST(NULL AS text), amount, 'order'
FROM orders;

ORDER BY e LIMIT sobre a uniao

ORDER BY se aplica a todo o resultado e e escrito uma unica vez, bem no fim. Ordenar ramos individuais nao adianta: o UNION pode reorganizar as linhas de qualquer forma.

SELECT id, name, salary FROM employees WHERE dept = 'eng'
UNION ALL
SELECT id, name, salary FROM employees WHERE dept = 'sales'
ORDER BY salary DESC
LIMIT 10;

Se precisar ordenar ou limitar um ramo especifico, envolva-o em parenteses e uma subconsulta:

SELECT * FROM (
  SELECT id, amount FROM orders WHERE status = 'paid'
  ORDER BY amount DESC LIMIT 5
) AS top_paid
UNION ALL
SELECT id, amount FROM orders WHERE status = 'refunded';

Pegadinha: o ORDER BY final ordena por posicao da coluna ou pelo nome do primeiro SELECT. Se os ramos nomeiam as colunas de forma diferente, use o nome do primeiro ramo ou o numero da posicao (ORDER BY 3).

Diferencas entre motores

  • PostgreSQL — verificacao estrita de tipos; UNION usa um Sort ou Hash Aggregate, visivel no EXPLAIN.
  • MySQL — permite mais conversoes implicitas e as vezes trunca valores em silencio; coloque o ORDER BY/LIMIT de um ramo em uma subconsulta ou ele sera ignorado.
  • ClickHouse — por padrao o UNION sem ALL pode exigir configuracao explicita; aqui quase sempre se escreve UNION ALL e a deduplicacao e feita com DISTINCT ou agregados.

Resumindo: UNION ALL e a escolha padrao pela velocidade, e voce recorre ao UNION de forma deliberada, so quando as repeticoes realmente precisam ser colapsadas.

Pratique com exercícios reais

Resolva exercícios no treinador de SQL com correção instantânea e dicas.

Abrir o treinador