pg内置函数

本文详细介绍了PostgreSQL中的窗口函数,包括sum、avg等常见函数的使用方法,并通过实例展示了如何利用窗口函数解决实际问题。此外,还介绍了行列转换函数的使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、            窗口函数

PG是在8.4以后版本中添加了一些窗口函数的功能,所谓窗口函数就是对分组中的每个行都返回分组结果,而聚合函数则是对分组中的每个组只返回一个分组结果,对于这句话大家可能还不理解,不过没关系,下面通过实例来讲解。

 

1、  PG窗口函数有(黄底的为常用窗口函数):

sum(): 组内求和

avg(): 组内平均

row_number(): 组内排序,不间断,如1,2,3,4,5,6

rank() : 组内排序,会间断,如1,2,2,4,5,6

dense_rank(): 组内排序,但会重复,如1,2,2,3,4,5

first_value(value any)返回窗口框架中的第一个值

last_value(value any)返回窗口框架中的最后一个值

count(*) over(partition by col_name)

max(*) over(partition by col_name)

min(*) over(partition by col_name)

nth_value(value any, nth integer):返回窗口框架中的指定值,如nth_value(salary,2),则表示返回字段salary的第二个窗口函数值

lag(value any [, offset integer [, defaultany ]]):偏移量函数,取滞后值,如lag(column_name,2,0)表示字段偏移量为2,没有则用default值代替,这里是0,不写默认是null

lead(value any [, offset integer [, defaultany ]]):偏移量函数,取提前值,类上

percent_rank():和CUME_DIST(累积分配)函数类似,对于一个组中给定的行来说,在计算那行的序号时(如果存在排序一样的情况,则取排序小的序号),先减1,然后除以n-1(n为组中所有的行数)。该函数总是返回0~1(包括1)之间的数

cume_dist():累积分配,对于一个组中给定的行来说,在计算那行的序号时(如果存在排序一样的情况,则取排序大的序号)然后除以n(n为组中所有的行数)。该函数总是返回0~1(包括1)之间的数

ntile(num_buckets integer):将一个组分为"表达式"的散列表示,例如,如果表达式=4,则给组中的每一行分配一个数(从1到4),如果组中有20行,则给前5行分配1,给下5行分配2等等。如果组的基数不能由表达式值平均分开,则对这些行进行分配时,组中就没有任何percentile的行数比其它percentile的行数超过一行。例如,若表达式=4,行数=21,则percentile=1的有6行,percentile=2的有5行等等

 

2、  构建实例所需要的数据,如下:

DROPTABLEIFEXISTS empsalary;

CREATETABLE empsalary(

  depname varchar,

  empno bigint,

  salary int,

  enroll_date date

);

INSERTINTO empsalaryVALUES('develop',10,5200,'2007/08/01');

INSERTINTO empsalaryVALUES('sales',1,5000,'2006/10/01');

INSERTINTO empsalaryVALUES('personnel',5,3500,'2007/12/10');

INSERTINTO empsalaryVALUES('sales',4,4800,'2007/08/08');

INSERTINTO empsalaryVALUES('sales',6,5500,'2007/01/02');

INSERTINTO empsalaryVALUES('personnel',2,3900,'2006/12/23');

INSERTINTO empsalaryVALUES('develop',7,4200,'2008/01/01');

INSERTINTO empsalaryVALUES('develop',9,4500,'2008/01/01');

INSERTINTO empsalaryVALUES('sales',3,4800,'2007/08/01');

INSERTINTO empsalaryVALUES('develop',8,6000,'2006/10/01');

INSERTINTO empsalaryVALUES('develop',11,5200,'2007/08/15');

 

3、  sum():统计各部门的总薪水,窗口函数的结果如下:

SELECTSUM(salary)OVER(PARTITIONBY depname),* FROM empsalary;


聚合函数的结果如下:

SELECTSUM(salary),depnameFROM empsalaryGROUPBY depname;


从上面两个语句返回的结果可以看出,聚合函数只返回各个分组的汇总结果,而窗口函数则是在原表展现的基础上返回所在部门的汇总结果,有了此函数我们就可以很简单的解决一个业务场景,求每个人薪水在整个部分中的比例,如下

SELECT *,

salary/(SUM(salary)OVER(PARTITION BYdepname))::numeric(10,2)

FROM empsalary;

当然不用此函数也能解决这个业务问题,但是写法稍复杂,性能稍差。

 

4、  avg() 统计部门的平均薪水

SELECTAVG(salary)OVER(PARTITIONBY depname),* FROM empsalary;

 

5、  row_number()\rank()\dense_rank(),组内排序函数,按部门统计薪水从低到高排名:

--如果部门有相同的薪水排名也不重复

SELECTROW_NUMBER()OVER(PARTITIONBY depname ORDERBY salary),*

FROMempsalary;


--如果部门有相同的薪水排名重复,但是接下来的一个排名会间断

SELECTRANK()OVER(PARTITIONBY depname ORDERBY salary),*

     FROM empsalary;


--如果部门有相同的薪水排名重复,但是接下来的一个排名不会间断

SELECTDENSE_RANK()OVER(PARTITIONBY depname ORDERBY salary),*

     FROM empsalary;

 

