分区函数partition by的基本用法【转载】

news/2024/12/2 21:11:26/文章来源:https://www.cnblogs.com/xyh9039/p/18580296

本章将和大家分享分区函数partition by的基本用法(此处以MySQL为例)。废话不多说,下面我们直接进入主题。

一、建表语句

-- 创建商品表
CREATE TABLE commodity (id int NOT NULL PRIMARY KEY COMMENT '主键',position VARCHAR(50) COMMENT '位置(商品放置的货架)',type VARCHAR(50) COMMENT '类型',price DECIMAL(10, 2) COMMENT '价格'
) COMMENT='商品表';-- 初始化数据
INSERT INTO commodity VALUES (1, '1-001', '苹果', 8.00);
INSERT INTO commodity VALUES (2, '2-002', '苹果', 10.00);
INSERT INTO commodity VALUES (3, '3-003', '苹果', 12.00);
INSERT INTO commodity VALUES (6, '1-001', '橘子', 5.00);
INSERT INTO commodity VALUES (7, '1-001', '橙子', 6.00);
INSERT INTO commodity VALUES (8, '3-003', '橙子', 8.00);
INSERT INTO commodity VALUES (10, '2-002', '菠萝', 10.00);
INSERT INTO commodity VALUES (9, '2-002', '香蕉', 5.00);
INSERT INTO commodity VALUES (4, '1-001', '苹果', 12.00);
INSERT INTO commodity VALUES (5, '1-001', '香蕉', 5.00);

二、窗口函数

1、partition by窗口函数 和 group by分组的区别

partition by关键字是分析性函数的一部分,它和聚合函数(如group by)不同的地方在于它能返回一个分组中的多条记录,而聚合函数一般只有一条反映统计值的记录。

partition by用于给结果集分组,如果没有指定那么它把整个结果集作为一个分组。

partition by与group by不同之处在于前者返回的是分组里的每一条数据,并且可以对分组数据进行排序操作。后者只能返回聚合之后的组的数据统计值的记录。

partition by相比较于group by,能够在保留全部数据的基础上,只对其中某些字段做分组排序(类似excel中的操作),而group by则只保留参与分组的字段和聚合函数的结果;简单来说窗口函数对部分数据进行排序、计算等操作,group by对一组值进行聚合,即窗口函数是每一行都会保留,group by是从多行浓缩为少数行。

2、窗口函数基本语法

<窗口函数> over (partition by<用于分组的列名> order by <用于排序的列名>)

3、窗口函数

专用窗口函数:rank(), dense_rank(), row_number()
聚合函数:sum(), max(), min(), count(), avg() 等

三、窗口函数的使用

1、over函数的写法

-- 先对 type 中相同的进行分区,在 type 中相同的情况下对 price 进行排序
over(partition by type order by price desc)

2、专用窗口函数 rank() 和 row_number() 以及 dense_rank()

SELECT *,rank() over(partition by type order by price desc) as  mm from commodity;
SELECT *,row_number() over(partition by type order by price desc) as  mm from commodity;
SELECT *,dense_rank() over(partition by type order by price desc) as  mm from commodity;

从以上结果来看:

rank()函数:如果存在并列名次的行,会占用下一个名次的位置,比如苹果的组内排名【1,2,3,4】,但是由于有两个是并列的,所以显示的排名是【1,1,3,4】,其中 2 的位置还是被占用了。 

row_number()函数:不考虑并列的情况,此函数即使遇到了 price 相同的情况,还是会默认排出一个先后来。 

dense_rank()函数:如果存在并列名次的行,不会占用下一个名次的位置,例如:图片的最后显示的是【1,1,2,3】。  

3、聚合函数作为窗口函数

1)sum()

SELECT *,sum(price) over(partition by type order by price) as sum  from commodity;

