Pular para o conteúdo principal

Questão de Banco de Dados — Consultas e Comandos em SQL — CESPE / CEBRASPE 2024

Banco de DadosConsultas e Comandos em SQL
Código
ce403613
Banca
CESPE / CEBRASPE
Órgão
FINEP
Ano
2024
Cargo
Ana ( )

Na tabela SQL criada pela expressão a seguir, sessao corresponde a uma sessão e a variável duracao corresponde à duração da sessão de certo usuário.

 

create table sessao (
   id integer primary key,
   userid integer not null,
   duracao decimal not null
)

 

A partir dessas informações, assinale a opção que corresponde ao script utilizado para se obter o tempo médio de duração das sessões dos usuários que tenham mais de uma sessão.

  1. Aselect userid, avg(duracao) from sessao group by userid having count(*)>1
  2. Bselect id, userid, avg(duracao) from sessao where count(*)>1
  3. Cselect userid, avg(duracao) from sessao having count(id)>1
  4. Dselect id, userid, avg(duracao) from sessao where count(*)>1 group by id, userid
  5. Eselect id, avg(duracao) from sessao group by id having count(*)>1
Revelar gabarito e comentário

GabaritoA — select userid, avg(duracao) from sessao group by userid having count(*)>1

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 – GROUP BY, HAVING e funções de agregação

Gabarito: letra A. A consulta correta agrupa as sessões por userid, calcula a média da duração com avg(duracao) e filtra os grupos com mais de uma sessão usando having count(*)>1. A cláusula HAVING é a única que pode filtrar grupos após a agregação, enquanto WHERE não pode conter funções de agregação.

A questão cobra o entendimento de como montar uma consulta SQL que retorna a média de duração das sessões apenas para usuários que possuem mais de uma sessão. Para isso, é necessário usar a função de agregação AVG, que calcula a média de um conjunto de valores, e agrupar os registros por usuário com GROUP BY. O filtro sobre os grupos (usuários com mais de uma sessão) deve ser feito com HAVING, pois WHERE não pode ser usado com funções de agregação.

Vamos entender cada parte da consulta correta:

  1. SELECT userid, avg(duracao): seleciona o identificador do usuário e a média da duração das sessões. A função AVG calcula a média dos valores da coluna duracao para cada grupo.

  2. FROM sessao: indica a tabela de onde os dados serão lidos.

  3. GROUP BY userid: agrupa as linhas da tabela por usuário. Cada grupo conterá todas as sessões de um mesmo usuário.

  4. HAVING count(*)>1: filtra os grupos que possuem mais de uma sessão. A função COUNT(*) conta o número de linhas de cada grupo, e o HAVING aplica a condição sobre o resultado da agregação.

A ordem lógica de execução de uma consulta SQL é: FROMWHEREGROUP BYHAVINGSELECTORDER BY. Isso significa que o WHERE filtra linhas antes do agrupamento, e o HAVING filtra grupos depois. Por isso, não se pode usar WHERE count(*)>1, pois count(*) é uma função de agregação que só é avaliada após o GROUP BY.

Um exemplo concreto: se a tabela sessao tiver os registros (1, 10, 30.5), (2, 10, 45.0), (3, 20, 60.0), a consulta correta agruparia por userid (10 e 20), calcularia a média de duracao para cada grupo (37.75 para o usuário 10 e 60.0 para o usuário 20) e, com HAVING count(*)>1, retornaria apenas o usuário 10, que tem duas sessões.

A pegadinha da banca está em confundir WHERE com HAVING e em agrupar por id em vez de userid. O id é a chave primária da tabela, portanto cada linha tem um id único, e agrupar por id faria cada grupo ter exatamente uma linha, tornando o HAVING count(*)>1 sempre falso. O correto é agrupar por userid, que identifica o usuário, e não a sessão.

Guarde a fronteira entre WHERE (filtra linhas antes do agrupamento) e HAVING (filtra grupos após o agrupamento): é exatamente nela que as alternativas se dividem.

Critério

