暂无图片
暂无图片
1
暂无图片
暂无图片
暂无图片

【每日分享】2022.08.15 窗口函数

原创 Maleah 2022-08-15
391

PG 窗口函数

窗口函数:基于结果集进行计算,将计算的结果合并到输出的结果集上,并返回多行。

1、语法

function_name ([expression[,expression ...]]) [filter (where filter_clause )] over (window_definition)

window_definition语法:

[ existing_window_name ] [ partition by expression [, ...]] [ order by expression [asc | desc | using operator] [nulls {first | last}] [, ...]] [ frame_clause ]
  • over:窗口函数的关键字。决定查询中的哪些行被分离出来由窗口函数处理
  • partition by:对查询返回的结果集进行分组,之后窗口函数处理分组的数据
  • order by:设定结果集的分组数据排序
  • 窗口帧:对于每一行,在它的分区中的行集被称为他的窗口帧
-- 创建测试函数
create table score(id serial primary key,subject character varying(32),stu_name character varying(32),score numeric(3,0));
insert into score(subject,stu_name,score) values('Chinese','aaa',70),('Chinese','bbb',70),('Chinese','ccc',80),('English','aaa',75),('English','bbb',90),('English','ccc',60),('Math','aaa',80),('Math','bbb',99),('Math','ccc',65);
postgres=# select * from score;
 id | subject | stu_name | score
----+---------+----------+-------
  1 | Chinese | aaa      |    70
  2 | Chinese | bbb      |    70
  3 | Chinese | ccc      |    80
  4 | English | aaa      |    75
  5 | English | bbb      |    90
  6 | English | ccc      |    60
  7 | Math    | aaa      |    80
  8 | Math    | bbb      |    99
  9 | Math    | ccc      |    65
(9 rows)

2、avg() over()

-- 查询每名学生成绩并且显示课程的平均分
postgres=# select a.*,b.avg_score from score as a left join (select subject,avg(score) as avg_score from score group by subject) as b on a.subject=b.subject;    id | subject | stu_name | score |      avg_score
----+---------+----------+-------+---------------------
  1 | Chinese | aaa      |    70 | 73.3333333333333333
  2 | Chinese | bbb      |    70 | 73.3333333333333333
  3 | Chinese | ccc      |    80 | 73.3333333333333333
  4 | English | aaa      |    75 | 75.0000000000000000
  5 | English | bbb      |    90 | 75.0000000000000000
  6 | English | ccc      |    60 | 75.0000000000000000
  7 | Math    | aaa      |    80 | 81.3333333333333333
  8 | Math    | bbb      |    99 | 81.3333333333333333
  9 | Math    | ccc      |    65 | 81.3333333333333333
(9 rows)

-- 窗口函数
postgres=# select subject,stu_name,score,avg(score) over(partition by subject) from score;
 subject | stu_name | score |         avg
---------+----------+-------+---------------------
 Chinese | aaa      |    70 | 73.3333333333333333
 Chinese | bbb      |    70 | 73.3333333333333333
 Chinese | ccc      |    80 | 73.3333333333333333
 English | aaa      |    75 | 75.0000000000000000
 English | bbb      |    90 | 75.0000000000000000
 English | ccc      |    60 | 75.0000000000000000
 Math    | aaa      |    80 | 81.3333333333333333
 Math    | bbb      |    99 | 81.3333333333333333
 Math    | ccc      |    65 | 81.3333333333333333
(9 rows)

3、row_number()

对结果集分组后的数据标注行号,从1开始

postgres=# select row_number() over (partition by subject order by score desc),* from score;
 row_number | id | subject | stu_name | score
------------+----+---------+----------+-------
          1 |  3 | Chinese | ccc      |    80
          2 |  1 | Chinese | aaa      |    70
          3 |  2 | Chinese | bbb      |    70
          1 |  5 | English | bbb      |    90
          2 |  4 | English | aaa      |    75
          3 |  6 | English | ccc      |    60
          1 |  8 | Math    | bbb      |    99
          2 |  7 | Math    | aaa      |    80
          3 |  9 | Math    | ccc      |    65
(9 rows)

-- 不指定 partition 属性
postgres=# select row_number() over (order by id),* from score;                  
row_number | id | subject | stu_name | score
------------+----+---------+----------+-------
          1 |  1 | Chinese | aaa      |    70
          2 |  2 | Chinese | bbb      |    70
          3 |  3 | Chinese | ccc      |    80
          4 |  4 | English | aaa      |    75
          5 |  5 | English | bbb      |    90
          6 |  6 | English | ccc      |    60
          7 |  7 | Math    | aaa      |    80
          8 |  8 | Math    | bbb      |    99
          9 |  9 | Math    | ccc      |    65
(9 rows)

4、rank()

当组内某行字段值相同时,行号重复并且行号产生间隙

postgres=# select rank() over (partition by subject order by score),* from score;
 rank | id | subject | stu_name | score
------+----+---------+----------+-------
    1 |  2 | Chinese | bbb      |    70
    1 |  1 | Chinese | aaa      |    70
    3 |  3 | Chinese | ccc      |    80
    1 |  6 | English | ccc      |    60
    2 |  4 | English | aaa      |    75
    3 |  5 | English | bbb      |    90
    1 |  9 | Math    | ccc      |    65
    2 |  7 | Math    | aaa      |    80
    3 |  8 | Math    | bbb      |    99
(9 rows)

5、dense_rank()

和rank()函数相似,主要区别为当组内某行字段值相同时,虽然行号相同,但行号不产生嫌隙

