partition by语法

partition by是Oracle中的一个分析函数。它的功能有点儿像分组函数group by,但又有较大区别。本文通过示例的方式,介绍一下partition by的用法。
数据准备
建表

create table xzq_person (       --行政区人口表
    province varchar(10),
    city varchar(10),
    persons number(10)
);

插入数据

insert into xzq_person values ('江苏','苏州',10);
insert into xzq_person values ('江苏','南京',20);
insert into xzq_person values ('浙江','杭州',19);
insert into xzq_person values ('浙江','义乌',13);
insert into xzq_person values ('浙江','金华',11);
insert into xzq_person values ('广东','广州',18);
insert into xzq_person values ('广东','深圳',18);
insert into xzq_person values ('广东','中山',16);
insert into xzq_person values ('广东','惠州',16);
insert into xzq_person values ('广东','东莞',15);

partition by 的用法与含义
首先我们看一下group by的用法,比如根据省份分组。

select province, sum(persons) from xzq_person group by province;

使用了group by后,select语句中只能是分组的字段(比如上面的province)或者是一个聚合函数(比如count()、sum()、max()等等)。
在这里插入图片描述
partition从字面上看是分区、分块的意思,所以partition by其实就是根据某个字段将数据分块,然后可以对该分块数据再做查询(包括聚合查询)。
例如,partition by常同row_number() over一起使用:

select province, city, persons, row_number() over(partition by province order by persons) from xzq_person;

在这里插入图片描述
这个sql的作用就是根据province分组,并且分组后的每组的数据按照persons正序排序。
我们看到通过partition by分组后,select中是可以查出非分组的字段,这和group by是不一样的。
如果我们要查找每个省份人数最少的城市,可以用如下sql:

select * from (
    select province, city, persons, row_number() over(partition by province order by persons) forder from xzq_person
) temp
where temp.forder=1;

其中,row_number()是对分组后的数据进行顺序连续排序。
除了row_number() over,partition by还可以跟rank() over、dense_rank()一起使用。
rank()、dense_rank()和row_number()排序的区别:
row_number()顺序排序,依次从第一个至最后一个。
rank()跳跃排序,如果有并列第一个会直接跳到第三个。
dense_rank()连续排序,如果有两个第一级别时仍然从第二级别开始。
具体看如下的例子,使用partition by和rank() over一起使用。

select province, city, persons, rank() over(partition by province order by persons) from xzq_person;

在这里插入图片描述
使用partition by和dense_rank() over一起使用。

select province, city, persons, dense_rank() over(partition by province order by persons) from xzq_person;

在这里插入图片描述
另外,也可以做分组+排序后,求累计值的功能等。

select province, city, persons, sum(persons) over(partition by province order by persons) forder from xzq_person;

在这里插入图片描述
用途举例
删除表中重复的记录

DELETE FROM T_PROD_CODE WHERE ID IN (
SELECT ID FROM (
    SELECT CODE,ID,ROW_NUMBER() over(PARTITION BY CODE ORDER BY ID) AS RN FROM T_PROD_CODE
    ) T WHERE RN>1
);

练习SQL如下:

-- group by的用法,比如根据省份分组,根据人数多少排序
select province,sum(persons) as num from xzq_person GROUP BY province ORDER BY num;

-- partition从字面上看是分区、分块的意思,所以partition by其实就是根据某个字段将数据分块,然后可以对该分块数据再做查询(包括聚合查询)
-- partition by常同row_number() over一起使用
-- 这个sql的作用就是根据province分组,并且分组后的每组的数据按照persons正序排序
select province, city, persons, row_number() over(partition by province ORDER BY persons) from xzq_person;
select province, persons, row_number() over(partition by province ORDER BY persons) from xzq_person;      -- 数据行不变,且不会分组,相比较上一个查询,只是少了一个查询列

---------------------------------------------------------------
-- 如果我们要查找每个省份人数最少的城市,如下
-- 先找出每个省份人数,按照升序排列
select province,persons, row_number() over(PARTITION BY province ORDER BY persons) as rankfirst from xzq_person;

select temp.* from(
	select province,persons, row_number() over(PARTITION BY province ORDER BY persons) as rankfirst from xzq_person
) temp 
where temp.rankfirst = 1;

-- 如果采用group by实现
select temp.province,min(temp.num) from(
select province,city,sum(persons) as num from xzq_person GROUP BY province,city order by persons
) temp GROUP BY temp.province;
----------------------------------------------------------------

/*
其中,row_number()是对分组后的数据进行顺序连续排序。
除了row_number() over,partition by还可以跟rank() over、dense_rank()一起使用。
rank()、dense_rank()和row_number()排序的区别:
row_number()顺序排序,依次从第一个至最后一个。
rank()跳跃排序,如果有并列第一个会直接跳到第三个。
dense_rank()连续排序,如果有两个第一级别时仍然从第二级别开始。
具体看如下的例子,使用partition by和rank() over一起使用
*/
select province,city,persons, rank() over(PARTITION BY province order by persons) from xzq_person;
select province,city,persons, dense_rank() over(PARTITION BY province order by persons) from xzq_person;


