2010-07-14 5 views
12

Je suis en train de compter le nombre de personnes par tranche d'âge, et je peux presque le faire avec 2 problèmes:MySQL GROUP BY tranche d'âge, y compris gammes null

  1. S'il n'y a personne dans une donnée âge (NULL), cette plage d'âge n'apparaît pas dans les résultats. Par exemple, dans mes données, il n'y a pas d'entrées pour "Plus de 80", de sorte que la plage de dates n'apparaît pas. Fondamentalement, cela ressemble à une erreur dans la programmation quand il y a des plages de dates manquantes.

  2. J'aimerais commander les résultats d'une manière spécifique. Dans la requête ci-dessous, étant donné que ORDER BY est défini par age_range, les résultats pour '20 - 29 'viennent avant les résultats pour' Under 20 '.

Voici un échantillon de la table db "demandes":

inquiry_id birth_date 
1   1960-02-01 
2   1962-03-04 
3   1970-03-08 
4   1980-03-02 
5   1990-02-08 

Voici la requête:

SELECT 
    CASE 
     WHEN age < 20 THEN 'Under 20' 
     WHEN age BETWEEN 20 and 29 THEN '20 - 29' 
     WHEN age BETWEEN 30 and 39 THEN '30 - 39' 
     WHEN age BETWEEN 40 and 49 THEN '40 - 49' 
     WHEN age BETWEEN 50 and 59 THEN '50 - 59' 
     WHEN age BETWEEN 60 and 69 THEN '60 - 69' 
     WHEN age BETWEEN 70 and 79 THEN '70 - 79' 
     WHEN age >= 80 THEN 'Over 80' 
     WHEN age IS NULL THEN 'Not Filled In (NULL)' 
    END as age_range, 
    COUNT(*) AS count 

    FROM (SELECT TIMESTAMPDIFF(YEAR, birth_date, CURDATE()) AS age FROM inquiries) as derived 

    GROUP BY age_range 

    ORDER BY age_range 

est ici une solution simple basée sur la suggestion faite par Wrikken:

SELECT 
    SUM(IF(age < 20,1,0)) as 'Under 20', 
    SUM(IF(age BETWEEN 20 and 29,1,0)) as '20 - 29', 
    SUM(IF(age BETWEEN 30 and 39,1,0)) as '30 - 39', 
    SUM(IF(age BETWEEN 40 and 49,1,0)) as '40 - 49', 
    SUM(IF(age BETWEEN 50 and 59,1,0)) as '50 - 59', 
    SUM(IF(age BETWEEN 60 and 69,1,0)) as '60 - 69', 
    SUM(IF(age BETWEEN 70 and 79,1,0)) as '70 - 79', 
    SUM(IF(age >=80, 1, 0)) as 'Over 80', 
    SUM(IF(age IS NULL, 1, 0)) as 'Not Filled In (NULL)' 

FROM (SELECT TIMESTAMPDIFF(YEAR, birth_date, CURDATE()) AS age FROM inquiries) as derived 
+0

Votre question a déjà répondu à ma propre question. Merci pour cela :) –

Répondre

10

une alternative à la table de gamme (qui a ma préférence), une réponse unique ligne pourrait être:

SELECT 
    SUM(IF(age < 20,1,0)) as 'Under 20', 
    SUM(IF(age BETWEEN 20 and 29,1,0)) as '20 - 29', 
    SUM(IF(age BETWEEN 30 and 39,1,0)) as '30 - 39', 
    SUM(IF(age BETWEEN 40 and 49,1,0)) as '40 - 49', 
...etc. 
FROM inquiries; 
+0

J'ai juste essayé d'utiliser l'approche SUM, et c'est simple et fonctionne parfaitement. Il place les SUM dans l'ordre spécifié. J'ai mis la solution finale dans la question originale au cas où quelqu'un voudrait la voir. – Mitchell

1
  1. Créez une table contenant toutes les plages et utilisez la jointure externe.
  2. Trier par valeur numérique dans une autre colonne de cette table

    gamme SELECT, .... DE gammes LEFT JOIN (Votre sous-requête) ON (ranges.range = your_range) ... ORDER BY range.year ASC

+0

Cela semble être une solution qui prendra soin de mes deux problèmes initiaux, mais j'ai du mal à trouver la clause JOIN. Dans la solution ci-dessus, que serait "your_range"? – Mitchell

2

Une façon de commander les résultats introduirait une colonne dans l'instruction select et en lui donnant une valeur de rang de la façon dont vous voulez que vos résultats à commander avec le reste et l'ordre par cette ligne, par exemple

SELECT 
CASE 
    WHEN age < 20 THEN 'Under 20' 
    WHEN age BETWEEN 20 and 29 THEN '20 - 29' 
    WHEN age BETWEEN 30 and 39 THEN '30 - 39' 
    WHEN age BETWEEN 40 and 49 THEN '40 - 49' 
    WHEN age BETWEEN 50 and 59 THEN '50 - 59' 
    WHEN age BETWEEN 60 and 69 THEN '60 - 69' 
    WHEN age BETWEEN 70 and 79 THEN '70 - 79' 
    WHEN age >= 80 THEN 'Over 80' 
    WHEN age IS NULL THEN 'Not Filled In (NULL)' 
END as age_range, 
COUNT(*) AS count, 
CASE 
    WHEN age < 20 THEN 1 
    WHEN age BETWEEN 20 and 29 THEN 2 
    WHEN age BETWEEN 30 and 39 THEN 3 
    WHEN age BETWEEN 40 and 49 THEN 4 
    WHEN age BETWEEN 50 and 59 THEN 5 
    WHEN age BETWEEN 60 and 69 THEN 6 
    WHEN age BETWEEN 70 and 79 THEN 7 
    WHEN age >= 80 THEN 8 
    WHEN age IS NULL THEN 9 
END as ordinal 

FROM (SELECT TIMESTAMPDIFF(YEAR, birth_date, CURDATE()) AS age FROM inquiries) as derived 

GROUP BY age_range 

ORDER BY ordinal