MySQL Query - 使用 group-by 时获取丢失的记录

Posted

技术标签:

【中文标题】MySQL Query - 使用 group-by 时获取丢失的记录【英文标题】:MySQL Query - getting missing records when using group-by 【发布时间】:2010-09-30 21:05:20 【问题描述】:

我有一个问题:

select score, count(1) as 'NumStudents' from testresults where testid = 'mytestid'
group by score order by score

其中 testresults 表包含学生在测试中的表现。假设测试的最高分数为 10,示例结果如下所示。

分数,NumStudents

0 10 1 20 2 12 3 5 5 34 .. 10 23

如您所见,此查询不会返回任何没有学生得分的记录。例如。没有人在测试中得分 4/10,并且查询输出中没有 score = 4 的记录。

我想更改查询,以便我可以获取这些缺失记录,其中 0 作为 NumStudents 字段的值。这样我的最终输出将有 max + 1 条记录,每个可能的分数都有一条。

有什么想法吗?

编辑:

数据库包含多个测试,测试的最高分数是测试定义的一部分。所以有一个新的表来存储所有可能的分数是不可行的。从某种意义上说,每当我创建一个新的最高分数的新测试时,我需要确保新表也应该更改为包含这些分数。

【问题讨论】:

【参考方案1】:

SQL 擅长处理数据库中的数据值集,但不擅长处理数据库中的数据值集。

最好的解决方法是保留一个小表来记录您需要覆盖的值:

CREATE TABLE ScoreValues (score int);
INSERT INTO ScoreValues (score) 
  VALUES (0), (1), (2), (3), (4), (5), (6), (7), (8), (9), (10);

鉴于您在另一个表中定义了测试的最大分数的评论,您可以通过以下方式加入该表,只要ScoreValues 的值肯定至少与最大值一样高或更高考试最高分:

SELECT v.score, COUNT(tr.score) AS 'NumStudents'
FROM ScoreValues v 
  JOIN Tests t ON (v.score <= t.maxmarks)
  LEFT OUTER JOIN TestResults tr ON (v.score = tr.score AND t.testid = tr.testid)
WHERE t.testid = 'mytestid'
GROUP BY v.score;

【讨论】:

【参考方案2】:

最明显的方法是创建一个名为“Scores”的表并将您的表左外部连接到它。

SELECT s.score, COUNT(1) AS scoreCount FROM 分数 AS s 左外连接 testScores AS ts ON s.score = ts.score GROUP BY s.score

如果你不想创建表,你可以使用

选择 1 作为分数,SUM(CASE WHEN ts.score = 1 THEN 1 ELSE 0 END) 作为 scoreCount, 2 作为分数,SUM(CASE WHEN ts.score = 2 THEN 1 ELSE 0 END) 作为 scoreCount, 3 作为分数,SUM(当 ts.score = 3 THEN 1 ELSE 0 END 时的情况)作为 scoreCount, 4 作为分数,SUM(当 ts.score = 4 THEN 1 ELSE 0 END 时的情况)作为 scoreCount, ... 10 作为分数,SUM(CASE WHEN ts.score = 10 THEN 1 ELSE 0 END) 作为 scoreCount FROM testScores AS ts

【讨论】:

@le dorfier:是的,一般来说这会起作用。但在我的具体情况下,测试的最高分数是测试定义的一部分,当有大量不同最高分数的测试时,有一个表来存储所有可能的分数是不可行的。 你最好把问题记录得更完整。很难想象可能的分数范围超出了定制表的容量的真实情况。【参考方案3】:

mysql 是否支持 set-returning 函数? PostgreSQL 的最新版本有一个函数generate_series(start, stop),它在第一行产生值start,在第二行产生start+1,依此类推,直到stopth 行产生stop。这样做的好处是您可以将此函数放在 FROM 子句中的子选择中,然后加入它,而不是按照 le dorfier 和 Bill Karwin 的建议创建和填充表并加入到该表中。

【讨论】:

很遗憾,MySQL 不支持这种功能。【参考方案4】:

作为一个心理练习,我想出了这个在 MySQL 中生成一个序列。只要正方形框上所有数据库中的表数小于序列的总长度,它就可以工作。不过,我不建议将其用于生产;)

SELECT @n:=@n+1 as n from (select @n:=-1) x, Information_Schema.Tables y, Information_Schema.Tables WHERE @n<20; /* sequence from 0 to 20 inclusive */

【讨论】:

以上是关于MySQL Query - 使用 group-by 时获取丢失的记录的主要内容,如果未能解决你的问题,请参考以下文章

有没有办法提示 mysql 使用 Using index for group-by

使用嵌套的 group-by/having 子句进行复杂连接?

如何使用group-by并获取其他行结果

如何在单个级别上添加新列时使用 pandas group-by?

Hadoop实战-MapReduce之分组(group-by)统计

如何根据 Transact-sql 中的 group-by 子句中的项目设置类别?