Nic*_*ick 2 mysql sql database
我正在学习大学数据库,并负责找到大学课程的最低平均考试成绩.我已经提出了两个解决方案,但我希望你们这里的专家可以帮助我:
什么是最好/最有效的解决方案?
解决方案1:
SELECT courses.name , MIN(avg_grade)
FROM (SELECT courseCode, AVG(grade) as avg_grade
FROM exams
GROUP BY courseCode) avg_grades, courses
WHERE courses.code = avg_grades.courseCode
Run Code Online (Sandbox Code Playgroud)
解决方案2:
SELECT name, min(avg_grade)
FROM (SELECT courses.name, AVG(grade) as avg_grade
FROM courses
LEFT JOIN exams on exams.courseCode = courses.code
GROUP BY courseCode) mytable
Run Code Online (Sandbox Code Playgroud)
而且我一直在考虑JOIN或LEFT JOIN在这里使用是否正确?
您的两个查询不同,因此您无法真正比较效率,您的第二个查询将返回没有检查结果的课程记录.假设您将LEFT JOIN切换为INNER以使查询具有可比性,那么我希望第一个查询稍微更高效,因为它只有一个派生表,第二个查询有两个:
解决方案1:
ID SELECT_TYPE TABLE TYPE POSSIBLE_KEYS KEY KEY_LEN REF ROWS FILTERED EXTRA
1 PRIMARY ALL 5 100
1 PRIMARY courses ALL 5 100 Using where; Using join buffer
2 DERIVED exams ALL 5 100 Using temporary; Using filesort
Run Code Online (Sandbox Code Playgroud)
解决方案2:
ID SELECT_TYPE TABLE TYPE POSSIBLE_KEYS KEY KEY_LEN REF ROWS FILTERED EXTRA
1 PRIMARY ALL 5 100
2 DERIVED courses ALL 5 100 Using temporary; Using filesort
2 DERIVED exams ALL 5 100 Using where; Using join buffer
Run Code Online (Sandbox Code Playgroud)
然而,我会根据你自己的执行计划来检查这一点,因为我只是一个关于SQL Fiddle的快速示例.
我想借此机会建议不要使用ANSI-89隐式连接语法,它在20多年前被ANSI-92标准中的显式连接语法所取代.Aaron Bertrand撰写了一篇关于切换原因的精彩文章,我不会在此重复.
另一个更重要的一点是,您的查询不是确定性的,也就是说您可以运行相同的查询两次并获得2个不同的结果,即使数据没有潜在的变化.
以您的第二个查询为例(尽管您会注意到SQL-Fiddle上的两个查询都是错误的),您有一个子查询,MyTable如下所示:
SELECT courses.name, AVG(grade) as avg_grade
FROM courses
LEFT JOIN exams on exams.courseCode = courses.code
GROUP BY courseCode
Run Code Online (Sandbox Code Playgroud)
这样返回一个表:
Name | avg_grade
--------+--------------
A | 10
B | 5
C | 6
D | 7
E | 2
Run Code Online (Sandbox Code Playgroud)
您可能希望整个查询返回:
Name | avg_grade
--------+--------------
E | 2
Run Code Online (Sandbox Code Playgroud)
由于2是最低平均等级,E是与之对应的名称.你会错的,正如这里所示,你可以看到这实际上会返回:
Name | avg_grade
--------+--------------
A | 2
Run Code Online (Sandbox Code Playgroud)
实际上正在发生的是MySQL正在正确计算最小avg_grade,但是由于你没有向该组添加任何列,因此你已经给了Name它选择任何值的MySQL Carte blanche .
为了得到你想要的输出,我认为你需要:
SELECT courses.name , MIN(avg_grade)
FROM ( SELECT courseCode, AVG(grade) as avg_grade
FROM exams
GROUP BY courseCode
) avg_grades
INNER JOIN courses
ON courses.code = avg_grades.courseCode
GROUP BY courses.Name;
Run Code Online (Sandbox Code Playgroud)
或者,如果您只想要平均成绩最低的课程,请使用:
SELECT courseCode, AVG(grade) as avg_grade
FROM exams
GROUP BY courseCode
ORDER BY avg_grade
LIMIT 1;
Run Code Online (Sandbox Code Playgroud)
请原谅我将要做的事情的懒惰,但我之前已经解释了很多这个问题,现在有一个标准的回复我发布以解释MySQL分组的问题.它比上面更详细,希望进一步解释.
MySQL隐式分组
我建议尽可能避免MySQL提供的隐式分组,这意味着包括选择列表中的列,即使它们不包含在聚合函数或group by子句中.
想象一下下面的简单表(T):
ID | Column1 | Column2 |
----|---------+----------|
1 | A | X |
2 | A | Y |
Run Code Online (Sandbox Code Playgroud)
在MySQL中你可以写
SELECT ID, Column1, Column2
FROM T
GROUP BY Column1;
Run Code Online (Sandbox Code Playgroud)
这实际上打破了SQL标准,但它适用于MySQL,但问题是它是非确定性的,结果是:
ID | Column1 | Column2 |
----|---------+----------|
1 | A | X |
Run Code Online (Sandbox Code Playgroud)
没有或多或少不正确
ID | Column1 | Column2 |
----|---------+----------|
2 | A | Y |
Run Code Online (Sandbox Code Playgroud)
所以你所说的是给我一行,每个不同的值Column1,两个结果集都满足,所以你怎么知道你会得到哪一个?嗯,你没有,似乎是一个相当流行的误解,你可以添加和ORDER BY子句来影响结果,所以例如以下查询:
SELECT ID, Column1, Column2
FROM T
GROUP BY Column1
ORDER BY ID DESC;
Run Code Online (Sandbox Code Playgroud)
确保您获得以下结果:
ID | Column1 | Column2 |
----|---------+----------|
2 | A | Y |
Run Code Online (Sandbox Code Playgroud)
因为ORDER BY ID DESC,但事实并非如此(如此处所示).
在MySQL的文件状态:
服务器可以自由选择每个组中的任何值,因此除非它们相同,否则所选的值是不确定的.此外,添加ORDER BY子句不会影响每个组中值的选择.
因此,即使您有一个订单,但在每个组选择一行之后才适用,并且这一行是不确定的.
SQL-Standard允许选择列表中的列不包含在GROUP BY中或聚合函数中,但是这些列必须在功能上依赖于GROUP BY中的列.例如,示例表中的ID是PRIMARY KEY,因此我们知道它在表中是唯一的,因此以下查询符合SQL标准并且将在MySQL中运行并且当前在许多DBMS中失败(在编写Postgresql时)是我所知道的最接近正确实施标准的DBMS):
SELECT ID, Column1, Column2
FROM T
GROUP BY ID;
Run Code Online (Sandbox Code Playgroud)
由于ID对于每一行都是唯一的,因此Column1每个ID 只能有一个值,一个值Column2对于每行返回的内容没有歧义.
编辑
从SQL-2003-Standard(5WD-02-Foundation-2003-09 - 第346页) - http://www.wiscorp.com/sql_2003_standard.zip
15)如果T是分组表,那么令G为T的分组列的集合.在每个包含的列中,引用T列的每个列引用应引用某些在功能上依赖于G或应包含的列C在聚合查询为QS的聚合参数中.
| 归档时间: |
|
| 查看次数: |
123 次 |
| 最近记录: |