赞
踩
PostgreSQL 是一款强大的开源数据库管理系统,具有丰富的特性和功能。其中,聚合查询是一项非常重要的功能之一。通过聚合查询,我们可以在数据库中对数据进行统计和分析,获取有用的信息。
在本文中,我们将深入探讨 PostgreSQL 的聚合查询功能,包括常见的聚合函数、GROUP BY 子句、HAVING 子句、CASE 表达式、聚合函数进行数据分析、WITH 子句、窗口函数、GROUPING SETS、CUBE、ROLLUP 和过滤器等,以及相关的示例代码。读完本文,您将能够熟练地使用 PostgreSQL 进行聚合查询,并获取您所需要的数据。
聚合查询是一种对数据进行处理的方式,可以从数据库中获取统计信息和汇总数据。每个聚合查询通常会使用一个或多个聚合函数,例如 COUNT
、AVG
、SUM
、MAX
和 MIN
。这些聚合函数可以对数据库中的数据进行统计和分析,从而让用户能够更好地了解数据。
本文将介绍 PostgreSQL 中的一些常见聚合函数,以及如何使用 GROUP BY 子句、HAVING 子句、CASE 表达式、WITH 子句、窗口函数、GROUPING SETS
、CUBE
和 ROLLUP
进行聚合查询。
COUNT 函数
用于计算查询结果集中行的数量。该函数可以用于计算表中的所有行、满足特定条件的行、或者某个字段的值的数量。COUNT 函数有两种语法:
SELECT COUNT(*) FROM table_name;
SELECT COUNT(column_name) FROM table_name;
其中,第一种语法用于计算表中的所有行的数量,而第二种语法用于计算某个字段的值的数量。
AVG
函数用于计算某个字段的平均值。例如,您可以使用以下语句计算一张表中某个字段的平均值:
SELECT AVG(column_name) FROM table_name;
SUM
函数用于计算某个字段的总和。例如,您可以使用以下语句计算一张表中某个字段的总和:
SELECT SUM(column_name) FROM table_name;
MAX
函数用于获取某个字段的最大值。例如,您可以使用以下语句获取一张表中某个字段的最大值:
SELECT MAX(column_name) FROM table_name;
MIN
函数用于获取某个字段的最小值。例如,您可以使用以下语句获取一张表中某个字段的最小值:
SELECT MIN(column_name) FROM table_name;
DISTINCT
函数用于获取某个字段的不同值。例如,您可以使用以下语句获取一张表中某个字段的不同值:
SELECT DISTINCT column_name FROM table_name;
GROUP BY
可以将结果集按照一个或多个列进行分组, 对每个分组进行聚合计算或筛选.
SELECT col1, col2, ...
FROM table_name
GROUP BY col1, col2, ...;
其中, col1, col2, … 表示需要进行分组的列.
SELECT col1, SUM(col2), AVG(col3)
FROM table_name
GROUP BY col1;
上述语句将结果按照col1列分组,并对每个分组的 col2列求和并计算AVG(col3).
HAVING
子句用于在 GROUP BY 分组语句执行后对分组后的结果集进行筛选.
SELECT col1, SUM(col2), AVG(col3)
FROM table_name
GROUP BY col1
HAVING condition;
其中, condition是对聚合函数结果的筛选条件.
SELECT col1, SUM(col2), AVG(col3)
FROM table_name
GROUP BY col1
HAVING SUM(col2) > 1000;
上述语句将结果按照 col1 分组, 检查每个分组的 col2是否大于1000, 如果符合条件,则返回该分组以及对应的 SUM(col2), AVG(col3) 值.
CASE 表达式
是一种条件判断语句,常常用于在查询中基于某个条件执行不同的操作.
SELECT col1,
(CASE WHEN condition1 THEN result1
WHEN condition2 THEN result2
...
ELSE default_result END) AS new_col
FROM table_name;
其中,condition1/2/3… 是条件, result1/2/3/… 是执行结果,default_result 是在所有条件都不匹配时返回的结果.
SELECT col1,
(CASE
WHEN col2 < 10 THEN 'small'
WHEN col2 < 100 THEN 'medium'
ELSE 'large' END) AS size_group
FROM table_name;
其中,对于 col2小于10的情况,size_group 返回’small’,对于 10 < col2 < 100的情况,size_group返回’medium’,对于 col2大于100的情况, size_group 返回’large’.
SELECT COUNT(*)
FROM table_name;
上述语句将返回 table_name 表中的总记录数.
SELECT COUNT(*), AVG(col1), MIN(col2), MAX(col2)
FROM table_name;
上述语句将返回 table_name 表中记录的总数,col1列的平均值,col2列的最小值和最大值.
SELECT col1, COUNT(*), AVG(col2)
FROM table_name
GROUP BY col1;
上述语句对 table_name表中的col1列进行分组,并对每个分组分别计算记录数(COUNT(*))和col2列的平均值(AVG(col2)).
SELECT col1, COUNT(*)
FROM table_name
GROUP BY col1
HAVING COUNT(*) > 10;
上述语句对 table_name表中的col1列进行分组,并计算每个分组的记录数(COUNT(*)),仅返回记录数大于10的分组.
WITH 子句常常用于在一个 SQL 查询中定义一个临时的结果集,然后在主查询中使用这个结果集.
WITH table_alias AS (
SELECT col1, col2, ...
FROM table_name
WHERE condition
)
SELECT ...
FROM table_alias JOIN other_table ON ...
WHERE other_condition;
其中, table_alias 是定义的这个临时结果集的别名.
WITH revenue AS (
SELECT order_date, SUM(amount) AS total_revenue
FROM orders
GROUP BY order_date
)
SELECT order_date, total_revenue
FROM revenue
WHERE total_revenue > 100000;
上述语句使用` WITH 子句定义了 revenue 临时结果集,该结果集中包含订单日期和该日期的总收入(total_revenue)。然后对 revenue 进行筛选,只返回总收入超过100000的记录.
窗口函数是一种 SQL 函数,它可以在查询结果上执行聚合、排序、排名等计算。和普通的聚合函数不同的是,窗口函数不会根据所有的行计算,而是根据特定的窗口(一组行)进行计算。
使用窗口函数可以将计算逻辑从 SELECT 语句中分离出来,提高查询的可读性和灵活性。
常见的窗口函数有:
ROW_NUMBER
:返回给定行的行号,按照指定的列进行排序。RANK
:计算每一行在排序结果中的排名,具有相等值时会跳过下一个排名。DENSE_RANK
:计算每一行在排序结果中的排名,相等值时具有相同排名。NTILE(n)
:将排序后的行划分成 n 组,返回每个组的组号。LAG
:返回指定列在某一行前面若干行的值。LEAD
:返回指定列在某一行后面若干行的值。FIRST_VALUE
:返回指定列在一组行中的第一个值。LAST_VALUE
:返回指定列在一组行中的最后一个值。SUM、AVG、MAX、MIN
等聚合函数:作为窗口函数时,计算特定窗口内的值。这里演示一个使用 ROW_NUMBER 函数排名的查询:
SELECT name, score, ROW_NUMBER() OVER (ORDER BY score DESC) as rank
FROM scores;
窗口函数的语法格式如下:
SELECT column_1, column_2, ..., aggregate_function(column_n)
OVER (
[PARTITION BY partition_expression, ... ]
[ORDER BY sort_expression [ASC|DESC], ... ]
[ROWS { UNBOUNDED | value | BETWEEN value1 AND value2 }]
) AS column_alias
FROM table_name;
OVER()
用于对计算进行定义分区和排序,然后使用一个或多个分析函数来执行计算。分区和排序可以是选项,但分析函数必须包含在OVER()中。
PARTITION BY
关键字用于定义要执行的分区列,这些列用于将数据分为不同的组。ORDER BY用于定义窗口函数计算的排序方式。ROWS用于定义计算的行数范围。
ROWS子句
有三种操作:UNBOUNDED、value和BETWEEN value1 AND value2。UNBOUNDED表示所选行之间的所有行。value可以是数字,表示从当前行开始的指定行数。BETWEEN value1 AND value2表示在当前行之前和之后的行数之间选择所有行。
关于窗口函数更加复杂的用法,可以参考以下这个例子。考虑一个 orders 表,其中包含一个订单 ID、一个客户 ID、一个订单日期和订单金额。现在,我们需要找到每个客户的分组内前两个订单的总金额、平均金额和总数量。
使用窗口函数 ONVER
和 RANK
可以实现这个查询,示例代码如下:
SELECT customer_id,
SUM(amount) OVER (PARTITION BY customer_id ORDER BY order_date ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING) AS total_amount_of_last_two_orders,
AVG(amount) OVER (PARTITION BY customer_id ORDER BY order_date ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING) AS average_amount_of_last_two_orders,
COUNT(*) OVER (PARTITION BY customer_id ORDER BY order_date ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING) AS count_of_last_two_orders
FROM orders
WHERE RANK() OVER (PARTITION BY customer_id ORDER BY order_date) <= 2
ORDER BY customer_id;
该查询首先使用 WHERE 子句筛选出要分析的订单,再使用 RANK 排序,并使用 PARTITION BY 语句对每个客户分别计算分组的结果。窗口函数的部分分别对每个客户的前两个订单计算总金额、平均金额和总数量。
GROUPING SETS
是一种用于在查询中生成多个汇总行的技术。它允许您在 GROUP BY 子句中指定多个汇总级别,使您可以按照不同的维度进行分组和聚合。
与 GROUPING SETS 类似,CUBE
允许您在一个查询中生成多个汇总行。但是,CUBE 提供了更为灵活的聚合选项,可以用于生成更多的子总体和层次结构。
ROLLUP
也是一种用于在查询中生成多个汇总行的技术。与 GROUPING SETS 和 CUBE 不同,ROLLUP 只允许您按照已知的维度列表进行分组,并生成这些维度的子总体和总体。
GROUPING SETS 允许在一个 SELECT 语句中指定多个 GROUP BY 子句,使查询结果可以按多列进行分组。例如,我们可以查询销售数据按年份、月份和产品类别进行分类:
SELECT year, month, category, SUM(sales)
FROM sales
GROUP BY GROUPING SETS((year, month), category);
上面的查询中,GROUPING SETS((year, month), category)
指定了两个分组级别:按年份和月份进行分组,以及按产品类别进行分组。这个查询的结果将会包含两个分组级别的聚合数据。
GROUPING SETS
提供了一种简单而直接的方法来处理有多个分组级别的聚合查询。当您需要按多个维度分组时,GROUPING SETS
可以大大简化查询语句。
CUBE 能够对给定的一组列生成所有可能的 GROUPING SETS,即在 GROUP BY 子句中指定每个列及每个列组合。例如,我们可以查询销售数据按年份、月份和产品类别所有可能的组合进行分类:
SELECT year, month, category, SUM(sales)
FROM sales
GROUP BY CUBE(year, month, category);
上面的查询是用 CUBE(year, month, category)
来指定三个分组维度。这将生成所有可能的 GROUP BY 组合,包括根据每个列、每个列的所有可能的两种组合、每个列的所有可能的三种组合,以及全部列。
这个查询的结果将包括所有可能的组合的聚合数据。CUBE 提供了一种方便的方法来生成跨越多列的聚合数据,同时减少了需要编写的 GROUP BY 子句的数量。
ROLLUP 在 GROUP BY 子句中指定一组列,并生成基于该组列和它们的子级的 GROUPING SETS。例如,我们可以查询销售数据按年份、月份和产品类别的组合情况来对数据进行分类:
SELECT year, month, category, SUM(sales)
FROM sales
GROUP BY ROLLUP(year, month, category);
上面的查询是用 ROLLUP(year, month, category)
来指定三个分组维度。这将创建一系列 GROUPING SETS,产生一个汇总列组合的层级结构。
这个查询的结果将包括所有列组合以及它们的子级的聚合数据。ROLLUP 提供了一种紧凑而直观的方法来生成基于多个列的聚合数据。
SQL 中的聚合函数通常会返回一个结果集,而使用过滤器可以从结果集中过滤掉不符合条件的数据。这使得 SQL 查询更加灵活和强大,并且可以节省内存和计算时间。
使用过滤器需要在 GROUP BY 子句后面使用 HAVING 子句。HAVING 子句的语法与 WHERE 子句的语法类似,但它作用于聚合结果而不是原始数据。
以下是一个简单的查询示例,该查询使用 HAVING 过滤器来过滤销售额大于 100000 的行:
SELECT region, SUM(sales)
FROM sales
GROUP BY region
HAVING SUM(sales) > 100000;
在 GROUP BY 子句中使用过滤器时,请遵循以下语法格式:
SELECT column1, column2, ..., columnN, aggregate_function(column), ...
FROM table
GROUP BY column1, column2, ..., columnN
HAVING condition;
HAVING 子句包括一个或多个聚合函数和一个条件运算符。任何 HAVING 子句中的列都必须在 GROUP BY 子句中显示列出。
以下是使用 HAVING 子句的一个示例:
SELECT region, SUM(sales)
FROM sales
GROUP BY region
HAVING SUM(sales) > 100000;
在上面的示例中,HAVING 子句限制了结果集的行数,该子句只返回销售额大于 100000 的记录。
找到所有客户最近30天总销售额超过1000元的记录
SELECT customer_id, SUM(sale_amount) AS total_sales
FROM _sales
WHERE sale_date BETWEEN NOW() - INTERVAL '30 days' AND NOW()
GROUP BY customer_id
HAVING SUM(sale_amount) > 1000;
首先,我们使用SELECT语句选择两个字段:customer_id和SUM(sale_amount),这些字段代表了我们想输出的结果。其中,SUM(sale_amount)
代表了每个客户在过去30天内的总销售额。接下来,我们使用FROM语句指定我们要查询的表格名"_sales"。然后,我们使用WHERE语句来过滤sales_date
字段,只保留在过去30天内的销售记录。然后,我们使用GROUP BY将查询结果按照customer_id
分组,并计算每组的总销售额。最后,我们使用HAVING过滤器来保留那些总销售额大于1000元的记录。
ARRAY_AGG函数是PostgreSQL中的一种聚合函数,它类似于其他统计函数,可以将一组数据汇总成一个数组。在使用该函数时,用户可以指定一个表达式或列名来对数据进行聚合,并返回一个与该列数据类型相同的数组。
在大多数情况下,我们使用SQL来获取某个表中特定列的值,并将其用作数据集。但有时,可能需要将同一列中的值汇总成一个数组。例如,当需要构建一个图表系统时,就有可能将查询结果汇总成可视化图表所需的数据结构,这时ARRAY_AGG函数变得很有用。
此外,ARRAY_AGG函数在处理重复或重复数据值时也非常有用。在这些情况下,用户可以根据该列中的值对数据进行分组,并通过将相同数据值的行汇总为一个数组来进行汇总,这非常适用于统计数据。
ARRAY_AGG可以用于一个或多个表达式或列名。如果多个表达式或列名一起使用,则汇总的结果存储在一个数组中。这种情况下用户可以在查询时指定数组中每个元素的顺序和数据类型。返回的数组中每个元素的数据类型都将与指定的表达式或列名相同。
在使用ARRAY_AGG函数时,一定要注意查询结果数据的大小,以免造成系统负担过重。此外,在进行分组时,也应该根据数据类型以及存储需要仔细考虑该列中可能出现的任何特殊字符或是其他数据类型相关细节。
ARRAY_AGG(expression)
ARRAY_AGG(DISTINCT expression)
其中expression
表示需要组合成数组的值或表达式。如果使用DISTINCT关键字,表示去除重复值,最终生成的数组只包含唯一值。需要注意的是ARRAY_AGG函数只能在GROUP BY子句中使用,用于将分组的结果组合成一个数组。
我们需要编写一个查询,它将所有顾客名称作为第一列,然后对于每个顾客,它将计算他们的总订单数,总花费以及购买的产品列表。
SELECT
customer,
COUNT(*) AS order_count,
SUM(price) AS total_spent,
ARRAY_AGG(product) AS products_purchased
FROM
orders
GROUP BY
customer;
XMLAGG是PostgreSQL聚合函数之一,它可以将查询结果中每一行的列值汇总成一个XML类型的数据。该函数主要用于将相关数据组织成标准格式,以便其他系统或者应用程序进行数据的利用和集成。
在实际应用中,XMLAGG函数可以将同一行中的不同列聚合成一个XML类型的数据,然后嵌入到其他XML文档中。使用该函数可以使得在存储和提交数据时更加高效和方便。
XMLAGG函数的使用方法非常简单,只需在查询语句中使用该函数,将需要汇总的列名作为参数,就可以将查询结果中的每一行的数据汇总为一个XML类型数据。函数的返回结果格式可以指定,并且可以自定义嵌套等级。
虽然XMLAGG函数非常方便,但需要注意的是,在使用该函数时应该考虑到性能和数据存储方面的问题。因为XML类型的数据比普通文本数据会更复杂一些,也会更加占用存储空间。
另外,在处理XML数据时,开发者应该对XML文档的构造和解析进行相应的处理。需要处理XML中出现的特殊字符、编码问题以及优化查询语句等一系列细节问题。
在使用XMLAGG函数时,应该考虑在查询语句中添加可以进一步更新查询结果的其他函数或操作符。例如可以在查询字符串中添加子查询或者添加对其他列使用不同的函数或操作符的操作等,以获得更为完整的查询结果。
XMLAGG(XMLELEMENT(name element_name, expression) ORDER BY expression [separator string])
其中XMLELEMENT用于创建XML元素,expression表示需要组合的值或表达式,element_name表示元素名称,ORDER BY用于指定排序的顺序,separator string表示分隔符。需要注意的是,XMLAGG函数只能在GROUP BY子句中使用,用于将分组的结果组合成一个XML值。
我们需要编写一个查询,它将所有部门名称作为第一列,然后对于每个部门,它将计算工资最高的员工姓名和薪资。
SELECT
department,
MAX(salary) AS max_salary,
XMLAGG(XMLELEMENT(NAME "employee", name)) AS top_employees
FROM
employees
GROUP BY
department;
JSON_AGG函数是PostgreSQL数据库聚合函数的一种类型,它可以将查询结果中每一行的列值汇总成一个JSON类型的数据。该函数主要用于将相关数据组织成标准格式,以便于其他系统或应用程序进行数据的使用和嵌入。
JSON(Abbreviation of JavaScript Object Notation)
是一种轻量级的数据交换格式,其较小的体积和机器读取性成为其广泛应用于RESTful Web服务中的关键因素之一。因此,通过 JSON_AGG 函数汇总数据可以更好地遵循Web开发中的数据格式标准,从而便于前端开发工作的处理和交互。
与XMLAGG函数类似,使用JSON_AGG函数可以将同一行中的不同列聚合为一个JSON格式的数据,并将其嵌入到其他JSON文档中。在实际应用中,使用该函数可以使得在数据存储和提交时更加高效和方便。
JSON_AGG函数的使用方法非常简单,只需在查询语句中使用该函数,将需要汇总的列名作为参数,就可以将查询结果中的每一行数据汇总为一个JSON类型数据。
需要注意的是,在使用JSON_AGG函数时要考虑到JSON文档的构造和解析。这些都需要处理特殊字符、编码问题、嵌套等级等一系列细节问题。对于JSON格式数据的处理,PostgreSQL支持广泛的数据类型和操作,以支持负载增加。
JSON_AGG(expression)
JSON_AGG(DISTINCT expression)
其中expression表示需要组合JSON对象的值或表达式。如果使用DISTINCT关键字,表示去除重复值,最终生成的JSON数组只包含唯一值。需要注意的是JSON_AGG函数只能在GROUP BY子句中使用,用于将分组的结果组合成一个JSON值。
我们需要编写一个查询,它将所有班级作为第一列,然后对于每个班级,它将计算平均成绩,以及所有学生的学科成绩列表,以JSON格式返回。
SELECT
class,
AVG((marks->>'maths')::numeric) AS avg_maths_score,
AVG((marks->>'english')::numeric) AS avg_english_score,
AVG((marks->>'science')::numeric) AS avg_science_score,
JSON_AGG(marks) AS student_marks
FROM
students
GROUP BY
class;
STRING_AGG函数是PostgreSQL中的一种聚合函数,它可以将一列中的各个值以指定的分隔符拼接到一起,返回一个字符串。 在实际应用中,STRING_AGG函数尤其适用于将一个列中的所有数据合并成一个单一的、以逗号或其他指定字符分隔的字符串进行处理。
STRING_AGG函数在处理一些数据储存格式较为复杂的场景时非常有用,它可以更加方便地处理必须以字符串形式进行传输的别记录容器。同时,使用该聚合函数可以减少处理需求,提高数据处理效率,使得查询结果更加清晰简洁。
STRING_AGG(expression [, delimiter])
其中expression表示需要组合的字符串值或表达式,delimiter表示组合字符串的分隔符。参数delimiter是可选的,如果省略,则默认使用逗号。需要注意的是STRING_AGG函数只能在GROUP BY子句中使用,用于将分组的结果组合成一个字符串。
我们需要编写一个查询,它将所有顾客名称作为第一列,然后对于每个顾客,它将计算他们的总订单数,总花费以及购买的产品列表,其中每个产品名称之间用逗号分隔。
SELECT
customer,
COUNT(*) AS order_count,
SUM(price) AS total_spent,
STRING_AGG(product, ', ') AS products_purchased
FROM
orders
GROUP BY
customer;
PERCENTILE_DIS(expression, percentile)
PERCENTILE_CON(expression, percentile) WITHIN GROUP (ORDER BY order_expression)
其中expression表示需要计算百分位的值或表达式,percentile表示所需计算的百分位数,order_expression用于指定百分位数的排序顺序。PERCENTILE_DIS返回一个分布式的近似估计值。PERCENTILE_CON提供了更准确的结果,但需要排序表格的复杂操作。需要注意的是这两个函数只能在SELECT语句中使用。
我们需要编写一个查询,在每个部门中,找到薪资排名前10%的员工(即工资最高的前10%),并计算他们的平均薪资和总薪资。
SELECT
department,
percentile_disc(0.9) within group (order by salary) AS top_10_percentile_salary,
percentile_cont(0.9) within group (order by salary) AS top_10_percentile_salary_cont,
AVG(salary) AS avg_salary,
SUM(salary) AS total_salary
FROM
employees
GROUP BY
department;
解释:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。