Pular para o conteúdo principal

Questão de Banco de Dados — Geral — FGV 2026

Banco de DadosGeral
Código
fg157150
Banca
FGV
Órgão
PC PI
Ano
2026
Cargo
Per OC ( )
Considere a versão simplificada de um banco de dados utilizado por uma delegacia, conforme descrito a seguir, especificado em SQL ANSI:   create table cad_suspeito  -- Cadastro de suspeitos (     id                    integer            primary key,     cpf                 char(11)          unique,     nome            varchar(50)   not null,     endereco     varchar(100),     dt_nasc        date                  not null   );   create table cad_crime     -- Cadastro de crimes   (     id                       integer              primary key,     descricao       varchar(50)     unique,     tipo                   varchar(20) );   create table cad_ocorrencia -- Cadastro de ocorrências (       id_crime          integer         references cad_crime(id),     id_suspeito     integer         references cad_suspeito,     data_ocorrencia date,     primary key(id_crime,id_suspeito)   );   Um investigador, conhecedor da linguagem SQL, acessou o módulo de processamento de consultas do sistema gerenciador de banco de dados relacional utilizado pelo sistema, e especificou a seguinte consulta em SQL ANSI:   select cpf, nome from cad_suspeito s where not exists (   select id from cad_crime     except     select id_crime from cad_ocorrencia o     where o.id_suspeito = s.id );   A consulta apresentada revela o número do CPF e nome de suspeitos associados a
  1. Acrimes sem ocorrência.
  2. Bnenhum crime.
  3. Cocorrências sem crime.
  4. Dtodos os crimes cadastrados.
  5. Euma ocorrência apenas.
Revelar gabarito e comentário

GabaritoD — todos os crimes cadastrados.

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”.

Consulta SQL com NOT EXISTS e EXCEPT: Divisão Relacional

Gabarito: letra D. A consulta retorna suspeitos associados a todos os crimes cadastrados — é a implementação clássica da operação de divisão relacional da álgebra relacional, que responde a perguntas com quantificador universal ("para todo"). O NOT EXISTS combinado com EXCEPT verifica se o conjunto de todos os crimes menos os crimes do suspeito é vazio, ou seja, se o suspeito tem ocorrência para cada crime existente.

A consulta usa três conceitos centrais de SQL que precisam ser dominados juntos: a subconsulta correlacionada (referencia s.id de fora), o operador EXCEPT (diferença de conjuntos) e o NOT EXISTS (negação da existência). Vamos destrinchar cada um para entender por que a resposta é a letra D e não as demais.

O que é a divisão relacional? Na álgebra relacional, a divisão (÷) responde a perguntas do tipo "quais X estão associados a TODOS os Y?". Por exemplo: "quais suspeitos cometeram todos os crimes cadastrados?" ou "quais alunos cursaram todas as disciplinas?". Não há um comando SQL direto para divisão — ela é implementada com combinações de NOT EXISTS, EXCEPT ou NOT IN com subconsultas correlacionadas. A consulta da questão é exatamente esse padrão.

Como a consulta funciona passo a passo:

  1. Para cada suspeito s (linha a linha, por ser correlacionada), executa-se a subconsulta interna.

  2. A subconsulta select id from cad_crime except select id_crime from cad_ocorrencia o where o.id_suspeito = s.id calcula: todos os crimes (primeiro bloco) menos os crimes que o suspeito s tem ocorrência (segundo bloco). O resultado é o conjunto de crimes que o suspeito NÃO possui ocorrência.

  3. O NOT EXISTS pergunta: esse conjunto é vazio? Se for vazio, significa que não existe nenhum crime sem ocorrência para o suspeito — ou seja, o suspeito tem ocorrência para todos os crimes.

  4. Se o conjunto for vazio, o suspeito entra no resultado final (cpf e nome).

Exemplo concreto: Suponha 3 crimes cadastrados (C1, C2, C3) e 2 suspeitos:

  • Suspeito A tem ocorrência para C1 e C2, mas não para C3. Subconsulta: {C1,C2,C3} − {C1,C2} = {C3} → não vazio → NOT EXISTS falso → A não entra.

  • Suspeito B tem ocorrência para C1, C2 e C3. Subconsulta: {C1,C2,C3} − {C1,C2,C3} = {} → vazio → NOT EXISTS verdadeiro → B entra.

