Criar sql para separar pessoas por grupos de idade

Oi gente, tudo bem,
to apanhando um pouco do sql aki, porém preciso fazer o seguinte relatório,
preciso fazer um relatorio que traga o nome das pessoas e suas respectivas idades, eu fiz o seguinte abaixo e funcionou:

SELECT
pes_nom_completo,pes_data_nascimento,(YEAR(CURDATE())-YEAR(pes_data_nascimento)) - (RIGHT(CURDATE(),5)<RIGHT(pes_data_nascimento,5)) AS idade
FROM
pessoas

Porém agora preciso fazer um relatório que divida as pessoas entre grupos de idade.
Exemplo

Grupo de idade - Quantidade de pessoas
<=20 - 4
25-30 - 8
31-30 - 2
36-30 - 5
.
.
.
86-90 - 2

91

Porém não faço ideia de como faze-lo, alguém poderia dar um help
ps: uso mysql

Camarada, com certeza você precisará de um select gigantesco.
Eu sugiro pensar em uma stored procedure…

O que seria uma stored procedure? Como se usa?

Wikipedia: Procedimento armazenado ou Stored Procedure é uma coleção de comandos em SQL para dispensamento de Banco de dados. Encapsula tarefas repetitivas, aceita parâmetros de entrada e retorna um valor de status (para indicar aceitação ou falha na execução). O procedimento armazenado pode reduzir o tráfego na rede, melhorar a performance, criar mecanismos de segurança, etc.

Uma stored procedure é como um programa, escrito para ser pre compilado e rodar direto no SGBD.
Bancos mais antigos como o SQL Server e Oracle possuem implementação há muito tempo.
MySQL, apenas a partir da versão 5.

Como qualquer outro programa, uma SP contém:
Entrada
Processamento
Saída
Onde:
Entrada: Recebe argumentos (partindo de zero);
Processamento: Realiza as ações programadas, dependentes dos argumentos inseridos ou não;
Saída: Retorna o resultado do processamento (pode ser um retorno vazio ou especificado).

Aqui tem um link com muita coisa legal para isso.

http://dev.mysql.com/doc/refman/4.1/pt/create-procedure.html

No teu caso, para cada faixa, você pode fazer um select count, para determinar a quantidade de pessoas naquela faixa etária.
Depois, concatena o resultado numa variável e retorna ela.

Nem precisa de SQL enorme (não mexi na lógica do cálculo de idade, mas acho que dá para otimizar isso):


SELECT
  CASE WHEN (YEAR(CURDATE())-YEAR(pes_data_nascimento)) - (RIGHT(CURDATE(),5)<RIGHT(pes_data_nascimento,5)) < 20 then '<20'
           ELSE Trunc((YEAR(CURDATE())-YEAR(pes_data_nascimento)) - (RIGHT(CURDATE(),5)<RIGHT(pes_data_nascimento,5))/5)*5
  END as Faixa_de_idade,
  Count(*)
FROM pessoas
GROUP BY 1

bom o que voce precisa nao eh uma store procedure e sim uma view.

pesquise sobre o group by, eh meio chato de entender no comeco, mas com o tempo vc se acostuma.

[]'s

Boa tarde!!

Bem simples isso, utilize uma clausula WHERE no seu select incluindo BETWEEN idade1 and idade2 e adicione um COUNT() para que te retorne a quantidade de pessoas em cada faixa de idade.

Por exemplo:

    SELECT  
    COUNT(pes_nom_completo,pes_data_nascimento,(YEAR(CURDATE())-YEAR(pes_data_nascimento)) - (RIGHT(CURDATE(),5)<RIGHT(pes_data_nascimento,5))) AS idade  
    FROM  
    pessoas 
    WHERE pes_nom_completo,pes_data_nascimento,(YEAR(CURDATE())-YEAR(pes_data_nascimento)) - (RIGHT(CURDATE(),5)<RIGHT(pes_data_nascimento,5))
       BETWEEN parametro1 and parametro2

Att.

Essa sentença funcionou depois que fiz uma pequena mudança nela

SELECT
pes_nom_completo,pes_data_nascimento,(YEAR(CURDATE())-YEAR(pes_data_nascimento)) - (RIGHT(CURDATE(),5)<RIGHT(pes_data_nascimento,5)) AS idade
FROM
pessoas
WHERE (YEAR(CURDATE())-YEAR(pes_data_nascimento)) - (RIGHT(CURDATE(),5)<RIGHT(pes_data_nascimento,5))
       BETWEEN 45 and 55