6、  first_value\last_value\ nth_value 取组内指定值

--取各个部门最高薪水

SELECT first_value(salary)OVER(PARTITIONBY depname ORDERBY salaryDESCROWSBETWEENUNBOUNDEDPRECEDINGANDUNBOUNDEDFOLLOWING),

        *

FROM empsalary;


--取各个部门最低薪水

SELECT last_value(salary)OVER(PARTITIONBY depname ORDERBY salaryDESCROWSBETWEENUNBOUNDEDPRECEDINGANDUNBOUNDEDFOLLOWING),

        *

FROM empsalary;


--取各个部门第二高薪

SELECT nth_value(salary,2)OVER(PARTITIONBY depname ORDERBY salaryDESCROWSBETWEENUNBOUNDEDPRECEDINGANDUNBOUNDEDFOLLOWING),

        *

FROM empsalary;


7、  lag\lead 取组内偏移行值

--部门薪水向后偏移2

SELECT LAG(salary,2,NULL)OVER(PARTITIONBY depname ORDERBY salaryDESC),

*

FROM empsalary;


--部门薪水向前偏移2

SELECT LEAD(salary,2,NULL)OVER(PARTITIONBY depname ORDERBY salaryDESC),

*

FROM empsalary;



8、  percent_rank()\cume_dist()\ntile() 分布函数

SELECT percent_rank()over(PARTITIONBY depname ORDERBY salaryDESC),

        *

  FROM empsalary;


SELECT cume_dist()over(PARTITIONBY depname ORDERBY salaryDESC),

        *

  FROM empsalary;


SELECT ntile(3)over(PARTITIONBY depname ORDERBY salaryDESC),

        *

  FROM empsalary;


9、  其他注意事项,如果一个查询中用到多个分析函数,且窗口属性一样,此时可以简写的方式,例如:

SELECTSUM(salary)OVER (PARTITIONBY depnameORDERBY salaryDESC),

     AVG(salary)OVER (PARTITIONBY depnameORDERBY salaryDESC),

   *

  FROM empsalary;

等价于

SELECTSUM(salary)OVER w,      

           AVG(salary)OVER w,

           *

  FROM empsalaryWINDOW wAS(PARTITIONBY depname ORDERBY salaryDESC);

 

 

二、            行列转换函数

regexp_split_to_table:列转行函数;

string_agg:行聚合函数

 

1、  regexp_split_to_table 根据指定的分隔符把一个列中的值拆分成多行

SELECT regexp_split_to_table('hello world   hexq!', E'\\s+');

2、  string_agg 取各部门有哪些薪水

 

 

三、            参考

http://www.postgresql.org/docs/9.1/static/tutorial-window.html

http://www.postgresql.org/docs/9.1/static/sql-expressions.html#SYNTAX-WINDOW-FUNCTIONS

http://www.postgresql.org/docs/9.1/static/sql-expressions.html

 

### PostgreSQL 内置系统函数 `pg_` 的官方文档和使用示例 #### 函数概述 PostgreSQL 提供了一系列以 `pg_` 开头的内置系统函数,这些函数主要用于管理和查询数据库内部状态、配置以及其他元数据。这类函数通常用于高级管理任务或诊断目的。 #### 查询路径相关函数:`pg_relation_filepath` 此函数返回指定关系(表、索引等)的数据文件存储位置。这对于了解物理存储布局非常有用[^2]: ```sql SELECT pg_relation_filepath('my_table'); ``` 该命令会显示名为 `my_table` 表对应的磁盘上实际存储路径。 #### 插件支持函数:`pg_stat_statements` 虽然严格来说这不是一个标准的 `pg_` 系统函数,但是作为一个重要的性能分析工具插件的一部分,它同样值得关注。通过加载 `pg_stat_statements` 扩展模块可以获取 SQL 语句执行统计信息,有助于优化查询性能[^4]: 为了激活并利用这一特性,在超级用户权限下运行如下指令: ```sql CREATE EXTENSION IF NOT EXISTS pg_stat_statements; -- 启用后可以通过下面的查询来查看统计数据 SELECT * FROM pg_stat_statements LIMIT 10; ``` 上述例子展示了如何限制输出到最近十条记录以便快速浏览。 #### 自定义过程语言中的应用:PL/pgSQL 中调用 `pg_` 函数 当涉及到更复杂的逻辑处理时,可以在 PL/pgSQL 这样的过程中直接嵌入对各种 `pg_` 类型函数的调用,实现动态行为控制或者基于特定条件的操作自动化[^3]。 例如,编写一段简单的匿名代码块来打印当前服务器版本号: ```plpgsql DO $$ BEGIN RAISE NOTICE 'Current server version is %', pg_version(); END $$ LANGUAGE plpgsql; ``` 请注意这里假设存在这样一个虚构的 `pg_version()` 方法;实际上应当查阅最新版的手册确认具体可用接口名称。 #### 获取更多帮助 对于完整的 `pg_` 函数列表及其详细的参数说明,请参阅 [PostgreSQL 官方文档](https://www.postgresql.org/docs/current/functions-admin.html),其中包含了所有管理员级别操作所需的知识点[^1]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值