【问题标题】:Select by age and gender按年龄和性别选择
【发布时间】:2014-07-21 08:39:56
【问题描述】:

我进行了以下查询,以按年龄组、计数和百分比选择人员。年龄在我的数据库中存储为0000-00-00

SELECT  AgeGroup, count(*) AS count, ROUND(sum( 100 ) / total) AS percentage
        FROM    (
        SELECT  case
                when  age between 0 and 17 then '00 - 17'
                when  age between 18 and 24 then '18 − 24'
                when  age between 25 and 34 then '25 − 34'
                when  age between 35 and 44 then '35 − 44'
                when  age between 45 and 54 then '45 − 54'
                when  age between 55 and 64 then '55 − 64'
                when  age between 65 and 125 then '65+'
                else 'Unknown'
                end AS AgeGroup
        FROM    (
                SELECT  ROUND(DATEDIFF(Cast(NOW() as Date),
                            Cast(dateofbirth as Date)) / 365, 0) as age
                FROM    people
                ) as SubQueryAlias
        ) as SubQueryAlias2
        CROSS JOIN (SELECT count( * ) AS total FROM people)x
        group by
        AgeGroup

目前的结果是:

AgeGroup | count | percentage
00 - 17    33      1
18 − 24    235     5
..         ..      ..

我需要在查询中添加一个以分隔男性/女性/未知的结果:

AgeGroup  | gender | count | percentage
00 - 17     M        33      1
00 - 17     F        33      1
..          ..       ..      ..

【问题讨论】:

  • GROUP BY 子句中简单地添加性别会有什么结果?
  • 使用 GROUP BY 性别按顺序返回结果?
  • @user2071225 Group BY 性别由于某种原因不起作用
  • 你在用group by AgeGroup, Gender吗?
  • @user2071225 是的,列名是“性别”,但我一直收到:“组声明”中的未知列“性别”

标签: php mysql sql


【解决方案1】:

定义范围表可能会让您度过最轻松的时光。这也避免了您需要对每个条目进行日期数学运算,因此可能更有效地进行分组。

首先,一个年龄范围表:

SELECT '00 - 17' AS ageGroup, CURRENT_DATE AS lower, CURRENT_DATE - INTERVAL 18 YEAR AS upper
UNION ALL
SELECT '18 - 24', CURRENT_DATE - INTERVAL 18 YEAR, CURRENT_DATE - INTERVAL 25 YEAR
UNION ALL
SELECT '25 - 34', CURRENT_DATE - INTERVAL 25 YEAR, CURRENT_DATE - INTERVAL 35 YEAR
UNION ALL
SELECT '35 - 44', CURRENT_DATE - INTERVAL 35 YEAR, CURRENT_DATE - INTERVAL 45 YEAR
UNION ALL
SELECT '45 - 54', CURRENT_DATE - INTERVAL 45 YEAR, CURRENT_DATE - INTERVAL 55 YEAR
UNION ALL
SELECT '55 - 64', CURRENT_DATE - INTERVAL 55 YEAR, CURRENT_DATE - INTERVAL 65 YEAR
UNION ALL
SELECT '65+', CURRENT_DATE - INTERVAL 65 YEAR, null
UNION ALL
SELECT 'Unknown', null, null

SQL FIddle Demo

...它会生成一个您所期望的表格。请注意,上限是互斥的,这就是为什么它使用与下一行的下限相同的值。另请注意,1)'65+' 括号没有上限,2)'Unknown' 括号两者都没有。

当然,我们还需要一个Gender 表:

SELECT 'M' AS gender
UNION ALL
SELECT 'F'
UNION ALL
SELECT 'Unknown'

(作为旁注,我通常会使用多行 VALUES(...) 语句,但由于某种原因,SQL Fiddle 似乎不喜欢 MySQL 子查询中的语法。使用任何你喜欢的语法。)

