Inquérito 007, "Litro por litro": solução passo a passo
O boletim
Não é crime da cidade: é crime de dentro de casa.
A delegacia abastece a viatura no Posto Trentini por convênio com a prefeitura. O posto manda a nota, a prefeitura paga e ninguém confere. De janeiro a junho a conta passou de cinco mil e oitocentos reais, quase o dobro do ano passado, e a prefeitura mandou um ofício perguntando se a delegacia comprou um segundo carro.
O doutor abriu sindicância interna, protocolo trezentos e noventa e dois, e quer três coisas até o fim do dia: quanto cada um abasteceu, em que veículos esse combustível entrou, e — já que a chefia nova sabe mexer na máquina — quantas vezes cada login abriu o SISPOL, porque ele desconfia que tem gente que não trabalha.
A viatura é a Ipanema branca, placa AIU-7001, o `id` 1 da tabela `veiculo`. Seu Jaime avisa: aqui não vai adiantar ler linha por linha. São cento e quarenta notas no livro do convênio, a tabela `abastecimento`, setenta e quatro só de janeiro a junho. Aqui a pergunta é de quanto, não de qual, e para responder quanto existe um jeito de a máquina somar sozinha.
Cinco nomes deram depoimento à sindicância, o do doutor entre eles. A chefia quer um nome, e quer a conta que mostra o nome.
O que o caso ensina: COUNT, SUM e GROUP BY.
Pergunta 1
O ofício da prefeitura quer a conta do semestre. Traga quantas notas o convênio teve de janeiro a junho de 2003 e quanto elas custaram, em reais.
Ver as dicas do jogo
- O ofício da prefeitura fala da conta do semestre. Traga, da tabela `abastecimento`, a contagem de notas e a soma do `valor` de todas as notas com `data` de 1º de janeiro a 30 de junho de 2003.
- É uma linha só: COUNT(*) conta as notas e SUM(`valor`) soma o dinheiro, e o semestre é a `data` entre '2003-01-01' e '2003-06-30', com BETWEEN.
- Escreva: `SELECT COUNT(*), SUM(valor) FROM abastecimento WHERE data BETWEEN '2003-01-01' AND '2003-06-30';`
Ver a consulta que resolve
SELECT COUNT(*), SUM(valor) FROM abastecimento WHERE data BETWEEN '2003-01-01' AND '2003-06-30';
`COUNT(*)` e `SUM(coluna)` são funções de agregação: a primeira conta quantas linhas passaram pelo `WHERE`, a segunda soma os números de uma coluna dessas linhas. Sem mais nada, todas as notas do semestre viram uma pilha só, e o resultado é uma linha.
Resultado
| quantas notas | quantos reais |
|---|---|
| 74 | 5847 |
Pergunta 2
Agora a mesma conta, assinatura por assinatura: quantas notas e quantos litros cada um que assinou tem no semestre.
Ver as dicas do jogo
- Agora a mesma pilha de notas, pessoa por pessoa. Traga, da tabela `abastecimento`, de 1º de janeiro a 30 de junho de 2003, o `pessoa_id` de quem assinou, a contagem de notas e a soma dos `litros` de cada um.
- Uma pilha por assinatura é GROUP BY `pessoa_id`; o COUNT(*) e o SUM(`litros`) passam a contar e somar cada pilha.
- Escreva: `SELECT pessoa_id, COUNT(*), SUM(litros) FROM abastecimento WHERE data BETWEEN '2003-01-01' AND '2003-06-30' GROUP BY pessoa_id;`
Ver a consulta que resolve
SELECT pessoa_id, COUNT(*), SUM(litros) FROM abastecimento WHERE data BETWEEN '2003-01-01' AND '2003-06-30' GROUP BY pessoa_id;
`GROUP BY` é quem faz o grupo existir: ele junta numa pilha só todo mundo que tem o mesmo `pessoa_id`, e o `COUNT` e o `SUM` passam a contar e somar pilha por pilha. Sem ele, a consulta volta a ser a da prefeitura: uma linha só.
Resultado
| pessoa_id | quantas notas | quantos litros |
|---|---|---|
| 2 | 5 | 190 |
| 4 | 39 | 1410 |
| 5 | 28 | 1120 |
| 6 | 2 | 132 |
Pergunta 3
O doutor quer saber quem trabalha nesta casa. Conte, no livro de acesso inteiro, quantas vezes cada login fez cada operação.
Ver as dicas do jogo
- O doutor também pediu o livro de acesso do SISPOL, a tabela `acesso`. Traga o `usuario_id`, a `operacao` e quantas vezes cada combinação das duas aparece no livro inteiro.
- Duas colunas no GROUP BY, `usuario_id` e `operacao`, e COUNT(*) ao lado. Sem faixa de datas.
- Escreva: `SELECT usuario_id, operacao, COUNT(*) FROM acesso GROUP BY usuario_id, operacao;`
Ver a consulta que resolve
SELECT usuario_id, operacao, COUNT(*) FROM acesso GROUP BY usuario_id, operacao;
`GROUP BY` aceita mais de uma coluna: aqui ele junta por `usuario_id` e por `operacao` ao mesmo tempo, então cada linha do resultado é uma combinação das duas, e o mesmo login aparece uma vez para cada operação diferente que ele fez.
Resultado
| usuario_id | operacao | quantas vezes |
|---|---|---|
| 11 | consulta | 3 |
| 12 | baixa | 13 |
| 12 | consulta | 56 |
| 12 | gravacao | 46 |
| 12 | impressao | 44 |
| 13 | consulta | 255 |
| 13 | gravacao | 270 |
| 13 | impressao | 278 |
| 14 | consulta | 132 |
| 14 | gravacao | 145 |
| 15 | consulta | 136 |
| 17 | consulta | 4 |
Pergunta 4
Separe a conta do semestre por carro e por assinatura ao mesmo tempo: quantas notas e quantos litros cada par tem.
Ver as dicas do jogo
- Separe as notas do semestre por carro e por pessoa ao mesmo tempo. Traga, da tabela `abastecimento`, de 1º de janeiro a 30 de junho de 2003, o `veiculo_id`, o `pessoa_id`, a contagem de notas e a soma dos `litros` de cada par.
- GROUP BY com as duas colunas, `veiculo_id` e `pessoa_id`, na mesma faixa de datas das outras contas.
- Escreva: `SELECT veiculo_id, pessoa_id, COUNT(*), SUM(litros) FROM abastecimento WHERE data BETWEEN '2003-01-01' AND '2003-06-30' GROUP BY veiculo_id, pessoa_id;`
Ver a consulta que resolve
SELECT veiculo_id, pessoa_id, COUNT(*), SUM(litros) FROM abastecimento WHERE data BETWEEN '2003-01-01' AND '2003-06-30' GROUP BY veiculo_id, pessoa_id;
É o mesmo `GROUP BY` de duas colunas do livro de acesso, agora no livro do convênio. Cada linha é uma combinação que existe de verdade nas notas: se um par não aparece, é porque nenhuma nota tem aquele carro com aquela assinatura.
Resultado
| veiculo_id | pessoa_id | quantas notas | quantos litros |
|---|---|---|---|
| 1 | 2 | 5 | 190 |
| 1 | 4 | 21 | 798 |
| 1 | 5 | 28 | 1120 |
| 1 | 6 | 2 | 132 |
| 33 | 4 | 18 | 612 |
Pergunta 5
Traga a ficha de cada carro que aparece nas notas do semestre.
Ver as dicas do jogo
- Traga, da tabela `veiculo`, o `id`, a `placa`, o `modelo`, a `cor`, o `ano` e o `dono_id` de cada veículo que aparece nas notas do semestre.
- Os números dos carros estão na conta por carro e por pessoa. Ponha os dois numa lista, depois de IN, para a coluna `id`.
- Escreva: `SELECT id, placa, modelo, cor, ano, dono_id FROM veiculo WHERE id IN (1, 33);`
Ver a consulta que resolve
SELECT id, placa, modelo, cor, ano, dono_id FROM veiculo WHERE id IN (1, 33);
O `IN` do caso 4 continua pedindo uma lista de valores de uma vez só. A lista quem escreveu foi o chefe, lendo o resultado de antes: a máquina não sabe quais carros importam, o chefe sabe.
Resultado
| id | placa | modelo | cor | ano | dono_id |
|---|---|---|---|---|---|
| 1 | AIU-7001 | Chevrolet Ipanema (viatura) | branca | 1996 | 0 |
| 33 | AJR-0182 | Chevrolet Monza | cinza | 1991 | 78 |
Quem foi
Ver o culpado e a prova
O culpado é Valdemar Prestes.
As provas que fecham o caso:
- A conta por carro e por pessoa: dezoito notas assinadas pelo 4 no carro 33, que não é a viatura.
- Dezoito notas assinadas pelo 4 no carro 33, e o carro 33 é um Monza cinza no nome de outra pessoa.
- O 4 aparece duas vezes na conta por carro e por pessoa: vinte e uma notas na viatura, o carro 1, e dezoito no carro 33.
O doutor leu a tela em silêncio e mandou chamar o Cabeção. O Cabeção entrou fazendo piada e parou de fazer piada quando viu os seiscentos e doze litros somados em números grandes.
Disse que o Monza era da sogra. Disse que ia devolver. Disse que era o adicional noturno que cortaram em 2002. Disse que todo mundo faz. Nessa última o doutor levantou a cabeça e perguntou quem é todo mundo, e o Cabeção não respondeu, porque ele mente por preguiça e não por coragem.
Foi afastado com sindicância, e o delegado mandou pôr cadeado na bomba do convênio.
À noite, com a delegacia vazia, Seu Jaime pediu para você abrir de novo a conta dos logins. Ficou muito tempo na linha da baixa. Disse que o usuário doze é o doutor, desde que o doutor chegou. Depois perguntou, sem olhar para você, quem é que fica aqui depois que ele vai embora. Do balcão vinha o barulho da máquina de escrever.