在GROUP BY的使用过程中,SELECT 中出现的非组函数的字段必须声明在 GROUP BY 中。
还记得 MySQL零散拾遗(四) 中,提到的 GROUP BY
的使用要点嘛?
SELECT
中出现的非组函数的字段必须声明在 GROUP BY
中。反而,在 GROUP BY
中声明的字段可以不出现在SEELCT
中。
现在就用个案例对其进行解释 o.O
GROUP BY
作用的只有分组列和聚合函数列,其他列不管用,返回的其他列只有对应的第一行
首先,我们来看一个具体的例子:
假设有一个 employees
表,包含以下数据:
employee_id | last_name | job_id | salary |
---|---|---|---|
1 | Smith | CLERK | 1000 |
2 | Johnson | CLERK | 1200 |
3 | Williams | MANAGER | 3000 |
4 | Jones | CLERK | 1100 |
5 | Brown | CLERK | 800 |
现在我们执行以下查询:
SELECT job_id, last_name, MAX(salary)
FROM employees
GROUP BY job_id;
结果如下:
job_id | last_name | MAX(salary) |
---|---|---|
CLERK | Jones | 1200 |
MANAGER | Williams | 3000 |
你可以观察到:
GROUP BY
的作用对象是job_id
列,也就是说查询结果会根据job_id
进行分组。- 在每个分组内,我们使用了聚合函数
MAX(salary)
来获取该分组内工资最高的值。 - 但对于
last_name
列,它并不是分组列也不是聚合函数,因此SELECT
中返回的last_name
值是该分组中第一条记录的last_name
。
也就是说,GROUP BY
作用的是分组列和聚合函数列,其他列只能取该分组中的第一条记录的值。
再来看另一个例子:
SELECT job_id, last_name, salary
FROM employees
GROUP BY job_id, last_name;
结果如下:
job_id | last_name | salary |
---|---|---|
CLERK | Brown | 800 |
CLERK | Jones | 1100 |
CLERK | Johnson | 1200 |
CLERK | Smith | 1000 |
MANAGER | Williams | 3000 |
这里我们在 GROUP BY
中同时指定了 job_id
和 last_name
,因此查询结果中每一行对应一个独特的 job_id
和 last_name
组合,salary
也是该组合的实际值。
总之,GROUP BY
的作用是将查询结果按照指定的列进行分组,分组内使用聚合函数进行计算,而其他非分组列和非聚合函数列则返回该分组中的第一条记录的值。
额…想手动实现一下,但创建表太麻烦了,(⊙﹏⊙)
莫事儿莫事儿,我还找到了对应的 OJ 题,3,2,1,“上链接”
产品销售分析 III
这道题的要求:选出每个售出过的产品 第一年 销售的 产品 id、年份、数量 和 价格
重点在于 第一年,这时候脑子里就出现一个想法(自行脑补那个表情包,哈哈哈哈)直接对product_id
字段进行分组,然后使用 MIN(year)
不就行了嘛!
SELECT product_id, year first_year, quantity, price
FROM sales
GROUP BY product_id
HAVING year = MIN(year);
额,这种做法其实是错误的
对其进行改进改进就行了,使用子查询先把product_id
和year
进行筛选,再进行外层筛选
SELECT product_id, year first_year, quantity, price
FROM sales
WHERE (product_id, year) IN (SELECT product_id, MIN(year)FROM salesGROUP BY product_id
);
还可以使用开窗函数 rank
SELECT product_id, year first_year, quantity, price
FROM (SELECT *,RANK() OVER(PARTITION BY product_id ORDER BY year) as rankingFROM sales
) rank_table
WHERE ranking = 1
对rank
函数进行介绍一下
Rank
开窗函数是 SQL
中一种用于对查询结果集中的行进行 排名 的开窗函数。它可以根据指定的列或表达式对结果集中的行进行排序,并为每一行分配一个排名。在排名过程中,相同的值将被赋予相同的排名,而不同的值将被赋予不同的排名。
当存在并列(相同排序值)时,Rank 会跳过后续排名,并保留相同的排名。
Rank
开窗函数的常见用法是在查询结果中查找前几名(Top N)或排名最高的行。
Rank
开窗函数的语法如下:
RANK() OVER (PARTITION BY 列名1, 列名2, ... -- 可选,用于指定分组列ORDER BY 列名3 [ASC|DESC], 列名4 [ASC|DESC], ... -- 用于指定排序列及排序方式
) AS rank_column
其中,PARTITION BY
子句可选,用于指定分组列,将结果集按照指定列进行分组;ORDER BY
子句用于指定排序列及排序方式,决定了计算 Rank 时的排序规则。AS rank_column
用于指定生成的 Rank
排名列的别名。