【问题标题】:MySQL GROUP BY age range including null rangesMySQL GROUP BY 年龄范围,包括空范围
【发布时间】:2010-07-14 15:17:01
【问题描述】:

我正在尝试按年龄段计算人数,我几乎可以解决 2 个问题:

  1. 如果给定年龄范围内没有人 (NULL),则该年龄范围不会出现在结果中。例如,在我的数据中没有“Over 80”的条目,因此不会出现日期范围。基本上,当缺少日期范围时,这看起来像是编程错误。

  2. 我想以特定方式对结果进行排序。在下面的查询中,因为 ORDER BY 是按年龄范围排列的,所以“20 - 29”的结果排在“20 岁以下”的结果之前。

这是 db 表“查询”的示例:

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

这是查询:

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

根据 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

【问题讨论】:

  • 您的问题已经回答了我自己的问题。谢谢你:)

标签: mysql


【解决方案1】:

范围表的替代方案(这是我的偏好),单行答案可能是:

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;

【讨论】:

  • 我刚刚尝试使用 SUM 方法,它很简单而且效果很好。它按指定的顺序放置 SUM。我已将最终解决方案放在原始问题中,以防有人想查看。
【解决方案2】:

对结果进行排序的一种方法是在 select 语句中引入一列,并为其指定您希望结果与其余部分排序的方式的排名值,然后按该行排序,例如

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

【讨论】:

    【解决方案3】:
    1. 创建一个包含所有范围的表并使用外连接。
    2. 按该表另一列中的数值排序

      选择范围,.... 从范围 左连接(您的子查询)打开(ranges.range = your_range) ... ORDER BY range.year ASC

    【讨论】:

    • 这似乎是一个可以解决我最初的两个问题的解决方案,但是我在弄清楚 JOIN 子句时遇到了麻烦。在上面的解决方案中,“your_range”是什么?
    猜你喜欢
    • 2016-11-24
    • 1970-01-01
    • 2021-10-22
    • 2015-04-14
    • 2015-07-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-19
    相关资源
    最近更新 更多