前几天我学了一些关于SQL的简单知识:
SELECT c FROM myTbl GROUP BY C
结果与:
SELECT DISTINCT C FROM myTbl
我好奇的是,SQL引擎处理命令的方式有什么不同,还是它们真的是一样的东西?
我个人更喜欢独特的语法,但我相信这更多是出于习惯而不是其他原因。
编辑:这不是一个关于聚合的问题。理解了GROUP BY与聚合函数的使用。
前几天我学了一些关于SQL的简单知识:
SELECT c FROM myTbl GROUP BY C
结果与:
SELECT DISTINCT C FROM myTbl
我好奇的是,SQL引擎处理命令的方式有什么不同,还是它们真的是一样的东西?
我个人更喜欢独特的语法,但我相信这更多是出于习惯而不是其他原因。
编辑:这不是一个关于聚合的问题。理解了GROUP BY与聚合函数的使用。
当前回答
我预计在执行上可能会有细微的差异。 我检查了Oracle 10g中两个功能相同的查询的执行计划:
core> select sta from zip group by sta;
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 58 | 174 | 44 (19)| 00:00:01 |
| 1 | HASH GROUP BY | | 58 | 174 | 44 (19)| 00:00:01 |
| 2 | TABLE ACCESS FULL| ZIP | 42303 | 123K| 38 (6)| 00:00:01 |
---------------------------------------------------------------------------
core> select distinct sta from zip;
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 58 | 174 | 44 (19)| 00:00:01 |
| 1 | HASH UNIQUE | | 58 | 174 | 44 (19)| 00:00:01 |
| 2 | TABLE ACCESS FULL| ZIP | 42303 | 123K| 38 (6)| 00:00:01 |
---------------------------------------------------------------------------
中间的操作略有不同:“HASH GROUP BY”和。“HASH唯一”,但估计成本等是相同的。然后,我在跟踪的情况下执行这些操作,两者的实际操作计数是相同的(除了第二个操作由于缓存而不需要进行任何物理读取)。
但我认为,由于操作名称不同,执行将遵循不同的代码路径,这可能会带来更大的差异。
出于这个目的,我认为您应该更喜欢DISTINCT语法。这不仅仅是习惯,它更清楚地表明了查询的目的。
其他回答
如果你使用的GROUP BY没有任何聚合函数,那么在内部它将被视为DISTINCT,所以在这种情况下,GROUP BY和DISTINCT之间没有区别。
但是,当提供DISTINCT子句时,最好使用它来查找唯一的记录,因为GROUP BY的目标是实现聚合。
它们具有不同的语义,即使它们恰好在特定数据上具有相同的结果。
仅仅从重复删除功能的角度来看有什么不同
除了与DISTINCT不同的事实,GROUP BY允许每个组聚合数据(这已经被许多其他答案提到),在我看来最重要的区别是,这两个操作“发生”在SELECT语句中执行的操作的逻辑顺序中的两个非常不同的步骤。
以下是最重要的操作:
FROM(包括JOIN、APPLY等) 在哪里 GROUP BY(可以删除重复项) 聚合 有 窗口函数 选择 DISTINCT(可以删除重复项) UNION, INTERSECT, EXCEPT(可删除重复项) 命令 抵消 限制
如您所见,每个操作的逻辑顺序影响着可以用它做什么以及它如何影响后续操作。特别地,GROUP BY操作“发生在”SELECT操作(投影)之前的事实意味着:
它不依赖于投影(这可能是一个优势) 它不能使用来自投影的任何值(这可能是一个缺点)
1. 它不依赖于投影
一个不依赖于投影的例子是,如果你想计算不同值的窗口函数:
SELECT rating, row_number() OVER (ORDER BY rating) AS rn
FROM film
GROUP BY rating
当对Sakila数据库运行时,会产生:
rating rn
-----------
G 1
NC-17 2
PG 3
PG-13 4
R 5
DISTINCT很难做到这一点:
SELECT DISTINCT rating, row_number() OVER (ORDER BY rating) AS rn
FROM film
这个查询是“错误的”,结果如下:
rating rn
------------
G 1
G 2
G 3
...
G 178
NC-17 179
NC-17 180
...
这不是我们想要的。DISTINCT操作“发生在”投影之后,因此我们不能再删除DISTINCT评级,因为窗口函数已经计算和投影了。为了使用DISTINCT,我们必须嵌套查询的这一部分:
SELECT rating, row_number() OVER (ORDER BY rating) AS rn
FROM (
SELECT DISTINCT rating FROM film
) f
旁注:在这种特殊情况下,我们还可以使用DENSE_RANK()
SELECT DISTINCT rating, dense_rank() OVER (ORDER BY rating) AS rn
FROM film
2. 它不能使用来自投影的任何值
SQL的缺点之一是有时冗长。出于与我们之前看到的相同的原因(即操作的逻辑顺序),我们不能“轻松地”根据我们所投射的东西进行分组。
这是无效的SQL:
SELECT first_name || ' ' || last_name AS name
FROM customer
GROUP BY name
这是有效的(重复表达式)
SELECT first_name || ' ' || last_name AS name
FROM customer
GROUP BY first_name || ' ' || last_name
这也是有效的(嵌套表达式)
SELECT name
FROM (
SELECT first_name || ' ' || last_name AS name
FROM customer
) c
GROUP BY name
我曾在一篇博客文章中更深入地讨论过这个话题
通常我们可以使用DISTINCT来消除表中特定列上的重复项。
在'GROUP BY'的情况下,我们可以应用聚合函数像 AVG, MAX, MIN, SUM和COUNT在特定列和获取 列名和它的聚合函数在同一列上产生。
例子:
select specialColumn,sum(specialColumn) from yourTableName group by specialColumn;
在使用方面,GROUP BY用于对要计算的行进行分组。DISTINCT将不做任何计算。它不会显示重复的行。
如果我想要呈现无重复的数据,我总是使用DISTINCT。
如果我想做计算,比如合计芒果的总数,我会使用GROUP BY