在进行求和的时候是这样的,当前行的 sum 值是组内当前行与其组内当前行之前所有行的和,例如红色圈出来的数据,橙子第一行是 6 ,第二行是两行的和 6 +8 = 14,同样的红色圈出来的 苹果的也是同样的道理。需要注意的是当在排序出现相同的时候,同样的都是 12 或者 同样的都是 5 无法进行区分所以在计算的时候会把两个或多个值都加进去,这样也就是 橙色圈出来的部分了 从 8 => 8+10 = 18 => 18+12+12 = 42 =>18+12+12 = 42 ,大概就是这个意思,下文会告诉大家如何解决这种问题 (rows between unbounded preceding and current row)。

我们来多看几种排序的结果是否符合上面的描述:

-- order by type
SELECT *,sum(price) over(partition by type order by type) as sum  from commodity;
-- order by position
SELECT *,sum(price) over(partition by type order by position) as sum  from commodity;
-- order by id
SELECT *,sum(price) over(partition by type order by id) as sum  from commodity;

2)max(), min(), avg(), count()

SELECT *,sum(price) over(partition by type order by price) as sum,max(price) over(partition by type order by price) as max,min(price) over(partition by type order by price) as min,avg(price) over(partition by type order by price) as avg,count(price) over(partition by type order by price) as count
from commodity;

我们可以看到,不管是sum(), avg() 还是min(), max(), count() 他们在窗口函数中,都是对自身记录以及位于自身记录之前的数据进行聚合,求和、求平均、最小值、最大值等。所以,聚合函数作为窗口函数的时候可以在每一行的数据里直观的看到,截止到本行数据统计数据是多少,也可以看出每一行数据对整体的影响。(注意:数据重复的除外,有点特殊)也就是说 sum(), max(), min(), avg(), count() 都是类似的。

4、rows 与 range

rows是物理窗口,即根据order by子句排序后,取的前N行及后N行的数据计算(与当前行的值无关,只与排序后的行号相关)。

range是逻辑窗口,是指定当前行对应值的范围取值,列数不固定,只要行值在范围内,对应列都包含在内。 

通俗点来讲就是说:rows 取的时候是取当前行的前几行以及后几行,包括当前行在内一起进行计算的;而 range 不受行的限制,他跟当前行的值有关,当前行的值减去几,加上几,这个范围内的值都是要进行计算的数据,具体例子如下所示:

-- 在当前行往前1行,往后2行,一共4行范围内进行计算
rows between 1 preceding and 2 following-- 在当前行的数值往前1个数值,往后2个数值,进行计算,范围不一定,因为可能会出现重复值
range between 1 preceding and 2 following
-- rows 
SELECT *,sum(price) over(partition by type order by price rows between 1 preceding and 2 following) as sum from commodity where type = '苹果';
-- 第一行 8 ,前一行没有,后两行是10、12 => 8 + 10 + 12 = 30
-- 第二行是 10 ,前一行8,后两行是12、12 => 8 + 10 + 12 + 12 = 42
-- 第三行是 12 ,前一行10,后两行只有一个12 => 10 + 12 + 12 = 34
-- 第四行是 12 ,前一行12,后两行没有 => 12 + 12 = 24

-- range 
SELECT *,sum(price) over(partition by type order by price range between 1 preceding and 2 following) as sum from commodity where type = '苹果';
-- 第一行 8 ,往前一个数值 8-1 = 7,往后两个数值 8+2 = 10 --> 7 <= price <= 10  --> 8 + 10 = 18
-- 第二行 10 ,往前一个数值 10-1 = 9,往后两个数值 10+2 = 12 --> 9 <= price <= 12  --> 10 + 12 + 12 = 34
-- 第三行 12 ,往前一个数值 12-1 = 11,往后两个数值 12+2 = 14 --> 11 <= price <= 14  --> 12 + 12 = 24
-- 第四行 12 ,往前一个数值 12-1 = 11,往后两个数值 12+2 = 14 --> 11 <= price <= 14  --> 12 + 12 = 24

5、unbound 和 current row

-- 在当前行往前1行,往后2行,一共4行范围内进行计算
rows between 1 preceding and 2 following-- 在当前行的数值往前1个数值,往后2个数值,区间内进行计算,行的范围不一定,因为可能会出现重复值
range between 1 preceding and 2 following

