row_number() over(partition by) 和 first_value over(partition by) 实用例子和二者区别。Mysql和Hive分别实现取组内最大条数据

需求:  1:id有5组, 现在要求出各组内薪资最高得那个人

          2:如果该组有多个薪水一样得人,那么取出年龄最大那个

数据源: mysql、hive

idnameagesalary
1a11080
1a21165
1a3590
2b112130
2b21345
2b31480
3c114300
3c215900
3c316900
4d116500
4d216600
4d317300
5e120200
5e220200
5e319100

一、数据生成

1:创建表

CREATE TABLE `test` ( `id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `age` int(255) NULL DEFAULT NULL, `salary` int(10) NULL DEFAULT NULL ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

2: 插入数据

insert into test(id,name,age,salary) values(1,'a1',10,80);

insert into test(id,name,age,salary) values(1,'a2',11,65);

insert into test(id,name,age,salary) values(1,'a3',05,90);

 

insert into test(id,name,age,salary) values(2,'b1',12,130);

insert into test(id,name,age,salary) values(2,'b2',13,45);

insert into test(id,name,age,salary) values(2,'b3',14,80);

 

insert into test(id,name,age,salary) values(3,'c1',14,300);

insert into test(id,name,age,salary) values(3,'c2',15,900);

insert into test(id,name,age,salary) values(3,'c3',16,900);

 

insert into test(id,name,age,salary) values(4,'d1',16,500);

insert into test(id,name,age,salary) values(4,'d2',16,600);

insert into test(id,name,age,salary) values(4,'d3',17,300);

 

insert into test(id,name,age,salary) values(5,'e1',20,200);

insert into test(id,name,age,salary) values(5,'e2',20,200);

insert into test(id,name,age,salary) values(5,'e3',19,100);

 

二: 需求实现(Mysql)

Mysql实现求出组内最大

SELECT * FROM test WHERE (id,salary) IN (
	SELECT id,MAX(salary) FROM test GROUP BY id
)
idnameagesalary
1a3590
2b112130
3c215900
3c316900
4d216600
5e120200
5e220200

可以看到结果现在是正确得,但是3组和5组当中, 3组求出来了组内薪资最大但是有两条数据薪资一样,他们的age不一样,  5组求出来了组内薪资最大但是有两条数据薪资一样,他们age也一样。

所以现在实现第二个需求,如果薪资一样求出age最大那一条数据, 如果薪资一样年龄也一样的话取出组内任意一条。那么现在3组应该取出name为c3的, 5组取出组内任意一条

SELECT
	* 
FROM
	test 
WHERE
	( ID, AGE, salary ) IN (
	SELECT
		T.ID,
		MAX( AGE ),
		salary 
	FROM
		test T 
	WHERE
		( T.ID, T.SALARY ) IN ( SELECT ID, MAX( SALARY ) FROM test T1 GROUP BY T1.ID ) 
	GROUP BY
		T.ID 
	) 
GROUP BY
	id
idnameagesalary
1a3590
2b112130
3c316900
4d216600
5e120200

现在这样的结果,就符合了需求

 

三: 需求实现(Hive)

在使用开窗函数之前可以先了解一下什么是开窗函数

https://blog.csdn.net/kuodannie1668/article/details/79757186?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.control

在了解完开窗函数之后可以结合需求, 这次我们需要的是,row_number() over(partition by) 或者 first_value over(partition by)  这两个函数, 具体实现方法如下

row_number() 使用

SELECT id,name,age,salary,row_number() over (PARTITION BY id ORDER BY salary desc) rn from salarytest
idnameagesalaryrn
1a35901
1a110802
1a211653
2b1121301
2b314802
2b213453
3c3169001
3c2159002
3c1143003
4d2166001
4d1165002
4d3173003
5e1202001
5e2202002
5e3191003

从上结果可以看出, row_number函数将按照分区条件分区后按照指定字段排序的结果,可以根据需求取数据, 比如我想要前三位, 那么可以再阔一层加个判断 rn <= 3。 

如果再这个SQL的基础上再去实现第二个需求, 如果薪资一样求出age最大那一条数据, 如果薪资一样年龄也一样的话取出组内任意一条。那么现在3组应该取出name为c3的, 5组取出组内任意一条

SELECT id,name,age,salary,row_number() over (PARTITION BY id ORDER BY salary desc ,age desc) rn  from salarytest

 

idnameagesalaryrn
1a35901
1a110802
1a211653
2b1121301
2b314802
2b213453
3c3169001
3c2159002
3c1143003
4d2166001
4d1165002
4d3173003
5e1202001
5e2202002
5e3191003

就是排序的时候 薪资倒序,年龄也倒序就可以了。如果要求出来薪资相同年龄最下的那一条, age 升序就可以了

 

first_value() 使用

SELECT id,name,age,first_value(salary) OVER (PARTITION BY id ORDER BY salary desc) rn  FROM salarytest
idnameagern
1a3590
1a11090
1a21190
2b112130
2b314130
2b213130
3c316900
3c215900
3c114900
4d216600
4d116600
4d317600
5e120200
5e220200
5e319200

 

frist_value 的结果很直观,就是分区排序后 取第一位 

 

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

李指导、

您的鼓励是我创作最大的动力

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

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

打赏作者

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

抵扣说明:

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

余额充值