当前位置: 首页 > 面试题库 >

SQL vs MySQL:有关聚合操作和GROUP BY的规则

苏涵润
2023-03-14
问题内容

下面给出了使用聚合运算符进行非法查询的示例:

查找最年长的水手的姓名和年龄。

考虑以下尝试回答此查询的尝试:

SELECT S.sname, MAX(S.age)
FROM Sailors S

此查询的目的是不仅返回最大年龄,还返回具有该年龄的水手的姓名。但是,此查询在SQL中是非法的-
如果SELECT子句使用聚合操作,那么除非查询包含GROUP BY子句,否则它 只能 使用聚合操作!

一段时间后,在使用MySQL进行练习时,我遇到了类似的问题,并且犯了一个与上述错误类似的错误。但是,MySQL并没有抱怨,只是吐出了一些表,后来发现这些表并不是我所需要的。

上面的查询在SQL中确实是非法的,但在MySQL中是合法的吗?在什么情况下需要进行这样的查询?

问题的进一步阐述:

问题不在于SELECT中提到的所有属性是否也应在GROUP BY中提及。这就是为什么上面的查询在属性中不带任何GROUP
BY的情况下使用归类和属性的聚合操作合法的原因。

假设“水手”表如下所示:

+----------+------+
| sname    | age  |
+----------+------+
| John Doe |   30 |
| Jane Doe |   50 |
+----------+------+

然后查询将返回:

+----------+------------+
| sname    | MAX(S.age) |
+----------+------------+
| John Doe |         50 |
+----------+------------+

现在谁会需要那个?约翰·多伊(John
Doe)不是50岁,他是30岁!正如该书的引文所述,这是首次尝试获得年龄最大的水手的名字和年龄,在本例中为50岁的简·多伊(Jane Doe)。

SQL会说此查询是非法的,但MySQL只会继续并吐出“垃圾”。谁会需要这种结果?为什么MySQL允许新手使用这个小陷阱?


问题答案:

基于 链接其a_horse_with_no_name在评论规定,我在我自己的答案到来:

似乎MySQL的使用GROUP BY的方式与SQL的方式不同,以便允许在功能上仍然依赖于其他包含的列的情况下,从GROUP BY子句中删除列。

假设我们有一个显示银行帐户活动的表格。这不是一个深思熟虑的表,但这是我们仅有的一个表,必须这样做。我们不去追踪金额,而是想象一个帐户从“
0”开始,而是记录到该帐户的所有交易,因此该金额是交易的总和。该表可能如下所示:

+------------+----------+-------------+
| costumerID | name     | transaction |
+------------+----------+-------------+
|       1337 | h4x0r    |         101 |
|         42 | John Doe |         500 |
|       1337 | h4x0r    |        -101 |
|         42 | John Doe |        -200 |
|         42 | John Doe |         500 |
|         42 | John Doe |        -200 |
+------------+----------+-------------+