between ... and ... 后面的数字可以随着需求进行替换,当然也可以使用 unbound 和 current row;其中 unbounded 表示不做限制current row 表示当前行

-- 按照分组内全部行求和,不做任何限制
rows between unbounded preceding and unbounded following-- 从分组内排序的起始行到当前行
rows between unbounded preceding and current row-- 按照分组内全部行求和,不做任何限制
range between unbounded preceding and unbounded following -- 从分组内排序的起始行的值到当前行的值
range between unbounded preceding and current row -- rows between unbounded preceding and unbounded following
SELECT *,sum(price) over(partition by type order by price rows between unbounded preceding and unbounded following) as sum from commodity where type = '苹果';-- rows between unbounded preceding and current row
SELECT *,sum(price) over(partition by type order by price rows between unbounded preceding and current row) as sum from commodity where type = '苹果';-- range between unbounded preceding and unbounded following
SELECT *,sum(price) over(partition by type order by price range between unbounded preceding and unbounded following) as sum from commodity where type = '苹果';-- range between unbounded preceding and current row
SELECT *,sum(price) over(partition by type order by price range between unbounded preceding and current row) as sum from commodity where type = '苹果';

按照分组内全部行求和,不做任何限制,如下:

从分组内排序的起始行到当前行,如下:

按照分组内全部行求和,不做任何限制,如下:

从分组内排序的起始行的值到当前行的值,如下:

6、first_value(), last_valus(), lag(), lead()

-- 取出分组后的第一个值
first_value(字段) over(partition byorder by …)
-- 取出分组后的最后一个值
last_value(字段) over(partition byorder by …)-- 取出分组后的第一个值
SELECT *,first_value(price) over(partition by type order by price) as mm  from commodity;
-- 取出分组后的最后一个值
SELECT *,last_value(price) over(partition by type order by price) as mm  from commodity;-- 取出分组后前第n行的数据
lag(expresstion,<offset>,<default>) over(partition byorder by …)
-- 取出分组后后第n行的数据
lead(expresstion,<offset>,<default>) over(partition byorder by …)-- 取分组后的前第2行的数据/后第2行的数据,默认值设置为0
SELECT *,lag(price,2,0) over(partition by type order by price) as mm  from commodity;
SELECT *,lead(price,2,0) over(partition by type order by price) as mm  from commodity;-- 第一个参数:要取的字段
-- 第二个参数:取排序后的第几条记录
-- 第三个参数:缺省值,如果后面的记录取不到值就默认取第三个参数的值,注意参数的类型要与第一个参数所取字段的类型保持一致,不传的话默认为空
SELECT *,lag(price,1,0) over(partition by type order by price) as lagval,lead(price,1,0) over(partition by type order by price) as leadval  from commodity;-- 注:具体的sql输出结果上文放置了建表语句,可以执行一下,自己体验体验!!!

7、preceding 和 following

preceding:往前,following:往后,这两个窗口函数不仅可以实现滑窗求和(指定rows范围)或者指定范围内数据求和(指定range范围),也可以用来计算移动平均值:

SELECT *,sum(price) over(partition by type order by price) as sum,avg(price) over(partition by type order by price) as avg,
avg(price) over(partition by type order by price rows 2 preceding) as avg2 from commodity where type = '苹果';

 

本文转载自博文:https://blog.csdn.net/weixin_44711823/article/details/135966741

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/845629.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JavaSwing外观美化

系统可选风格 windows风格: com.sun.java.swing.plaf.windows.WindowsLookAndFeelwindows Classic风格: com.sun.java.swing.plaf.windows.WindowsClassicLookAndFeel Metal风格 ( Swing默认) :avax.swing.plaf.metal.MetalLookAndFeel Motif风格 : com.sun.java.swing.plaf…

网络架构

二层交换机电脑通过网线与交换机连接,形成局域网 发送信息时,电脑将信息发给交换机广播,传给其他电脑。 路由器为了避免广播风暴,引出路由器,通过路由器连接每个交换机 路由器上会配置网关,从而识别每个局域网,将消息发到特定的局域网中

