O operador INTERSECT retorna apenas as linhas que aparecem no resultado das duas consultas ao mesmo tempo. E a forma mais direta de responder "quem esta nos dois conjuntos" sem montar um join na mao, e e um dos tres operadores de conjuntos do SQL ao lado de UNION e EXCEPT.
Sintaxe basica
INTERSECT fica entre duas instrucoes SELECT e compara linhas inteiras, coluna a coluna. As duas consultas precisam retornar o mesmo numero de colunas com tipos compativeis.
SELECT user_id FROM purchases
INTERSECT
SELECT user_id FROM refunds;
O resultado e um conjunto ordenado de valores user_id unicos presentes em cada entrada. Um exemplo concreto sobre o nosso esquema: paises que tem ao mesmo tempo usuarios cadastrados e pedidos pagos.
SELECT country FROM users
INTERSECT
SELECT u.country
FROM users u
JOIN orders o ON o.user_id = u.id
WHERE o.status = 'paid';
Propriedades principais do operador:
- Todas as colunas sao comparadas, e
NULL e tratado como igual a NULL (ao contrario de um = comum).
- As duplicatas sao removidas por padrao, assim como em
DISTINCT.
- A ordem das colunas importa: a primeira casa com a primeira, a segunda com a segunda.
INTERSECT versus INTERSECT ALL
Por padrao o INTERSECT remove duplicatas. Quando voce precisa de uma linha repetida tantas vezes quanto ela aparece nas duas entradas, use INTERSECT ALL: ele mantem o numero minimo de ocorrencias de cada lado.
SELECT user_id FROM orders WHERE amount > 100
INTERSECT
SELECT user_id FROM orders WHERE status = 'paid';
SELECT user_id FROM orders WHERE amount > 100
INTERSECT ALL
SELECT user_id FROM orders WHERE status = 'paid';
Se user_id = 7 aparece 3 vezes a esquerda e 2 a direita, o INTERSECT ALL o retorna duas vezes, enquanto o INTERSECT simples o retorna apenas uma vez. Na pratica a forma sem ALL e a mais usada: normalmente importa se uma linha pertence aos dois conjuntos, nao quantas copias existem. E nao trate o INTERSECT ALL como "de graca": ele ainda precisa casar as linhas e contar as ocorrencias de cada lado para manter min(count_left, count_right) copias. A unica economia frente ao INTERSECT simples e que a deduplicacao final e dispensada; o casamento e a contagem continuam acontecendo.
Pegadinha: no PostgreSQL o INTERSECT tem prioridade maior que UNION e EXCEPT. Numa cadeia como A UNION B INTERSECT C, o motor avalia primeiro B INTERSECT C. Use parenteses explicitos para nunca precisar adivinhar.
INTERSECT versus JOIN e EXISTS
A mesma "pertinencia comum" pode ser expressa com um INNER JOIN ou com EXISTS, mas a semantica difere nos detalhes.
SELECT DISTINCT a.user_id
FROM orders a
JOIN refunds b ON a.user_id = b.user_id;
SELECT DISTINCT o.user_id
FROM orders o
WHERE EXISTS (
SELECT 1 FROM refunds r WHERE r.user_id = o.user_id
);
Como escolher:
INTERSECT quando voce compara conjuntos de linhas inteiros e quer deduplicacao automatica.
EXISTS quando precisa de colunas extras da tabela principal que a segunda consulta nao expoe.
INNER JOIN quando precisa de dados das duas tabelas, mas atencao a multiplicacao de linhas e recorra ao DISTINCT.
O tratamento de NULL e a diferenca principal: o INTERSECT considera NULL igual a NULL e casa essas linhas, enquanto um join sobre a.user_id = b.user_id descarta as linhas cuja chave e NULL. O INTERSECT brilha quando os dois conjuntos vem de expressoes complexas: em vez de uma subconsulta desajeitada no WHERE, voce escreve dois blocos SELECT legiveis.
Suporte por banco
O INTERSECT esta disponivel ha muito tempo em PostgreSQL, Oracle, SQL Server e SQLite. No MySQL o operador so chegou na versao 8.0.31 — versoes anteriores o emulavam com um INNER JOIN mais DISTINCT, ou com IN.
SELECT DISTINCT user_id FROM purchases
WHERE user_id IN (SELECT user_id FROM refunds);
No ClickHouse, o INTERSECT e suportado, e se ele deduplica ou mantem as duplicatas e governado pelo ajuste intersect_default_mode, nao e algo fixo. Para nao depender desse ajuste, escreva INTERSECT DISTINCT para a semantica classica de conjuntos ou INTERSECT ALL quando quiser preservar a multiplicidade.
Resumo rapido:
INTERSECT — intersecao de conjuntos com remocao de duplicatas.
INTERSECT ALL — intersecao que respeita a multiplicidade: min(count_left, count_right) copias de cada linha.
- Disponivel no MySQL desde 8.0.31; no ClickHouse o comportamento padrao e controlado por
intersect_default_mode, entao escreva DISTINCT ou ALL de forma explicita.
O INTERSECT torna as consultas de "pertinencia comum" declarativas e legiveis — use-o ao comparar conjuntos inteiros de linhas, e reserve EXISTS/JOIN para os casos em que precisa de colunas adicionais.
O operador
INTERSECTretorna apenas as linhas que aparecem no resultado das duas consultas ao mesmo tempo. E a forma mais direta de responder "quem esta nos dois conjuntos" sem montar um join na mao, e e um dos tres operadores de conjuntos do SQL ao lado deUNIONeEXCEPT.Sintaxe basica
INTERSECTfica entre duas instrucoesSELECTe compara linhas inteiras, coluna a coluna. As duas consultas precisam retornar o mesmo numero de colunas com tipos compativeis.-- Users who both placed an order and requested a refund SELECT user_id FROM purchases INTERSECT SELECT user_id FROM refunds;O resultado e um conjunto ordenado de valores
user_idunicos presentes em cada entrada. Um exemplo concreto sobre o nosso esquema: paises que tem ao mesmo tempo usuarios cadastrados e pedidos pagos.SELECT country FROM users INTERSECT SELECT u.country FROM users u JOIN orders o ON o.user_id = u.id WHERE o.status = 'paid';Propriedades principais do operador:
NULLe tratado como igual aNULL(ao contrario de um=comum).DISTINCT.INTERSECT versus INTERSECT ALL
Por padrao o
INTERSECTremove duplicatas. Quando voce precisa de uma linha repetida tantas vezes quanto ela aparece nas duas entradas, useINTERSECT ALL: ele mantem o numero minimo de ocorrencias de cada lado.-- DISTINCT semantics: each matching id appears once SELECT user_id FROM orders WHERE amount > 100 INTERSECT SELECT user_id FROM orders WHERE status = 'paid'; -- Multiplicity preserved: min(count_left, count_right) copies SELECT user_id FROM orders WHERE amount > 100 INTERSECT ALL SELECT user_id FROM orders WHERE status = 'paid';Se
user_id = 7aparece 3 vezes a esquerda e 2 a direita, oINTERSECT ALLo retorna duas vezes, enquanto oINTERSECTsimples o retorna apenas uma vez. Na pratica a forma semALLe a mais usada: normalmente importa se uma linha pertence aos dois conjuntos, nao quantas copias existem. E nao trate oINTERSECT ALLcomo "de graca": ele ainda precisa casar as linhas e contar as ocorrencias de cada lado para mantermin(count_left, count_right)copias. A unica economia frente aoINTERSECTsimples e que a deduplicacao final e dispensada; o casamento e a contagem continuam acontecendo.INTERSECT versus JOIN e EXISTS
A mesma "pertinencia comum" pode ser expressa com um
INNER JOINou comEXISTS, mas a semantica difere nos detalhes.-- INNER JOIN can multiply rows if either side has duplicates SELECT DISTINCT a.user_id FROM orders a JOIN refunds b ON a.user_id = b.user_id; -- EXISTS: clean, no row multiplication, handles NULL via predicate SELECT DISTINCT o.user_id FROM orders o WHERE EXISTS ( SELECT 1 FROM refunds r WHERE r.user_id = o.user_id );Como escolher:
INTERSECTquando voce compara conjuntos de linhas inteiros e quer deduplicacao automatica.EXISTSquando precisa de colunas extras da tabela principal que a segunda consulta nao expoe.INNER JOINquando precisa de dados das duas tabelas, mas atencao a multiplicacao de linhas e recorra aoDISTINCT.O tratamento de
NULLe a diferenca principal: oINTERSECTconsideraNULLigual aNULLe casa essas linhas, enquanto um join sobrea.user_id = b.user_iddescarta as linhas cuja chave eNULL. OINTERSECTbrilha quando os dois conjuntos vem de expressoes complexas: em vez de uma subconsulta desajeitada noWHERE, voce escreve dois blocosSELECTlegiveis.Suporte por banco
O
INTERSECTesta disponivel ha muito tempo em PostgreSQL, Oracle, SQL Server e SQLite. No MySQL o operador so chegou na versao 8.0.31 — versoes anteriores o emulavam com umINNER JOINmaisDISTINCT, ou comIN.-- MySQL < 8.0.31 emulation of INTERSECT SELECT DISTINCT user_id FROM purchases WHERE user_id IN (SELECT user_id FROM refunds);No ClickHouse, o
INTERSECTe suportado, e se ele deduplica ou mantem as duplicatas e governado pelo ajusteintersect_default_mode, nao e algo fixo. Para nao depender desse ajuste, escrevaINTERSECT DISTINCTpara a semantica classica de conjuntos ouINTERSECT ALLquando quiser preservar a multiplicidade.Resumo rapido:
INTERSECT— intersecao de conjuntos com remocao de duplicatas.INTERSECT ALL— intersecao que respeita a multiplicidade:min(count_left, count_right)copias de cada linha.intersect_default_mode, entao escrevaDISTINCTouALLde forma explicita.O
INTERSECTtorna as consultas de "pertinencia comum" declarativas e legiveis — use-o ao comparar conjuntos inteiros de linhas, e reserveEXISTS/JOINpara os casos em que precisa de colunas adicionais.