在多列上使用group by

1497

我理解GROUP BY x的意思。

但是GROUP BY x, y是如何工作的,它又代表什么意思呢?


2
你不会在这个问题所描述的方式中找到它。GROUP BY 子句可以使用一个或多个字段。GROUP BY customer; GROUP BY lastname, firstname; GROUP BY year, store, sku 等。 - Bill
3个回答

2759

Group By X 意思是将所有具有相同 X 值的元素放在一组中。

Group By X, Y 意思是将所有同时具有相同 X 和 Y 值的元素放在一组中。

为了举个例子,假设我们有以下与大学生选课相关的表格:

Table: Subject_Selection

+---------+----------+----------+
| Subject | Semester | Attendee |
+---------+----------+----------+
| ITB001  |        1 | John     |
| ITB001  |        1 | Bob      |
| ITB001  |        1 | Mickey   |
| ITB001  |        2 | Jenny    |
| ITB001  |        2 | James    |
| MKB114  |        1 | John     |
| MKB114  |        1 | Erica    |
+---------+----------+----------+

当你只对subject列使用group by时:

select Subject, Count(*)
from Subject_Selection
group by Subject

您会得到类似如下的内容:

+---------+-------+
| Subject | Count |
+---------+-------+
| ITB001  |     5 |
| MKB114  |     2 |
+---------+-------+

因为ITB001有5个条目,而MKB114有2个条目

如果我们按照两列来进行分组:

select Subject, Semester, Count(*)
from Subject_Selection
group by Subject, Semester

我们会得到这个:

+---------+----------+-------+
| Subject | Semester | Count |
+---------+----------+-------+
| ITB001  |        1 |     3 |
| ITB001  |        2 |     2 |
| MKB114  |        1 |     2 |
+---------+----------+-------+

这是因为当我们按照两列进行分组时,它实际上是在说“将所有主题和学期相同的内容归为一组,然后对每个组计算所有聚合函数(例如:计数、求和、平均值等)。”在这个例子中,当我们进行计数时,有三个人在第一学期修ITB001,而在第二学期只有两个人修这门课。两个修MKB114的人都在第一学期,所以在第二学期没有与“MKB114,第2学期”相匹配的数据(该组内没有数据)。

希望这些解释能让您理解。


38
这是否意味着 GROUP BY A,BGROUP BY B,A 是相同的? - tumchaaditya
66
可以的,它确实可以。我不能确定它们的效率是否相同,但它们会得出相同的结果,是的。 - Smashery
4
这里需要补充一点,GROUP BY a, bGROUP BY a AND b之间存在区别,因为第二个选项只列出了具有完全相同内容而没有“子分组”的分组项。在这种情况下,输出与第一个选项相同。 - Dwza
6
我想补充一点,按列分组的顺序并不重要。在上面的例子中,按学期、科目分组会得到相同的结果。 - user2441441
6
按a、b分组和按b、a分组不会返回相同的结果——行将以不同的顺序显示。 - fanny
显示剩余8条评论

99

在这里,我不仅将解释 GROUP 子句的用途,还将解释聚合函数的用途。

GROUP BY 子句与聚合函数一起使用,可以通过一个或多个列对结果集进行分组。例如:

-- GROUP BY with one parameter:
SELECT column_name, AGGREGATE_FUNCTION(column_name)
FROM table_name
WHERE column_name operator value
GROUP BY column_name;

-- GROUP BY with two parameters:
SELECT
    column_name1,
    column_name2,
    AGGREGATE_FUNCTION(column_name3)
FROM
    table_name
GROUP BY
    column_name1,
    column_name2;

请记住以下顺序:

  1. SELECT (用于从数据库中选择数据)

  2. FROM(子句用于列出表格)

  3. WHERE(子句用于过滤记录)

  4. GROUP BY(子句可在 SELECT 语句中使用,以跨多个记录收集数据,并按一个或多个列对结果进行分组)

  5. HAVING(子句与 GROUP BY 子句结合使用,将返回行的组限制为仅那些满足条件的行)

  6. ORDER BY(关键字用于对结果集进行排序)

如果您正在使用聚合函数,可以使用所有这些,这是必须设置它们的顺序,否则可能会出现错误。

聚合函数包括:

MIN()(返回给定列中最小的值)

MAX()(返回给定列中最大的值)

SUM()(返回给定列中数值的总和)

AVG()(返回给定列的平均值)

COUNT()(返回给定列中值的总数)

COUNT(*)(返回表中行的数量)

关于使用聚合函数的 SQL 脚本示例:

假设我们需要查找总销售额大于 $950 的销售订单。我们结合使用 HAVING 子句和 GROUP BY 子句来完成这个任务:

SELECT 
    orderId, SUM(unitPrice * qty) Total
FROM
    OrderDetails
GROUP BY orderId
HAVING Total > 950;

计算所有订单并按客户ID分组,将结果按升序排序。我们结合使用 COUNT 函数和 GROUP BYORDER BY 子句以及 ASC

SELECT 
    customerId, COUNT(*)
FROM
    Orders
GROUP BY customerId
ORDER BY COUNT(*) ASC;

使用AVG函数结合GROUP BYHAVING子句检索平均单价大于$10的类别:

SELECT 
    categoryName, AVG(unitPrice)
FROM
    Products p
INNER JOIN
    Categories c ON c.categoryId = p.categoryId
GROUP BY categoryName
HAVING AVG(unitPrice) > 10;

使用子查询中的 MIN 函数,获取每个类别最便宜的产品:

SELECT categoryId,
       productId,
       productName,
       unitPrice
