Observe o script SQL do PostgreSQL a seguir. CREATE TABLE partes ( id INT PRIMARY KEY, nome VARCHAR(100)); CREATE TABLE processos ( id INT PRIMARY KEY, numero_processo VARCHAR(50)); CREATE TABLE audiencias ( id INT PRIMARY KEY, processo_id INT, FOREIGN KEY (processo_id) REFERENCES processos(id)); CREATE TABLE partes_processos ( processo_id INT, parte_id INT, PRIMARY KEY (processo_id, parte_id), FOREIGN KEY (processo_id) REFERENCES processos(id), FOREIGN KEY (parte_id) REFERENCES partes(id)); -- Partes INSERT INTO partes (id, nome) VALUES (1, 'João Silva'), (2, 'Maria Souza'); -- Processos INSERT INTO processos (id, numero_processo) VALUES (101, '0001234-56.2025.8.01.0001'), (102, '0001234-56.2025.8.01.0002'); -- Audiências INSERT INTO audiencias (id, processo_id) VALUES (201, 101); -- Partes_Processos INSERT INTO partes_processos (processo_id, parte_id) VALUES (101, 1), (102, 2); A consulta que retorna apenas os registros com Partes que ainda não possuem Audiências marcadas é:
ASELECT p.nome FROM audiencias a RIGHT JOIN partes_processos pp ON a.processo_id = pp.processo_id JOIN partes p ON pp.parte_id = p.id;
BSELECT p.nome FROM partes p JOIN partes_processos pp ON p.id = pp.parte_id LEFT JOIN audiencias a ON pp.processo_id = a.processo_id WHERE a.id IS NOT NULL;
CSELECT p.nome FROM partes p WHERE NOT EXISTS ( SELECT 1 FROM partes_processos pp JOIN audiencias a ON pp.processo_id = a.processo_id WHERE pp.parte_id = p.id );
DSELECT p.nome FROM partes p WHERE EXISTS ( SELECT 1 FROM partes_processos pp JOIN audiencias a ON pp.processo_id = a.processo_id WHERE pp.parte_id = p.id );
ESELECT p.nome FROM partes p JOIN partes_processos pp ON pp.parte_id = p.id WHERE EXISTS ( SELECT 1 FROM audiencias a WHERE a.processo_id = pp.processo_id );
Revelar gabarito e comentário▾
GabaritoC — SELECT p.nome
FROM partes p
WHERE NOT EXISTS (
SELECT 1
FROM partes_processos pp
JOIN audiencias a ON pp.processo_id = a.processo_id
WHERE pp.parte_id = p.id );
Comentário gerado por IA. É um apoio ao estudo, ancorado em fontes, mas pode conter imprecisões — confira sempre na fonte oficial (lei, súmula, edital e gabarito da banca). Encontrou um erro? Use “Reportar”.
SQL: Subconsultas correlacionadas e a busca por registros sem correspondência
Gabarito: letra C. A consulta correta usa NOT EXISTS com uma subconsulta correlacionada que verifica, para cada parte, se existe algum processo dela com audiência marcada — se não existir, a parte é retornada. As demais alternativas ou retornam partes que têm audiência (B, D, E) ou não filtram corretamente (A).
O problema pede para encontrar as partes que não possuem audiências marcadas. No banco de dados, uma parte se relaciona a processos pela tabela partes_processos, e um processo pode ter audiências na tabela audiencias. A relação é: parte → (partes_processos) → processo → (audiencias) → audiência. Precisamos, portanto, de uma consulta que retorne as partes para as quais não existe nenhum caminho que as ligue a uma audiência.
A ferramenta clássica para isso é o NOT EXISTS, que testa a não existência de registros que satisfaçam uma condição. A subconsulta correlacionada é aquela que referencia a consulta externa (no caso, p.id), permitindo avaliar a condição para cada linha da tabela partes. A alternativa C usa exatamente essa estrutura: para cada parte p, a subconsulta verifica se existe algum registro em partes_processos (com pp.parte_id = p.id) que esteja ligado a uma audiência (JOIN audiencias a ON pp.processo_id = a.processo_id). Se a subconsulta retornar nenhuma linha, o NOT EXISTS é verdadeiro e a parte é incluída no resultado.
Vamos testar com os dados fornecidos:
João Silva (id=1): está no processo 101, que tem audiência (201). A subconsulta encontra essa combinação, então NOT EXISTS é falso → João não é retornado.
Maria Souza (id=2): está no processo 102, que não tem audiência. A subconsulta não encontra nenhuma combinação, então NOT EXISTS é verdadeiro → Maria é retornada.
O resultado correto é apenas Maria Souza. As outras alternativas falham por diferentes motivos:
A: usa RIGHT JOIN entre audiencias e partes_processos, o que retorna todas as linhas de partes_processos (mesmo sem audiência), mas não filtra as que não têm audiência — retorna todas as partes, inclusive as que têm.
B: usa LEFT JOIN e filtra com WHERE a.id IS NOT NULL, o que retorna apenas as partes que têm audiência (o oposto do pedido).
D: usa EXISTS, que retorna as partes que têm audiência (o oposto do pedido).
E: usa EXISTS com subconsulta correlacionada, retornando as partes que têm audiência (o oposto do pedido).
A pegadinha central é a inversão entre EXISTS e NOT EXISTS. O EXISTS verifica se existe pelo menos um registro que satisfaz a condição; o NOT EXISTS verifica se não existe nenhum. A banca explora exatamente essa confusão, colocando alternativas com EXISTS (D e E) que retornam o conjunto complementar ao pedido.
1Parte → processos (partes_processos)
2Processo → audiências (audiencias)
3NOT EXISTS: sem nenhum caminho
4Retorna a parte
LEVEL · soulevel.com.br
Alternativa A — ❌ Incorreta
Esta consulta usa RIGHT JOIN entre audiencias e partes_processos. O RIGHT JOIN preserva todas as linhas da tabela da direita (partes_processos), mesmo que não haja correspondência em audiencias. No entanto, a consulta não filtra as linhas sem audiência — ela simplesmente retorna todas as partes, incluindo as que têm audiência. O resultado seria João Silva e Maria Souza, não apenas Maria. Para funcionar, seria necessário adicionar WHERE a.id IS NULL.
Alternativa B — ❌ Incorreta
Esta consulta usa LEFT JOIN entre partes_processos e audiencias, preservando todas as linhas de partes_processos. O filtro WHERE a.id IS NOT NULL seleciona apenas as linhas que têm audiência correspondente. Ou seja, retorna as partes que possuem audiências marcadas — exatamente o oposto do que a questão pede. O resultado seria apenas João Silva.
Alternativa C — ✅ Correta ⟵ GABARITO
Esta é a consulta correta. O NOT EXISTS com subconsulta correlacionada verifica, para cada parte p, se existe algum processo dela com audiência. A subconsulta junta partes_processos com audiencias pela chave processo_id e filtra pela parte atual (pp.parte_id = p.id). Se não houver nenhuma linha, a parte não tem audiência e é retornada. Com os dados do enunciado, apenas Maria Souza (id=2) é retornada.
Alternativa D — ❌ Incorreta
Esta consulta usa EXISTS em vez de NOT EXISTS. O EXISTS retorna verdadeiro se a subconsulta encontrar pelo menos uma linha. Portanto, retorna as partes que têm audiências marcadas — o oposto do pedido. O resultado seria apenas João Silva.
Alternativa E — ❌ Incorreta
Esta consulta também usa EXISTS, com uma subconsulta correlacionada que verifica se existe alguma audiência para o processo da parte. Como o EXISTS retorna verdadeiro quando há pelo menos uma audiência, a consulta retorna as partes que têm audiências — novamente o oposto do pedido. O resultado seria apenas João Silva.
NÃO CAIA NESSA!
A banca explora a inversão entre EXISTS e NOT EXISTS. O EXISTS verifica se existe um registro; o NOT EXISTS verifica se não existe. As alternativas D e E usam EXISTS, retornando as partes que têm audiência, enquanto a questão pede as que não têm. Identifique o que a questão pede (existência ou não existência) e escolha o operador correspondente.
PEGA ESSA DICA!
Para questões de "encontrar registros sem correspondência", use NOT EXISTS com subconsulta correlacionada. O padrão é: SELECT ... FROM tabela_principal p WHERE NOT EXISTS (SELECT 1 FROM tabela_relacionada r WHERE r.chave = p.chave). Essa estrutura é mais clara e evita erros com JOIN e filtros de NULL.