Mysql 所选项目不必出现在GROUPBY子句中,也不必在聚合函数中使用

Mysql 所选项目不必出现在GROUPBY子句中,也不必在聚合函数中使用,mysql,sql,group-by,aggregate,Mysql,Sql,Group By,Aggregate,我听说在sql/mysql中,select子句中的项必须出现在GROUPBY子句中,或者在聚合函数中使用,如中所示 然而,下面的例子可能改变了我的想法 两张表: 学生席德是关键 把sid+oid放在一起是关键,oid代表提供id 问题:我想找到每个至少修过2门课的学生的sid、姓名和平均成绩 答复: 结果: 基于必须出现在GROUP BY子句中或在聚合函数中使用,查询应该不正确,因为名称既不在GROUP子句中,也不在聚合函数中 我看了一些帖子,我的理解是,尽管名称既不在group子句中,也不是聚

我听说在sql/mysql中,select子句中的项必须出现在GROUPBY子句中,或者在聚合函数中使用,如中所示

然而,下面的例子可能改变了我的想法

两张表: 学生席德是关键

把sid+oid放在一起是关键,oid代表提供id

问题:我想找到每个至少修过2门课的学生的sid、姓名和平均成绩

答复:

结果:

基于必须出现在GROUP BY子句中或在聚合函数中使用,查询应该不正确,因为名称既不在GROUP子句中,也不在聚合函数中

我看了一些帖子,我的理解是,尽管名称既不在group子句中,也不是聚合函数,但我们按sid分组,sid是键,每个sid只对应一个名称,因此它不会返回sql不知道返回哪个选项的多个选项。为了确认我的理解,如果我再选择一个专栏邮件,它仍然可以;但如果我选择oid,它会给出错误,因为每个sid对应于多个oid

如果这是错误的,有人能纠正我的理解吗?或者对这条语句进行更详细的说明:必须出现在GROUPBY子句中,或者在聚合函数中使用

谢谢

第一次编辑:

顺便说一句,我在MySQL 8.0.17中进行了测试

第二次编辑:

当你阅读下面的答案/评论时,只是一个有用链接的摘要

你被正确地教导了

根据SQL标准,使用GROUP BY时,SELECT子句中可能出现的列分为三类:

GROUPBY子句中包含的列。在这种情况下,您有s.sid。 聚合列。在这种情况下,您有avggrade。 情况1的功能相关列。由于s.sid是表的主键,因此可以包含s.name而不聚合它。 一切都很好

但是,您应该知道,MySQL 5.7.4及更高版本确实允许您以非聚合形式包含其他列。这是MySQL的一个bug/特性,我个人认为它很容易出错。如果您这样做,MySQL将默默地随机选取一个值,而不会聚合它,也不会告诉您

这个功能可以通过使用@Shawn在新版MySQL的注释中指出的ONLY_FULL_GROUP_by配置参数来打开,以允许运行旧的/坏的查询。不过,我会尽量避免使用它。

你的学习是正确的

根据SQL标准,使用GROUP BY时,SELECT子句中可能出现的列分为三类:

GROUPBY子句中包含的列。在这种情况下,您有s.sid。 聚合列。在这种情况下,您有avggrade。 情况1的功能相关列。由于s.sid是表的主键,因此可以包含s.name而不聚合它。 一切都很好

但是,您应该知道,MySQL 5.7.4及更高版本确实允许您以非聚合形式包含其他列。这是MySQL的一个bug/特性,我个人认为它很容易出错。如果您这样做,MySQL将默默地随机选取一个值,而不会聚合它,也不会告诉您


这个功能可以通过使用@Shawn在新版MySQL的注释中指出的ONLY_FULL_GROUP_by配置参数来打开,以允许运行旧的/坏的查询。不过,我会尽量避免使用它。

首先,您应该使用正确的显式连接语法:

这将起作用,因为有一种叫做函数依赖性的东西。基本上,这是标准的一部分,它说:如果按主键或唯一键分组,则可以包含该表中的任何列

