MySQL - 复杂的COUNT查询

时间:2012-03-27 20:24:31

标签: mysql sql count max

我有一个名为user_scores的表,如下所示:

id | af_id | uid | level | record_date
----------------------------------------
1  | 1.1   | 1   | 3     | 2012-01-01
2  | 1.1   | 1   | 4     | 2012-02-01
3  | 1.2   | 1   | 3     | 2012-01-01
4  | 1.2   | 1   | 5     | 2012-03-01
...

我有另一个表调用user_info,如下所示:

uid | forename | surname | gender 
-----------------------------------
1   | Homer    | Simpson | M
2   | Marge    | Simpson | F
3   | Bart     | Simpson | M
4   | Lisa     | Simpson | F
...

在用户分数中,uid是系统上注册用户的用户ID,af_id标识用户提交的特定测试。每个测试的用户得分在1到5之间,可以每月提交。

我的问题是我需要在年底进行分析,以计算达到特定测试每个级别的用户数量。分析是为了显示男性和女性的性别分歧。

因此,例如,管理员将选择测试1.1,系统将生成基于年度中每个用户达到的总MAX水平的COUNT的统计数据,并进行性别分割。

非常感谢任何帮助。提前谢谢。

-

我想我需要澄清一下自己。由于用户可以在一年中多次完成测试,因此同一测试将有多个分数。查询应采用达到的最高级别并将其包括在计数中。示例结果将是:

Male Results: 
level1 | level2 | level3 | level4 | level5 
------------------------------------------
2      | 5      | 10     | 8      | 1

5 个答案:

答案 0 :(得分:2)

我不确定我到底是什么意思,但我一如既往地走了。据我了解,您想知道每个性别中有多少人在某一年达到了每个级别。

SELECT  MaxLevel, 
        COUNT(CASE WHEN ui.Gender = 'M' THEN 1 END) AS Males,
        COUNT(CASE WHEN ui.Gender = 'F' THEN 1 END) AS Females
FROM    User_Info ui
        INNER JOIN
        (   SELECT  MAX(Level) AS MaxLevel, 
                    UID
            FROM    User_Scores us
            WHERE   af_ID = '1.1'
            AND     YEAR(Record_Date) = 2012
            GROUP BY UID
        ) AS MaxUs
            ON MaxUs.uid = ui.UID
GROUP BY MaxLevel

我已在SQL Fiddle上提供了一些示例数据,因此您可以看到它是否是您所追求的。

修改 要转置数据,以便级别位于行顶部,而性别位于行中,则以下内容将起作用:

SELECT  Gender, 
        COUNT(CASE WHEN MaxLevel = 1 THEN 1 END) AS Level1,
        COUNT(CASE WHEN MaxLevel = 2 THEN 1 END) AS Level2,
        COUNT(CASE WHEN MaxLevel = 3 THEN 1 END) AS Level3,
        COUNT(CASE WHEN MaxLevel = 4 THEN 1 END) AS Level4,
        COUNT(CASE WHEN MaxLevel = 5 THEN 1 END) AS Level5
FROM    User_Info ui
        INNER JOIN
        (   SELECT  MAX(Level) AS MaxLevel, 
                    UID
            FROM    User_Scores us
            WHERE   af_ID = '1.1'
            AND     YEAR(Record_Date) = 2012
            GROUP BY UID
        ) AS MaxUs
            ON MaxUs.uid = ui.UID
GROUP BY Gender

注意,如果有超过5个级别,则需要向select语句添加更多内容,或者开始构建动态SQL。

答案 1 :(得分:2)

假设record_date只保留日期(没有时间部分):

SELECT
  s.maxlevel,
  COUNT(NULLIF(gender, 'F')) AS M,
  COUNT(NULLIF(gender, 'M')) AS F
FROM user_info u
  INNER JOIN (
    SELECT
      uid,
      MAX(level) AS maxlevel
    FROM user_scores
    WHERE record_date > DATE_SUB(CURDATE(), INTERVAL DAYOFYEAR(CURDATE()) DAY)
      AND af_id = '1.1'
    GROUP BY
      uid
  ) s ON s.uid = u.uid
GROUP BY
  s.maxlevel

这将只显示user_scores表中找到的最高级别。如果您有一个Levels表,其中列出了所有可能的级别(1到5),则可以使用该表来获取完整的级别列表。如果请求的数据子集中没有某些级别,则相应的行将在两列中显示0

以上是上面的脚本,稍加修改以显示完整的关卡图表:

SELECT
  l.level AS maxlevel,
  COUNT(NULLIF(gender, 'F')) AS M,
  COUNT(NULLIF(gender, 'M')) AS F
FROM user_info u
  INNER JOIN (
    SELECT
      uid, MAX(level) AS maxlevel
    FROM user_scores
    WHERE record_date > DATE_SUB(CURDATE(), INTERVAL DAYOFYEAR(CURDATE()) DAY)
      AND af_id = '1.1'
    GROUP BY
      uid
  ) s ON s.uid = u.uid
  RIGHT JOIN Levels l ON s.maxlevel = l.level
GROUP BY
  l.level

答案 2 :(得分:0)

根据您的编辑进行编辑。

 select sum(if(a.gender="M",1,0)) Male_users, sum(if(a.gender="F",1,0)) Female_users
 from myTable a where 
    a.level = (select max(b.level) from myTable b where a.uid=b.uid) 
 group by af_id.

我匆匆打字。但它应该工作或至少让你到达你需要去的地方。例如。如果您需要指定时间范围,请添加。

答案 3 :(得分:0)

希望这是你想要的!

按用户ID显示记录组数,并为af_id'1.1'显示最高得分的性别。

select count(*), info.uid, info.gender, max(score.level)
from user_info as info 
join user_scores as score
  on info.uid = score.uid
where score.af_id = '1.1'
group by info.uid, info.gender;

答案 4 :(得分:-2)

你需要像

这样的东西
SELECT
  uid,
  MAX(level)
WHERE
  record_date BETWEEN '2012-01-01' AND '2012-12-31'
  AND af_id='1.1'
GROUP BY uid

如果您需要性别拆分,那么根据您每个性别需要的统计信息,您可以在user_info表中将JOIN添加到此查询中(以获得每性别的MAX)以将其包装为子查询和JOIN on整件事。