postgres=# select dense_rank() over (partition by subject order by score),* from score;
 dense_rank | id | subject | stu_name | score
------------+----+---------+----------+-------
          1 |  2 | Chinese | bbb      |    70
          1 |  1 | Chinese | aaa      |    70
          2 |  3 | Chinese | ccc      |    80
          1 |  6 | English | ccc      |    60
          2 |  4 | English | aaa      |    75
          3 |  5 | English | bbb      |    90
          1 |  9 | Math    | ccc      |    65
          2 |  7 | Math    | aaa      |    80
          3 |  8 | Math    | bbb      |    99
(9 rows)

6、lag()

获取行偏移offset那行某个字段的数据

lag(value anycompatible[,offset integer[,default anycompatible ]]) -- value:要返回记录的字段 -- offset:偏移量,默认为1 -- default:如果不存在 offset 便宜的行时用默认值填充,default 默认值是 null

示例:

-- 查询 score 表并获取向上偏移一行记录的 id 值
postgres=# select lag(id,1) over(),* from score;
 lag | id | subject | stu_name | score
-----+----+---------+----------+-------
     |  1 | Chinese | aaa      |    70
   1 |  2 | Chinese | bbb      |    70
   2 |  3 | Chinese | ccc      |    80
   3 |  4 | English | aaa      |    75
   4 |  5 | English | bbb      |    90
   5 |  6 | English | ccc      |    60
   6 |  7 | Math    | aaa      |    80
   7 |  8 | Math    | bbb      |    99
   8 |  9 | Math    | ccc      |    65
(9 rows)

-- 查询 score 表并获取向上偏移两行行记录的 id 值,并指定默认值
postgres=# select lag(id,-2,9999) over(),* from score;
 lag  | id | subject | stu_name | score
------+----+---------+----------+-------
    3 |  1 | Chinese | aaa      |    70
    4 |  2 | Chinese | bbb      |    70
    5 |  3 | Chinese | ccc      |    80
    6 |  4 | English | aaa      |    75
    7 |  5 | English | bbb      |    90
    8 |  6 | English | ccc      |    60
    9 |  7 | Math    | aaa      |    80
 9999 |  8 | Math    | bbb      |    99
 9999 |  9 | Math    | ccc      |    65
(9 rows)

7、first_value()

读取结果集每一个分组的第一行数据的字段值

postgres=# select first_value(score) over(partition by subject),* from score;
 first_value | id | subject | stu_name | score
-------------+----+---------+----------+-------
          70 |  1 | Chinese | aaa      |    70
          70 |  2 | Chinese | bbb      |    70
          70 |  3 | Chinese | ccc      |    80
          75 |  4 | English | aaa      |    75
          75 |  5 | English | bbb      |    90
          75 |  6 | English | ccc      |    60
          80 |  7 | Math    | aaa      |    80
          80 |  8 | Math    | bbb      |    99
          80 |  9 | Math    | ccc      |    65
(9 rows)

8、last_value()

读取结果集每一个分组的最后一行数据的字段值

postgres=# select last_value(score) over(partition by subject),* from score;
 last_value | id | subject | stu_name | score
------------+----+---------+----------+-------
         80 |  1 | Chinese | aaa      |    70
         80 |  2 | Chinese | bbb      |    70
         80 |  3 | Chinese | ccc      |    80
         60 |  4 | English | aaa      |    75
         60 |  5 | English | bbb      |    90
         60 |  6 | English | ccc      |    60
         65 |  7 | Math    | aaa      |    80
         65 |  8 | Math    | bbb      |    99
         65 |  9 | Math    | ccc      |    65
(9 rows)

9、nth_value()

获取结果集每一个分组的指定行数据的字段值

语法:nth_value(value any,nth integer)

  • value:指定表的字段
  • nth:指定结果集分组数据中的第几行,如果不存在则返回空
postgres=# select nth_value(score,2) over(partition by subject),* from score;
 nth_value | id | subject | stu_name | score
-----------+----+---------+----------+-------
        70 |  1 | Chinese | aaa      |    70
        70 |  2 | Chinese | bbb      |    70
        70 |  3 | Chinese | ccc      |    80
        90 |  4 | English | aaa      |    75
        90 |  5 | English | bbb      |    90
        90 |  6 | English | ccc      |    60
        99 |  7 | Math    | aaa      |    80
        99 |  8 | Math    | bbb      |    99
        99 |  9 | Math    | ccc      |    65
(9 rows)

10、窗口函数别名的使用

如需多次使用窗口函数,可以使用窗口函数别名

语法:select ... from ... window window_name as (window_defination)[,...]

示例:

postgres=# select avg(score) over(r),sum(score) over(r),* from score window r as (partition by subject);
         avg         | sum | id | subject | stu_name | score
---------------------+-----+----+---------+----------+-------
 73.3333333333333333 | 220 |  1 | Chinese | aaa      |    70
 73.3333333333333333 | 220 |  2 | Chinese | bbb      |    70
 73.3333333333333333 | 220 |  3 | Chinese | ccc      |    80
 75.0000000000000000 | 225 |  4 | English | aaa      |    75
 75.0000000000000000 | 225 |  5 | English | bbb      |    90
 75.0000000000000000 | 225 |  6 | English | ccc      |    60
 81.3333333333333333 | 244 |  7 | Math    | aaa      |    80
 81.3333333333333333 | 244 |  8 | Math    | bbb      |    99
 81.3333333333333333 | 244 |  9 | Math    | ccc      |    65
(9 rows)
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

文章被以下合辑收录

评论