我们需要最后一点知识:
具体来说,COUNT(<expression>) 将忽略 null 行。因此,我们可以将完整的查询拼接在一起,类似于:

SELECT AgeRange.ageGroup, Gender.gender, 
       COUNT(People.id), ROUND(100 * COUNT(People.id) / Total.countOfPeople) AS percentage
FROM (SELECT '00 - 17' AS ageGroup, CURRENT_DATE AS lower, CURRENT_DATE - INTERVAL 18 YEAR AS upper
      UNION ALL
      SELECT '18 - 24', CURRENT_DATE - INTERVAL 18 YEAR, CURRENT_DATE - INTERVAL 25 YEAR
      UNION ALL
      SELECT '25 - 34', CURRENT_DATE - INTERVAL 25 YEAR, CURRENT_DATE - INTERVAL 35 YEAR
      UNION ALL
      SELECT '35 - 44', CURRENT_DATE - INTERVAL 35 YEAR, CURRENT_DATE - INTERVAL 45 YEAR
      UNION ALL
      SELECT '45 - 54', CURRENT_DATE - INTERVAL 45 YEAR, CURRENT_DATE - INTERVAL 55 YEAR
      UNION ALL
      SELECT '55 - 64', CURRENT_DATE - INTERVAL 55 YEAR, CURRENT_DATE - INTERVAL 65 YEAR
      UNION ALL
      SELECT '65+', CURRENT_DATE - INTERVAL 65 YEAR, null
      UNION ALL
      SELECT 'Unknown', null, null)  AgeRange
CROSS JOIN (SELECT 'M' AS Gender
            UNION ALL
            SELECT 'F'
            UNION ALL 
            SELECT 'Unknown') Gender
CROSS JOIN (SELECT COUNT(*) countOfPeople
            FROM People) Total
LEFT JOIN People
       ON ((People.dateOfBirth > AgeRange.upper AND dateOfBirth <= AgeRange.lower)
           OR (People.dateOfBirth <= AgeRange.lower AND AgeRange.upper IS NULL)
           OR (AgeRange.lower IS NULL AND AgeRange.upper IS NULL AND People.dateOfBirth IS NULL))
          AND (Gender.gender = People.gender
               OR Gender.gender = 'Unknown' AND People.gender IS NULL)
GROUP BY AgeRange.ageGroup, Gender.gender

SQL Fiddle Demo
(注意 Fiddle 演示使用这篇文章的日期,'2014-07-21',作为CURRENT_DATE,以使未来读者的年龄范围查询稳定)。

【讨论】:

    【解决方案2】:

    我真的希望我错了....但是经常出错的原因会是...您没有选择性别吗?

    另外,一个书呆子的旁注,365 天不等于一年,它大约是 365.25 天 XD,这意味着你的等式有点偏离哈哈

    SELECT  AgeGroup, gender, count(*) AS count, ROUND(sum( 100 ) / total) AS percentage
        FROM    (
        SELECT  case
                when  age between 0 and 17 then '00 - 17'
                when  age between 18 and 24 then '18 − 24'
                when  age between 25 and 34 then '25 − 34'
                when  age between 35 and 44 then '35 − 44'
                when  age between 45 and 54 then '45 − 54'
                when  age between 55 and 64 then '55 − 64'
                when  age between 65 and 125 then '65+'
                else 'Unknown'
                end AS AgeGroup, gender
        FROM    (
                SELECT  ROUND(DATEDIFF(Cast(NOW() as Date),
                            Cast(dateofbirth as Date)) / 365, 0) as age, 
                            gender
                FROM    people
                ) as SubQueryAlias
        ) as SubQueryAlias2
        CROSS JOIN (SELECT count( * ) AS total FROM people)x
        group by
        AgeGroup, gender
    

    【讨论】:

    • 你还需要在SubQueryAlias2中选择性别
    • ……没看过哈哈
    猜你喜欢
    • 1970-01-01
    • 2015-09-08
    • 2020-05-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多