文章目录
-
- [1. GROUP BY 分组](#1. GROUP BY 分组)
-
- 简介
- 示例
-
- 1) 不使用聚合函数的 `GROUP BY` 不使用聚合函数的
GROUP BY
) - 2) 使用 `SUM()` 函数的 `GROUP BY` 使用
SUM()
函数的GROUP BY
) - 3) 结合 `JOIN` 子句的 `GROUP BY` 结合
JOIN
子句的GROUP BY
) - 4) 使用 `COUNT()` 函数的 `GROUP BY` 使用
COUNT()
函数的GROUP BY
) - 5) 多列 `GROUP BY` 多列
GROUP BY
) - 6) 使用日期列的 `GROUP BY` 使用日期列的
GROUP BY
)
- 1) 不使用聚合函数的 `GROUP BY` 不使用聚合函数的
- [2. HAVING 子句](#2. HAVING 子句)
-
- 简介
- [HAVING 对比 WHERE](#HAVING 对比 WHERE)
- [PostgreSQL HAVING 子句示例](#PostgreSQL HAVING 子句示例)
-
- 1) 使用 HAVING 子句和 SUM 函数的示例 使用 HAVING 子句和 SUM 函数的示例)
- 2) 使用 HAVING 子句和 COUNT 函数的示例 使用 HAVING 子句和 COUNT 函数的示例)
- [3. PARTITION BY 分区计算](#3. PARTITION BY 分区计算)
-
- 简介
- [PARTITION BY 与 GROUP BY](#PARTITION BY 与 GROUP BY)
1. GROUP BY 分组
简介
GROUP BY
子句用于将SELECT
语句返回的行分组。可以使用聚合函数(如SUM()
或COUNT()
)对每个组进行计算。
基本语法如下:
sql
SELECT
column_1,
column_2,
...,
aggregate_function(column_3)
FROM
table_name
GROUP BY
column_1,
column_2,
...;
PostgreSQL 计算GROUP BY
子句的时间点,在FROM
和WHERE
子句之后, , 以及HAVING
、SELECT
、DISTINCT
、ORDER BY
和LIMIT
子句之前。
示例
1) 不使用聚合函数的 GROUP BY
sql
SELECT
customer_id
FROM
payment
GROUP BY
customer_id;
在这种情况下,GROUP BY
工作方式类似于从结果集中删除重复行的DISTINCT
子句。
2) 使用 SUM()
函数的 GROUP BY
sql
SELECT
customer_id,
SUM (amount)
FROM
payment
GROUP BY
customer_id;
以下语句使用带GROUP BY
子句的ORDER BY
子句对分组进行排序:
sql
SELECT
customer_id,
SUM (amount)
FROM
payment
GROUP BY
customer_id
ORDER BY
SUM (amount) DESC;
3) 结合 JOIN
子句的 GROUP BY
sql
SELECT
first_name || ' ' || last_name full_name,
SUM (amount) amount
FROM
payment
INNER JOIN customer USING (customer_id)
GROUP BY
full_name
ORDER BY amount DESC;
4) 使用 COUNT()
函数的 GROUP BY
sql
SELECT
staff_id,
COUNT (payment_id)
FROM
payment
GROUP BY
staff_id;
GROUP BY
子句将付款中的行分为几组,并按staff_id
列中的值对它们进行分组。对于每个组,它使用COUNT()
函数返回行数。
5) 多列 GROUP BY
以下示例在GROUP BY
子句中使用多个列:
sql
SELECT
customer_id,
staff_id,
SUM(amount)
FROM
payment
GROUP BY
staff_id,
customer_id
ORDER BY
customer_id;
在此示例中,GROUP BY
子句将payment
表中的行按照customer_id
和staff_id
列中的值划分组。对于(customer_id, staff_id)
的每组,使用SUM()
计算总金额。
6) 使用日期列的 GROUP BY
payment_date
是一个时间戳列。要按日期对付款进行分组,您可以使用DATE()
函数首先将时间戳转换为日期,然后按结果日期对付款进行分组:
sql
SELECT
DATE(payment_date) paid_date,
SUM(amount) sum
FROM
payment
GROUP BY
DATE(payment_date);
2. HAVING 子句
简介
HAVING
子句指定分组或聚合的搜索条件。HAVING
子句通常与GROUP BY
子句一起使用,以根据指定条件过滤分组或聚合。
以下语句说明了HAVING
子句的基本语法:
sql
SELECT
column1,
aggregate_function (column2)
FROM
table_name
GROUP BY
column1
HAVING
condition;
还可以添加SELECT
语句的其他子句,例如JOIN
、LIMIT
、FETCH
等。
PostgreSQL 计算HAVING
子句的时间点,在FROM
、WHERE
、GROUP BY
子句之后,在SELECT
、DISTINCT
、ORDER BY
和LIMIT
子句之前。
由于HAVING
子句在SELECT
列表子句之前求值,因此不能在HAVING
子句中使用列别名。因为在计算HAVING
子句时,SELECT
列表子句中指定的列别名还不可用。
HAVING 对比 WHERE
WHERE
子句允许您根据指定条件过滤行。但是,HAVING
子句允许您根据指定条件过滤行组。
换句话说,WHERE
子句应用于行,而HAVING
子句应用于行组。
PostgreSQL HAVING 子句示例
1) 使用 HAVING 子句和 SUM 函数的示例
以下查询使用带有SUM()
函数的GROUP BY
子句来查找每个客户的总金额:
sql
SELECT
customer_id,
SUM (amount)
FROM
payment
GROUP BY
customer_id;
以下语句添加了HAVING
子句来查询支出超过200
的客户:
sql
SELECT
customer_id,
SUM (amount)
FROM
payment
GROUP BY
customer_id
HAVING
SUM (amount) > 200;
2) 使用 HAVING 子句和 COUNT 函数的示例
以下查询使用GROUP BY
子句来查找每个商店的顾客数量:
sql
SELECT
store_id,
COUNT (customer_id)
FROM
customer
GROUP BY
store_id
以下语句添加了HAVING
子句来查找拥有超过 300 名顾客的商店:
sql
SELECT
store_id,
COUNT (customer_id)
FROM
customer
GROUP BY
store_id
HAVING
COUNT (customer_id) > 300;
3. PARTITION BY 分区计算
简介
PARTITION BY
子句是OVER
子句的一部分。它将查询结果集划分为多个分区,使得窗口函数可以在每个分区内独立计算。
基本语法如下:
sql
window_function ( expression ) OVER (
PARTITION BY expression1, expression2, ...
order_clause
frame_clause
)
可以指定一个或多个列或表达式来对结果集进行分区。这些表达式必须引用 FROM
子句中的列,不能引用 SELECT
列表中的表达式或别名。
PARTITION BY
子句的表达式可以是列表达式、标量子查询或标量函数。请注意,标量子查询和标量函数始终返回单个值。
如果省略 PARTITION BY
子句,则整个结果集将被视为单个分区。
PARTITION BY 与 GROUP BY
GROUP BY
子句通常与聚合函数(如SUM()
或AVG()
)结合使用。GROUP BY
子句会汇总和计算每组的总和或平均值,从而减少返回的行数。
例如,以下语句返回按部门划分的员工平均工资:
sql
SELECT
department_id,
ROUND(AVG(salary)) avg_department_salary
FROM
employees
GROUP BY
department_id
ORDER BY
department_id;
下图显示了结果:
PARTITION BY
子句将结果集划分为多个分区,并更改窗口函数的计算方式。PARTITION BY
子句不会减少返回的行数。
以下语句返回员工的工资及其所在部门的平均工资:
sql
SELECT
first_name,
last_name,
department_id,
ROUND(AVG(salary) OVER (
PARTITION BY department_id
)) avg_department_salary
FROM
employees;
以下是部分输出:
简而言之,GROUP BY
子句是聚合性的,而PARTITION BY
子句是分析型的。