2010-07-14 15 views
12

estoy tratando de contar el número de personas por rangos de edad, y casi puedo hacerlo con 2 problemas:GRUPO POR MySQL rango de edad oscila incluyendo nula

  1. Si no hay gente en un determinado rango de edad (NULL), entonces ese rango de edad no aparece en los resultados. Por ejemplo, en mis datos no hay entradas para "Más de 80" por lo que el rango de fechas no aparece. Básicamente, parece un error en la programación cuando faltan rangos de fechas.

  2. Me gustaría ordenar los resultados de una manera específica. En la siguiente consulta, dado que el ORDER BY está por age_range, los resultados para '20 - 29 'vienen antes de los resultados para' Under 20 '.

He aquí una muestra de la tabla db "indagaciones":

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

Aquí está la consulta:

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 

Aquí es una solución simple basada en la sugerencia de 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

Tu pregunta ya respondió mi propia pregunta. Gracias por eso :) –

Respuesta

10

una alternativa a la tabla de rango (que tiene mi preferencia), una respuesta de una sola fila podría ser:

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

Acabo de intentar usar el enfoque de SUM, y es simple y funciona perfectamente. Pone los SUM en el orden especificado. He puesto la solución final en la pregunta original en caso de que alguien quiera verla. – Mitchell

1
  1. Crea una tabla que contiene todos los rangos y usa la combinación externa.
  2. Ordenar por valor numérico en otra columna de dicho cuadro

    gama SELECT, .... de los fogones de combinación izquierda (Su subconsulta) ON (ranges.range = your_range) ... ORDER BY range.year ASC

+0

Esto parece ser una solución que resolverá mis dos problemas iniciales, sin embargo, tengo problemas para descifrar la cláusula JOIN. En la solución anterior, ¿cuál sería "your_range"? – Mitchell

2

Una forma de ordenar los resultados serían la introducción de una columna en la instrucción de selección y dándole un valor de rango de la forma en que desea que sus resultados pueden pedir con el resto y luego el fin de esa fila, por ejemplo

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