Portanto, apenas suspeitos com ocorrência em todos os crimes são retornados.

A pegadinha da banca: a alternativa B ("nenhum crime") é a mais tentadora para quem lê NOT EXISTS apressadamente e pensa que é o oposto de EXISTS. Mas NOT EXISTS aqui não nega a existência de ocorrências — nega a existência de crimes sem ocorrência. A alternativa A ("crimes sem ocorrência") inverte o sujeito: a consulta retorna suspeitos, não crimes. A alternativa C ("ocorrências sem crime") é impossível pela modelagem, pois id_crime é chave estrangeira para cad_crime. A alternativa E ("uma ocorrência apenas") confunde com uma contagem, que não existe na consulta.

Guarde o padrão: NOT EXISTS (SELECT ... EXCEPT SELECT ...) = divisão = "todos". É exatamente esse critério que separa as alternativas.

Alternativa A — ❌ Incorreta

"Crimes sem ocorrência" inverte o resultado: a consulta retorna suspeitos (cpf, nome), não crimes. Além disso, o NOT EXISTS exige que o conjunto de crimes sem ocorrência seja vazio — ou seja, o oposto de listar crimes sem ocorrência. Se a consulta quisesse crimes sem ocorrência, seria algo como select id from cad_crime where id not in (select id_crime from cad_ocorrencia) — sem a correlação com o suspeito e sem o NOT EXISTS.

Alternativa B — ❌ Incorreta

"Nenhum crime" é a pegadinha clássica. O NOT EXISTS não significa "não tem ocorrência"; significa "não existe crime sem ocorrência". Um suspeito sem nenhuma ocorrência teria a subconsulta {todos os crimes} − {} = {todos os crimes}, que não é vazio (a menos que não haja crimes cadastrados), então NOT EXISTS seria falso e o suspeito não entraria. A consulta retorna justamente o oposto: suspeitos com ocorrência em todos os crimes.

Alternativa C — ❌ Incorreta

"Ocorrências sem crime" é impossível pela modelagem: a tabela cad_ocorrencia tem id_crime como chave estrangeira referenciando cad_crime(id). A restrição de integridade referencial garante que toda ocorrência aponta para um crime existente. Além disso, a consulta retorna suspeitos, não ocorrências.

Alternativa D — ✅ Correta ⟵ GABARITO

A consulta implementa a divisão relacional: retorna suspeitos que possuem ocorrência para todos os crimes cadastrados. O EXCEPT calcula os crimes que o suspeito não tem; o NOT EXISTS verifica se esse conjunto é vazio. Se for, o suspeito tem todos os crimes — exatamente o que a alternativa afirma.

Alternativa E — ❌ Incorreta

"Uma ocorrência apenas" não corresponde à lógica da consulta. Não há nenhuma contagem (COUNT) ou restrição a uma única ocorrência. A consulta exige que o suspeito tenha ocorrência para todos os crimes, não apenas um. Um suspeito com uma única ocorrência teria a subconsulta {todos os crimes} − {1 crime} = não vazio → não entraria no resultado.

NÃO CAIA NESSA!

A banca explora a leitura apressada do NOT EXISTS. Muitos candidatos leem "não existe" e marcam "nenhum crime" (letra B), mas o NOT EXISTS aqui nega a existência de crimes sem ocorrência — o que equivale a "tem todos". O EXCEPT é o operador de diferença: ele subtrai os crimes do suspeito do total de crimes. Se sobrar algo, falta crime; se não sobrar nada, tem todos. Treine identificar o padrão NOT EXISTS (SELECT ... EXCEPT SELECT ...) como divisão relacional — é o mesmo que "para todo".

PEGA ESSA DICA!

Para questões de SQL com NOT EXISTS + EXCEPT (ou NOT IN), traduza mentalmente para a pergunta com quantificador universal: "para todo crime, existe ocorrência?". Monte um mini-exemplo com 2-3 crimes e 1-2 suspeitos no papel e execute a consulta manualmente — isso desfaz qualquer ambiguidade. Na prova, desconfie de alternativas que invertem o sujeito (crimes × suspeitos) ou que usam "nenhum" quando a lógica é "todos".

Gabarito: letra D

Link permanente: /questoes/fg157150