MySQL底层概述—9.ACID与事务

大纲 1.ACID之原子性 2.ACID之持久性 3.ACID之隔离性 4.ACID之一致性 5.ACID的关系 6.事务控制演进之排队 7.事务控制演进之排它锁 8.事务控制演进之读写锁 9.事务控制演进之MVCC 10.事务隔离级别之隔离级别的类型 11.事务隔离级别之和锁的关系 12.事务隔离级别之隔离级别的控制…

信息安全概论复习4

数字签字和身份识别报文鉴别(接收方鉴别报文真伪)报文源鉴别(发方鉴别)报文宿鉴别(收方鉴别)报文时间性鉴别(能够挫败重播攻击) 初始向量法(事先约定一组初始向量Zi,Zi作为初始向量链接加密第i份报文Mi,只有对应才能还原,重点在加密)时间参数法(类似时间戳,第i份报文…

【知识】模拟退火

模拟退火算法!模拟退火 概念:温度(步长):初始温度 \(T\)终止温度衰减系数 $ 0 \sim 1$随机选择一个点: \(f(新点) - f(当前点) = \Delta E\)\(\Delta E < 0\) 跳到新点 \(\Delta E>0\) 以一定概率跳过去,概率为 \(e^{- \frac{\Delta E}{T}}\)过程如下图:题型:A…

实验五 C语言指针应用编程

实验五 C语言指针应用编程 实验任务1——数组求最大最小值 #include <stdio.h> #define N 5 void input(int x[], int n); void output(int x[], int n); void find_min_max(int x[], int n, int* pmin, int* pmax); int main() {int a[N];int min, max;printf("录入…

使用Tauri创建桌面应用

当前是在 Windows 环境下 1.准备系统依赖项Microsoft C++ 构建工具WebView2 (Windows10 v1803 以上版本不用下载,已经默认安装了)下载安装 Rust 下载安装 Rust 需要重启终端或者系统重新打开cmd,键入rustc --version,出现 rust 版本号,说明安装成功 2.开始 #npm npm create…

【windows工作合集】 远程连接出现问题记录

问题记录:由于需求要登录本地windows的虚拟机 但是在输入用户信息/密码都正确的情况下出现上面截图的问题 于是就百度进行查阅解决--主要就是说我这边机器可能是因为系统更新或者一些注册表的问题导致信息对不上,所以被认为无法登录 (系统更新。微软系统补丁的更新将 CredSSP…

AGC032 VP记录

A 17:35 +0 B 39:51 +0 C 80:28 +4 A.Limited Insertion 简要题面: 最初有一个空序列,每次操作选定一个 \(i\) 并把 \(i\) 插入到位置 \(i\) ,给定最终序列,构造一种合法方案或者输出 -1 。 \(n \leq 100\) 做法: 简单思考发现每次操作出来的数一定从后往前对应了最终序列…

高级语言程序设计第十次作业

代码写的最长的一题,写了十五分钟,数据类型还写错了使用ftell与fseek的组合来计算字节数,跟上面的一题类似这题因为我没创建相关的文件所以输出是这样,但是创建了之后是可以成功写入的可以将输入内容复制通过c语言程序这个也是复制的一个用法同样通过ftell与fseek来计算字节…

H5-15 H5里面的CSS

1、CSS 简介使用CSS的目的就是让网页具有美观一致的页面 2、CSS概念CSS (Cascading Style Sheets)层叠样式表,又叫级联样式表,简称样式表CSS文件后缀名为 .cssCSS用于HTML文档中元素样式的定义 3、为什么需要CSS使用css的目的就是让网页具有美观一致的页面 4、语法CSS规则由…

实验5 继承和多态

实验任务三 源码1 #pragma once2 #include<iostream>3 #include<string>4 5 using std::string;6 using std::cout;7 using std::endl;8 9 //电子宠物类 10 class MachinePets { 11 private: 12 string nickname; 13 public: 14 MachinePets(const string&…