FROM Products p1
WHERE unitPrice = (
                SELECT MIN(unitPrice)
                FROM Products p2
                WHERE p2.categoryId = p1.categoryId)

以下将向您展示如何使用子查询中的MAX函数来选择最近的日期项"productDate":
SELECT categoryId,
       productId,
       productName,
       unitPrice,
       productDate
FROM Products p1
WHERE productDate= (
                  SELECT MAX(productDate) 
                  FROM Products p2
                  WHERE p2.categoryId = p1.categoryId)

以下语句将在categoryIdproductId列中具有相同值的行进行分组:
SELECT 
    categoryId, categoryName, productId, SUM(unitPrice)
FROM
    Products p
INNER JOIN
    Categories c ON c.categoryId = p.categoryId
GROUP BY categoryId, productId

4
我们应该把这两列放在哪里?如何基于两个或更多列进行聚合是问题所在。 - Chaitanya Bapat
6
这个回答与问题完全不相关... 这里的问题是如何同时实现“学科”和“学期”的“链式分组”,就像给出的例子一样... - MahNas92
1
最后一个示例向您展示了如何使用聚合函数放置2列。@ChaitanyaBapat - S. Mayol
如果您有更多不想分组的选择列,则此方法在Oracle中无法正常工作。 - Marco
如果使用GROUP BY但没有聚合函数会怎么样? - undefined

4
GROUP BY 带有两个参数的简单解释是寻找相似值对,并在第三列计算它们的数量。以下示例可供参考。此处使用的是1872年至2020年国际足球比赛结果数据集
+----------+----------------+--------+---+---+--------+---------+-------------------+-----+
|       _c0|             _c1|     _c2|_c3|_c4|     _c5|      _c6|                _c7|  _c8|
+----------+----------------+--------+---+---+--------+---------+-------------------+-----+
|1872-11-30|        Scotland| England|  0|  0|Friendly|  Glasgow|           Scotland|FALSE|
|1873-03-08|         England|Scotland|  4|  2|Friendly|   London|            England|FALSE|
|1874-03-07|        Scotland| England|  2|  1|Friendly|  Glasgow|           Scotland|FALSE|
|1875-03-06|         England|Scotland|  2|  2|Friendly|   London|            England|FALSE|
|1876-03-04|        Scotland| England|  3|  0|Friendly|  Glasgow|           Scotland|FALSE|
|1876-03-25|        Scotland|   Wales|  4|  0|Friendly|  Glasgow|           Scotland|FALSE|
|1877-03-03|         England|Scotland|  1|  3|Friendly|   London|            England|FALSE|
|1877-03-05|           Wales|Scotland|  0|  2|Friendly|  Wrexham|              Wales|FALSE|
|1878-03-02|        Scotland| England|  7|  2|Friendly|  Glasgow|           Scotland|FALSE|
|1878-03-23|        Scotland|   Wales|  9|  0|Friendly|  Glasgow|           Scotland|FALSE|
|1879-01-18|         England|   Wales|  2|  1|Friendly|   London|            England|FALSE|
|1879-04-05|         England|Scotland|  5|  4|Friendly|   London|            England|FALSE|
|1879-04-07|           Wales|Scotland|  0|  3|Friendly|  Wrexham|              Wales|FALSE|
|1880-03-13|        Scotland| England|  5|  4|Friendly|  Glasgow|           Scotland|FALSE|
|1880-03-15|           Wales| England|  2|  3|Friendly|  Wrexham|              Wales|FALSE|
|1880-03-27|        Scotland|   Wales|  5|  1|Friendly|  Glasgow|           Scotland|FALSE|
|1881-02-26|         England|   Wales|  0|  1|Friendly|Blackburn|            England|FALSE|
|1881-03-12|         England|Scotland|  1|  6|Friendly|   London|            England|FALSE|
|1881-03-14|           Wales|Scotland|  1|  5|Friendly|  Wrexham|              Wales|FALSE|
|1882-02-18|Northern Ireland| England|  0| 13|Friendly|  Belfast|Republic of Ireland|FALSE|
+----------+----------------+--------+---+---+--------+---------+-------------------+-----+

现在,我将通过GROUP BY操作,将相似的国家(_c7)和赛事(_c5)值对进行分组。

SELECT `_c5`,`_c7`,count(*)  FROM res GROUP BY `_c5`,`_c7`

+--------------------+-------------------+--------+
|                 _c5|                _c7|count(1)|
+--------------------+-------------------+--------+
|            Friendly|  Southern Rhodesia|      11|
|            Friendly|            Ecuador|      68|
|African Cup of Na...|           Ethiopia|      41|
|Gold Cup qualific...|Trinidad and Tobago|       9|
|AFC Asian Cup qua...|             Bhutan|       7|
|African Nations C...|              Gabon|       2|
|            Friendly|           China PR|     170|
|FIFA World Cup qu...|             Israel|      59|
|FIFA World Cup qu...|              Japan|      61|
|UEFA Euro qualifi...|            Romania|      62|
|AFC Asian Cup qua...|              Macau|       9|
|            Friendly|        South Sudan|       1|
|CONCACAF Nations ...|           Suriname|       3|
|         Copa Newton|          Argentina|      12|
|            Friendly|        Philippines|      38|
|FIFA World Cup qu...|              Chile|      68|
|African Cup of Na...|         Madagascar|      29|
|FIFA World Cup qu...|       Burkina Faso|      30|
| UEFA Nations League|            Denmark|       4|
|        Atlantic Cup|           Paraguay|       2|
+--------------------+-------------------+--------+

解释:第一行的意思是南罗德西亚总共举办了11个友谊赛。

注意:在这种情况下,使用计数列是强制性的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接