是关于这个主题的文件


也就是说,因为数据库知道s.sid是唯一的,所以使用其他列是安全的。这是标准的一部分。据我所知,唯一支持此功能的其他常用数据库是Postgres。

首先,您应该使用正确的显式连接语法:

这将起作用,因为有一种叫做函数依赖性的东西。基本上,这是标准的一部分,它说:如果按主键或唯一键分组,则可以包含该表中的任何列

是关于这个主题的文件


也就是说,因为数据库知道s.sid是唯一的,所以使用其他列是安全的。这是标准的一部分。据我所知,唯一支持这一点的其他常见数据库是Postgres。

mysql将在这方面为您做出推断,而所有其他主要dbms将严格执行这一规则。即使在mysql中,我也建议您简单地遵循该规则,以避免任何混淆,但您似乎对此有着完美的理解。@AaronDietz不知道其他供应商的情况,但在mysql中,当GROUP BY子句中包含非索引列时,可能会出现性能问题。请参阅:控件this,顺便说一句。it
在mysql 8中,默认情况下是打开的。。。这篇博文很古老,但直到今天仍然相关,它可以澄清围绕FULL_GROUP_BY和SQL标准的所有误解和神话:mysql将在这方面为您做出推断,而所有其他主要dbms将严格执行该规则。即使在mysql中,我也建议您简单地遵循该规则,以避免任何混淆,但您似乎对此有着完美的理解。@AaronDietz不知道其他供应商的情况,但在mysql中,当GROUP BY子句中包含非索引列时,可能会出现性能问题。请参阅:此控件,顺便说一句,它在mysql 8中默认打开。。。这篇博文很古老,但直到今天仍然相关,它可以澄清关于FULL_GROUP_BY和SQL标准的所有误解和神话:MySQL 5.7.5+运行SQL_模式,只有FULL_GROUP_BY能够正确地实现ANSI/ISO SQL 1999标准对函数依赖规则检测的重新分级,据我所知……MySQL 5.7.5+运行SQL_模式据我所知,只有_FULL_GROUP_BY正确地实现了ANSI/ISO SQL 1999函数依赖规则检测的标准重新分级……谢谢,这非常有用。有一件事我不明白,为什么显式连接比cartisian产品更好,在本例中,它们执行相同的功能,可能是因为速度问题?易读性,因为很明显这是内部连接,在MySQL优化中,这些显式连接将再次成为逗号连接@Kenny,因为逗号连接仅支持交叉连接/内部连接结果,而MySQL中的显式连接支持交叉/左/右/内部连接,因此如果需要其他结果,可以更简单地更改查询。@RaymondNijland谢谢。我也刚刚找到了谢谢,非常有用。有一件事我不明白,为什么显式连接比cartisian产品更好,在本例中,它们执行相同的功能,可能是因为速度问题?易读性,因为很明显这是内部连接,在MySQL优化中,这些显式连接将再次成为逗号连接@Kenny,因为逗号连接仅支持交叉连接/内部连接结果,而MySQL中的显式连接支持交叉/左/右/内部连接,因此如果需要其他结果,可以更简单地更改查询。@RaymondNijland谢谢。我也刚刚找到它
sid  | name | email
========================
99901| mike | mike@a.edu
99902| jane | jane@b.edu
99903| peter| pete@b.edu
sid  | oid| grade
==================
99901| 1  | 100
99901| 2  | 30
99901| 3  | 40
99902| 4  | 100
99902| 5  | 100
99902| 6  | 40
99903| 6  | 95
select s.sid, name, avg(grade) as average
from Student as s, Took as t
where s.sid = t.sid
group by s.sid
having count(*) >= 2;
sid  | name | avgerage
=======================
99901| mike | 56.6667
99902| jane | 80.0000
select s.sid, s.name, avg(grade) as average
from Student s join
     Took t
     on s.sid = t.sid
group by s.sid
having count(*) >= 2;