显然,“名称”在功能上取决于“ costumerID”。(在本html" target="_blank">示例中,另一种方法也是可行的。)

如果我们想知道每个客户的客户编号,名称和当前金额怎么办?

在这种情况下,两个非常相似的查询将返回以下正确结果:

+------------+----------+--------+
| costumerID | name     | amount |
+------------+----------+--------+
|         42 | John Doe |    600 |
|       1337 | h4x0r    |      0 |
+------------+----------+--------+

该查询可以在MySQL中执行,并且根据SQL合法。

SELECT costumerID, name, SUM(transaction) AS amount
FROM Activity
GROUP BY costumerID, name

该查询可以在MySQL中执行,根据SQL而言是 合法的。

SELECT costumerID, name, SUM(transaction) AS amount
FROM Activity
GROUP BY costumerID

以下行将使查询返回并返回错误,因为它现在必须遵循使用聚合操作和GROUP BY的SQL方式:

SET sql_mode = 'ONLY_FULL_GROUP_BY';

允许在MySQL中进行第二个查询的参数似乎是假设,已在SELECT运算中提及但在GROUP BY中未提及的所有列都在聚合操作中使用(对于“
transaction”而言),或者功能上取决于其他包含的列(“名称”的情况)。对于“名称”,我们可以确保为所有组条目选择了正确的“名称”,因为它在功能上依赖于“
costumerID”,因此,每一组costumeID可能只有一个名称。

这种使用GROUP BY的方法似乎很难克服,因为它不会进一步检查GROUP
BY子句中遗漏的内容。人们可以从自己的SELECT语句中选择和选择列,以按照他们认为合适的方式放入GROUP
BY子句,即使包括或不包含任何特定的列也没有意义。

Sailor示例很好地说明了此缺陷。使用聚合运算符(可能与GROUP
BY结合使用)时,返回集中的每个组条目的每个列只有一个值。对于Sailor,由于不使用GROUP
BY子句,因此整个表都放在一个单独的组条目中。该条目需要一个名称和最大年龄。毫不费力地为该条目选择最大年龄,因为MAX(S.age)仅返回一个值。对于S.sname而言,仅在SELECT中提到了wich,现在,在整个Sailor表中,选择的数量就和唯一的sname一样多(本例中为John和Jane
Doe)。MySQL没有 任何
有什么选择的线索,我们什么也没给,它也没有及时刹车,所以它必须选择首先出现的东西,(简·多伊)。如果将两行切换,它实际上会偶然给出“正确答案”。似乎很愚蠢,因为在MySQL中允许这样的事情,如果GROUP
BY子句中遗漏了某些东西,则使用GROUP
BY的查询结果可能会取决于表的顺序。显然,这就是MySQL滚动的方式。但是它仍然不能至少有礼貌地警告我们,因为它由于“有缺陷的”查询而无所适从吗?我的意思是,可以肯定的是,如果对程序给出错误的指令,它可能不会(或不应该)按照您的意愿进行,但是,如果您给出的指令不明确,我当然不会



 类似资料:
  • ZUNIONSTORE destination numkeys key [key ...] [WEIGHTS weight] [AGGREGATE SUM|MIN|MAX] 例如: 127.0.0.1:6379> zrangebyscore votes -inf inf withscores 1) "sina" 2) "1" 3) "google" 4) "5" 5) "baidu" 6) "10

  • 本页展示的操作符用于对整个序列执行算法操作或其它操作,由于这些操作必须等待数据发射完成(通常也必须缓存这些数据),它们对于非常长或者无限的序列来说是危险的,不推荐使用。 rxjava-math 模块的操作符 averageInteger( ) — 求序列平均数并发射 averageLong( ) — 求序列平均数并发射 averageFloat( ) — 求序列平均数并发射 averageDoub

  • GraphX中提供的聚合操作有aggregateMessages、collectNeighborIds和collectNeighbors三个,其中aggregateMessages在GraphImpl中实现,collectNeighborIds和collectNeighbors在 GraphOps中实现。下面分别介绍这几个方法。 1 aggregateMessages 1.1 aggregateM

  • 问题内容: 我有以下数据框,并希望: 分组记录 点心和每一个独特的(每月) 在结果数据框中也包括其余的列 我想我能做到这一点的方法是1:创建一个聚合列,再总结的。 脚本: 当前数据帧: 所需输出: 实际输出: 问题: 如何包含每一行的月份? 如何包含数据框的其余列? 除了又如何求和? 问题答案: 具有功能 创建一个函数并将其传递给。您还需要防止组列成为输出中的索引。 毯 只需调用而无需任何列名。这

  • Average 计算原始Observable发射数字的平均值并发射它 Average操作符操作符一个发射数字的Observable,并发射单个值:原始Observable发射的数字序列的平均值。 这个操作符不包含在RxJava核心模块中,它属于不同的rxjava-math模块。它被实现为四个操作符:averageDouble, averageFloat, averageInteger, avera

  • GroupBy 将一个Observable分拆为一些Observables集合,它们中的每一个发射原始Observable的一个子序列 GroupBy操作符将原始Observable分拆为一些Observables集合,它们中的每一个发射原始Observable数据序列的一个子序列。哪个数据项由哪一个Observable发射是由一个函数判定的,这个函数给每一项指定一个Key,Key相同的数据会被同