Alternativa A (correta)

Alternativas B, C, D, E (incorretas)

Uso de GROUP BY

Agrupa por userid (identifica usuários)

B e C não usam GROUP BY; D e E agrupam por id (chave primária, única por linha)

Filtro de grupos

HAVING count(*)>1 filtra grupos após agregação

B e D usam WHERE count(*) (inválido, pois WHERE não aceita agregação); C usa HAVING sem GROUP BY; E usa HAVING mas agrupa por id

Colunas no SELECT

userid + avg(duracao) (coluna não agregada está no GROUP BY)

B e D incluem id sem agrupá-lo; C e E selecionam colunas inconsistentes com o agrupamento

Resultado esperado

Retorna média por usuário apenas para quem tem >1 sessão

B e D geram erro de sintaxe; C retorna média geral (1 linha); E retorna conjunto vazio (nenhum grupo com >1 linha)

Alternativa A — ✅ Correta ⟵ GABARITO

A consulta select userid, avg(duracao) from sessao group by userid having count(*)>1 está sintaticamente correta e realiza exatamente o que se pede: agrupa as sessões por usuário, calcula a média da duração de cada grupo e filtra apenas os grupos com mais de uma sessão. A função AVG é a função de agregação correta para calcular a média, e HAVING é a cláusula adequada para filtrar grupos após a agregação.

Alternativa B — ❌ Incorreta

A consulta select id, userid, avg(duracao) from sessao where count(*)>1 está incorreta por dois motivos: primeiro, WHERE não pode conter funções de agregação como count(*), pois o WHERE é avaliado antes do agrupamento; segundo, a consulta não possui GROUP BY, então não há grupos para filtrar. Além disso, selecionar id junto com userid e avg(duracao) sem agrupar por id violaria a regra de que colunas não agregadas no SELECT devem aparecer no GROUP BY.

Alternativa C — ❌ Incorreta

A consulta select userid, avg(duracao) from sessao having count(id)>1 está incorreta porque não possui a cláusula GROUP BY. Sem o GROUP BY, a consulta trata toda a tabela como um único grupo, e o HAVING count(id)>1 seria avaliado sobre esse grupo único, retornando apenas uma linha com a média geral, não a média por usuário. Além disso, count(id) conta apenas valores não nulos de id, mas como id é chave primária, não há diferença prática em relação a count(*).

Alternativa D — ❌ Incorreta

A consulta select id, userid, avg(duracao) from sessao where count(*)>1 group by id, userid está incorreta porque WHERE não pode conter funções de agregação. O WHERE é avaliado antes do agrupamento, e count(*) só pode ser usado no HAVING. Além disso, agrupar por id e userid faria com que cada grupo tivesse uma única linha (já que id é único), tornando o filtro count(*)>1 sempre falso.

Alternativa E — ❌ Incorreta

A consulta select id, avg(duracao) from sessao group by id having count(*)>1 está incorreta porque agrupa por id, que é a chave primária da tabela. Como cada id é único, cada grupo teria exatamente uma linha, e o HAVING count(*)>1 nunca seria satisfeito. O correto seria agrupar por userid, que identifica o usuário, e não a sessão.

NÃO CAIA NESSA!

A banca troca a coluna de agrupamento: em vez de userid, usa id (chave primária). Como id é único por linha, agrupar por id faz cada grupo ter uma única sessão, e o filtro count(*)>1 nunca retorna nada. Fique atento: a pergunta pede usuários com mais de uma sessão, então o agrupamento deve ser por userid.

PEGA ESSA DICA!

Para montar consultas com agregação, siga a ordem lógica: FROMWHEREGROUP BYHAVINGSELECT. O WHERE filtra linhas antes de agrupar; o HAVING filtra grupos depois. Se a condição envolve uma função de agregação (como count, avg, sum), ela só pode estar no HAVING. E lembre-se: toda coluna no SELECT que não estiver dentro de uma função de agregação deve aparecer no GROUP BY.

Gabarito: letra A

Link permanente: /questoes/ce403613