-- 删除表中code字段重复的记录,sql如下
DELETE FROM T_PROD_CODE WHERE ID IN (
SELECT ID FROM (
    SELECT CODE,ID,ROW_NUMBER() over(PARTITION BY CODE ORDER BY ID) AS RN FROM T_PROD_CODE
    ) T WHERE RN>1
);

/*****查询案例二***/
1、数据
CREATE TABLE Student
(
    s_id    VARCHAR(20) COMMENT '学生编号',
    s_name  VARCHAR(20) NOT NULL DEFAULT '' COMMENT '学生姓名',
    s_birth VARCHAR(20) NOT NULL DEFAULT '' COMMENT '出生年月',
    s_sex   VARCHAR(10) NOT NULL DEFAULT '' COMMENT '学生性别',
    PRIMARY KEY (s_id)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8 COMMENT '学生表';
-- 课程表
CREATE TABLE Course
(
    c_id   VARCHAR(20) COMMENT '课程编号',
    c_name VARCHAR(20) NOT NULL DEFAULT '' COMMENT '课程名称',
    t_id   VARCHAR(20) NOT NULL COMMENT '教师编号',
    PRIMARY KEY (c_id)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8 COMMENT '课程表';
-- 教师表
CREATE TABLE Teacher
(
    t_id   VARCHAR(20) COMMENT '教师编号',
    t_name VARCHAR(20) NOT NULL DEFAULT '' COMMENT '教师姓名',
    PRIMARY KEY (t_id)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8 COMMENT '教师表';
-- 成绩表
CREATE TABLE Score
(
    s_id    VARCHAR(20) COMMENT '学生编号',
    c_id    VARCHAR(20) COMMENT '课程编号',
    s_score INT(3) COMMENT '分数',
    PRIMARY KEY (s_id, c_id)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8 COMMENT '成绩表';
  
  
-- 查询每门功课成绩最好的前两名
/*该sql查询所有信息列表*/
select stu.s_name,c_name,sc.s_score from score sc 
left join student stu on stu.s_id = sc.s_id
left join course c on c.c_id = sc.c_id order by c_name;

-- 该sql查询没门课程前两名的详细数据
select c.c_name,stu.s_name,ss.s_score from(
select s_id,c_id,s_score from(
select s_id,c_id,s_score, dense_rank() over(PARTITION BY c_id ORDER BY s_score desc) as sc from score
) temp where temp.sc <= 2
) ss left join course c on ss.c_id = c.c_id
left join student stu on stu.s_id = ss.s_id;

/*不同课程,成绩相同的学生的学生编号、课程编号、学生成绩 建议使用PARTITION BY*/
select c.c_name,stu.s_name,temp.s_score from(
select s1.* from score s1 join score s2 
where s1.s_id != s2.s_id and s1.c_id = s2.c_id and s1.s_score = s2.s_score
-- ORDER BY s1.c_id,s1.s_score
)temp 
left join course c on temp.c_id = c.c_id
left join student stu on stu.s_id = temp.s_id
ORDER BY c.c_name,temp.s_score;
  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
MySQLPARTITION BY是一种用于对查询结果进行分组排序的语法。它与GROUP BY有一些相似之处,但也有一些不同之处。PARTITION BY可以在保留全部数据的基础上,只对某些字段进行分组排序,而GROUP BY则会保留参与分组的字段和聚合函数的结果。它类似于Excel中的透视表。 在MySQL中,使用PARTITION BY需要在SELECT语句的OVER()函数中添加PARTITION BY关键字,然后指定要分组排序的字段。例如,可以使用以下语法查询每种商品的id、name以及同类型商品的数量: SELECT id, name, COUNT(*) OVER (PARTITION BY type) FROM product; 这个查询会将结果按照type字段进行分组,并显示每个分组中商品的数量。 另外,PARTITION BY还可以传入多列来进行分组排序。例如,下面的查询将会显示每个城市每个类型价格最高的商品名称: SELECT name, price, type, MAX(price) OVER (PARTITION BY address, type) AS 'max_price' FROM product; 这个查询会按照address和type两个字段进行分组,并显示每个分组中价格最高的商品名称。 总结来说,MySQLPARTITION BY语法允许在查询结果上进行分组排序,可以根据需要指定不同的分组字段。它可以在保留全部数据的情况下,对部分字段进行分组排序,提供了更大的灵活性。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [MySql数据分区操作之新增分区操作](https://download.csdn.net/download/weixin_38693657/13692488)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [MySQL窗口函数 PARTITION BY()函数介绍](https://blog.csdn.net/feizuiku0116/article/details/126127948)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

荒--

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值