Porém eu teria que repeti-la para cada intervalo de idade, acho q pode ser mais otimizado, mas já é um bom começo.

Eu removi o Trunc(o mysql workbench falou q tal função não existia) e removi a multiplicação por 5 no final do else e a sentença funcionou trazendo os seguintes resultados
Faixa de idade - Quant Pessoas
35.0000 - 2
37.0000 - 1
42.0000 - 1
46.0000 - 1
49.0000 - 1
61.0000 - 1
64.0000 - 1
65.0000 - 1
80.0000 - 1
83.0000 - 1
<20 - 1

Foi bem feita a sentença, porém como eu nunca tinha usado CASE e END numa sentença sql, fiquei meio sem entender o q aconteceu, agora tenho q tentar agrupar o resultado dentro das faixas de idade, em vez de categorizar por cada idade

A solução dada pelo evefuji é a mais eficiente de todas. Vou só tentar contribuir com o modo como fazemos cálculo de idade aqui:

select trunc((curdate() - pes_data_nascimento) / 365.25)

o .25 corresponde ao chorinho de um dia dos anos bissextos…

Então… no caso, como você quer agrupar por faixas ficaria tipo assim:

select case when trunc((curdate() - pes_data_nascimento) / 365.25) <= 20 then
         'ate 20'
          when trunc((curdate() - pes_data_nascimento) / 365.25)  between 25 and 30 then
         'de 25 a 30'
         when  trunc((curdate() - pes_data_nascimento) / 365.25)  between 31 and 35 then
         'de 31 a 35
         ...
         end as faixa_idade
, count(*)
from pessoas
group by 1

Veja se o trunc não existe mesmo, deve ter outra função no lugar dele pra pegar só a parte inteira do resultado da operação

Por esse motivo havia sugerido stored procedure.
Você conseguiria criar os selects isoladamente e, ao fim, concatenar todos os resultados em uma única saída, formatada.
Talvez um cursor já resolvesse, também.
Enfim, há várias formas de se resolver isto, o ideal é que você foque em uma e vá até o fim com ela.
Dúvidas, poste aqui.

[quote=ADEMILTON]A solução dada pelo evefuji é a mais eficiente de todas. Vou só tentar contribuir com o modo como fazemos cálculo de idade aqui:

select trunc((curdate() - pes_data_nascimento) / 365.25)

o .25 corresponde ao chorinho de um dia dos anos bissextos…[/quote]
Não seria concat???

[quote=drsmachado][quote=ADEMILTON]A solução dada pelo evefuji é a mais eficiente de todas. Vou só tentar contribuir com o modo como fazemos cálculo de idade aqui:

select trunc((curdate() - pes_data_nascimento) / 365.25)

o .25 corresponde ao chorinho de um dia dos anos bissextos…[/quote]
Não seria concat???[/quote]

Não, não, colega… faço exatamente do jeito que coloquei, só que no meu caso uso a função sysdate() porque aqui é Oracle.

[quote=fabiobh][quote=ManoJava]
Bem simples isso, utilize uma clausula WHERE no seu select incluindo BETWEEN idade1 and idade2 e adicione um COUNT() para que te retorne a quantidade de pessoas em cada faixa de idade.
SELECT
COUNT(pes_nom_completo,pes_data_nascimento,(YEAR(CURDATE())-YEAR(pes_data_nascimento)) - (RIGHT(CURDATE(),5)<RIGHT(pes_data_nascimento,5))) AS idade
FROM
pessoas
WHERE pes_nom_completo,pes_data_nascimento,(YEAR(CURDATE())-YEAR(pes_data_nascimento)) - (RIGHT(CURDATE(),5)<RIGHT(pes_data_nascimento,5))
BETWEEN parametro1 and parametro2

[/quote]
Essa sentença funcionou depois que fiz uma pequena mudança nela

SELECT
pes_nom_completo,pes_data_nascimento,(YEAR(CURDATE())-YEAR(pes_data_nascimento)) - (RIGHT(CURDATE(),5)<RIGHT(pes_data_nascimento,5)) AS idade
FROM
pessoas
WHERE (YEAR(CURDATE())-YEAR(pes_data_nascimento)) - (RIGHT(CURDATE(),5)<RIGHT(pes_data_nascimento,5))
       BETWEEN 45 and 55

Porém eu teria que repeti-la para cada intervalo de idade, acho q pode ser mais otimizado, mas já é um bom começo.

