首页 > 其他分享 >分区函数partition by的基本用法【转载】

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

时间:2024-12-02 21:24:30浏览次数:7  
标签:over -- 分区 partition 用法 order type price

本章将和大家分享分区函数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 by … order by …)
-- 取出分组后的最后一个值
last_value(字段) over(partition by … order 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 by … order by …)
-- 取出分组后后第n行的数据
lead(expresstion,<offset>,<default>) over(partition by … order 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

标签:over,--,分区,partition,用法,order,type,price
From: https://www.cnblogs.com/xyh9039/p/18580296

相关文章

  • 关于el-cascader 双向绑定值v-model的值为字符串的用法
    常规用法绑定的值为数组,但是项目中需要绑定的值为字符串才好,两种解决方式,方式1:按常规写法来做,最后将数据处理成字符串给后端方式2:直接绑定成字符串,不用来回转换格式方式2比较方便,所以选择方式2来做//dom结构<el-form-itemv-if="form.userType==='subject'"label="登......
  • vxe-form 的基础用法
    vxe-form的基础用法,data指定表单的数据,items用于配置表单的项列表<template><div><vxe-formv-bind="formOptions"@submit="submitEvent"@reset="resetEvent"></vxe-form></div></temp......
  • D85【python 接口自动化学习】- pytest基础用法
    day85pytest指定目录或文件执行测试用例学习日期:20241201学习目标:pytest基础用法--pytest指定目录,文件执行测试用例学习笔记:pytest指定目录或文件执行测试用例终端执行用例pytest不跟目标目录或文件,执行根目录下所有符合规则的测试用例终端执行用例pytest指定......
  • AspectRatio组件的用法
    文章目录1概念介绍2使用方法2.1ClipOval2.2ClipRRect3示例代码我们在上一章回中介绍了AspectRatioWidget相关的内容,本章回中将介绍剪裁类组件(Clip).闲话休提,让我们一起TalkFlutter吧。1概念介绍我们在这里说的剪裁类组件主要是指对子组件进行......
  • MATLAB中listdlg函数用法
    目录语法说明示例显示颜色列表用于进行多选显示当前文件夹文件用于进行单选        listdlg函数的功是创建列表选择对话框。语法[indx,tf]=listdlg('ListString',list)[indx,tf]=listdlg('ListString',list,Name,Value)说明[indx,tf]=listdlg('List......
  • MATLAB中questdlg函数用法
    目录语法说明示例在问题对话框中将用户的选择用整数编码使用TeX设置对话框中的问题的格式        questdlg函数的功能是创建问题对话框。语法answer=questdlg(quest)answer=questdlg(quest,dlgtitle)answer=questdlg(quest,dlgtitle,defbtn)answer......
  • string 的基本用法
    前言string是一个非常常见的数据类型,用于表示文本或字符序列。以下是关于它的详细介绍:string(字符串)是由零个或多个字符组成的有限序列。字符可以是字母、数字、标点符号、空格或其他符号。例如,“Hello”、“123”、“!@#$”等都是字符串。在C++中,string是标准库(<stri......
  • AspectRatio组件的用法
    文章目录1概念介绍2使用方法3示例代码我们在上一章回中介绍了CardWidget相关的内容,,本章回中将介绍AspectRatioWidget.闲话休提,让我们一起TalkFlutter吧。1概念介绍我们将要介绍的AspectRatioWidget是一个布局约束类组件,在二十一章回中介绍过这方面......
  • vxe-table 树形表格的用法详解
    vxe-table树形表格的使用,支持多种数据结构,可以是带有父子结构的数组,也可以带有层级结构的嵌套数据。官网:https://vxetable.cnGitee带有父子结构的平级数据只需要带有父子结构的平级数据,例如:id和parentId,字段名可以任意设置。对于保存到数据库的平级数据非常方便,无需转换就......
  • 请说说什么是分区响应图?
    在前端开发中,「分区响应图」通常指的是一种根据不同的视口(viewport)或设备尺寸,加载不同大小或分辨率的图片的技术。它旨在优化网页性能和用户体验,避免在小型设备上加载过大的图片,从而减少加载时间和带宽消耗。虽然没有一个正式的术语叫做“分区响应图”,但这通常是通过以下几种技......