pg内置函数

一、            窗口函数

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

猜你喜欢

转载自blog.csdn.net/wenzhihui_2010/article/details/44240373