Eu removi o Trunc(o mysql workbench falou q tal função não existia) e removi a multiplicação por 5 no final do else e a sentença funcionou trazendo os seguintes resultados
Faixa de idade - Quant Pessoas
35.0000 - 2
37.0000 - 1
42.0000 - 1
46.0000 - 1
49.0000 - 1
61.0000 - 1
64.0000 - 1
65.0000 - 1
80.0000 - 1
83.0000 - 1
<20 - 1

Foi bem feita a sentença, porém como eu nunca tinha usado CASE e END numa sentença sql, fiquei meio sem entender o q aconteceu, agora tenho q tentar agrupar o resultado dentro das faixas de idade, em vez de categorizar por cada idade
[/quote]

Otimização é a palavra chave, apesar que a diferença de performance é imperceptível, mas sempre é recomendado resumir ao maximo as sentenças, lógico que respeitando sempre as limitações de cada BD.

Att.

a soluçao do ADEMILTON teria sido ideal se eu tivesse conseguido fazer funcionar,
eu não soube passar ela corretamente
o que eu posso estar escrevendo errado nesta sentença abaixo

select case when ((curdate() - pes_data_nascimento) / 365.25) <= 20 then           
         when ((curdate() - pes_data_nascimento) / 365.25)  between 25 and 30 then           
         when  ((curdate() - pes_data_nascimento) / 365.25)  between 31 and 35 then 
         end as faixa_idade  
, count(*)  
from pessoas  
group by 1 

no mysql workbench acusa erro na linha 2 no ‘when’

Faz tempo que não mexo com mysql (agora estou mais com oracle e postgres), mas vou fazer umas observações:

  1. No Oracle, quando você faz diferença de datas, ele retorna o número de dias, no mysql, como data é tratada no formato Unix, não é possível fazer essa diferença. (se me lembro bem)
  2. Para cálculo de idade no Oracle, eu costumava usar a diferença de datas em meses. Se tiver uma função no MySQL que faça a diferença de datas e retorne em meses ou ano, seria melhor (e teria o melhor desempenho)
  3. No mysql, se me lembro bem, é Floor. A ideia da lógica é “truncar” o número usando o valor de intervalos, segue um exemplo:

Numero /5 trunc *5 21 4,2 4 20 22 4,4 4 20 23 4,6 5 25 24 4,8 5 25 25 5 5 25 26 5,2 5 25 27 5,4 5 25 28 5,6 6 30 29 5,8 6 30 30 6 6 30 31 6,2 6 30 32 6,4 6 30 33 6,6 7 35 34 6,8 7 35 35 7 7 35 36 7,2 7 35 37 7,4 7 35 38 7,6 8 40

É mais rápido usar cálculos aritméticos que “case when”. No caso, coloquei só o valor inicial no Case When porque agrupa todos os valores menores que 20.

Edit: Acusa erro no segundo WHEN porque não colocou o valor que retorna no “THEN” anterior.

Como vc falou estava esquecendo o retorno, mas agora q coloquei funcionou.

Sim, o trunc não funciona no mysql, o floor resolve o problema.

Eu entendi sua logica, vou ver se consigo fazer o Mysql devolver o valor da data em anos para poder gerar essa sentença, caso não consiga a solução do case when funciona e eu vou tentar me virar com ela.

Obrigado a todos por ajudarem, a galera do GUJ detona mesmo, vlw e t+

só uma coisa que me toquei agora, na lógica:

((curdate() - pes_data_nascimento) / 365.25)

Se o cara tiver mais de 100 anos vai dar diferença de 1 dia. (a cada 100 anos não tem 1 dos anos bissextos, e a cada 1000 anos “volta” esse ano bissexto que não deveria ter)

eu faria assim no mysql …

1 - criaria uma tabela temporaria …
2 - nesta tabela tem tudo que preciso …

da uma olhada no exemplo que fiz, ver se ajuda !!!

drop table if exists tempgrupoidade;

create table tempgrupoidade
 Select apelido, dtnascimento, (DATEDIFF(NOW(), dtnascimento) / 365.25) as idade from flfuncionarios;

alter table tempgrupoidade add grupo int(10);

update tempgrupoidade set grupo = 1 where idade < 20;
update tempgrupoidade set grupo = 2 where idade between 20 and 31;
update tempgrupoidade set grupo = 3 where idade between 32 and 51;
update tempgrupoidade set grupo = 4 where idade between 52 and 71;
update tempgrupoidade set grupo = 5 where idade > 72;

select * from tempgrupoidade;

existe uma ganbiarra … mas funciona !
t+