Sqlserver OVER(PARTITION BY)的简单理解
|
freeflydom
2023年10月28日 15:22
本文热度 543
|
ROW_NUMBER() OVER(…)
虽然写法很复杂,但这确实只是一个普通函数(就像字符串转数字这样的函数),可以得出一个值
这个函数不会改变数据条数,它的作用是给每个数据记录增加一个字段,这个字段值就是函数得到的值
函数虽然不会改变查询结果条数,但会改变结果的顺序。会按照某个字段a(这个字段会重复)分组,函数的值就是在每个分组内部的排序值(1,2,3,4.。。)
比如:一群人在排队买东西。会自动以家庭为单位分成一段一段的“小组”,然后又在家庭内部按照年龄大小做了排序(比如年龄大人在前面,小孩跟在大人后面),这个函数值就是这个家庭内部排序值
按照上面的比喻,这个函数就是ROW_NUMBER() over (PARTITION BY 家庭编号 order by 年龄)
函数完整的样子:ROW_NUMBER() OVER(PARTITION BY… ORDER BY…)。为什么要很啰嗦的再加一个ROW_NUMBER()? 因为前面这个ROW_NUMBER()会进一步控制函数的特性,后面会讲解【不过我个人认为这个前缀确实很啰嗦。让我设计的话,我会去掉它。因为对于大部分人可能就只会用最普通的函数使用方式,不写时就默认为ROW_NUMBER()多好】
类比一个完整的查询
select *, ROW_NUMBER() over (PARTITION BY 家庭编号 order by 年龄 desc) as “家庭地位” from 人员表
这句话除了得到了所有人员的信息之外,还额外得到了一个字段"家庭地位"(这里就默认:年龄越大,家庭地位越高)
理解了函数的含义和用法,然后我们就可以利用函数,比如,只获取所有家庭地位最高的人,那么就可以在我们再包一层,得到:
select * from( select *, ROW_NUMBER() over (PARTITION BY 家庭编号 order by 年龄 desc) as “家庭地位” from 人员表 ) t where t.家庭地位=1
引申
这样就可以解决类似:表T中 字段a会重复,但我们查询的结果又不想要重复的数据,并且要求只要其中最新的那一条
select * from( select *, ROW_NUMBER() over (PARTITION BY a order by create_time desc) as index from T ) t where t.index=1
或者topN问题:分组后,把每组前5个找出来
select * from( select *, ROW_NUMBER() over (PARTITION BY a order by create_time desc) as index from T ) t where t.index < 6
ROW_NUMBER()
这是一个控制 OVER函数特性的参数,而且不能省,over前面必须有一个。但并不是只有ROW_NUMBER()这一种。
假设在一共家庭中,有四个孩子,其中两个是双胞胎,年龄分别是5岁,7岁,7岁,9岁。
两个7岁的双胞胎 谁大谁小是很难说。理论上可以讲,两个孩子年龄是相同的。那么排队时,谁是老大谁是老二呢。
ROW_NUMBER():简单粗暴的做了自己的判断,哪条数据在前面,哪个就是老大(谁先生出来谁就是老大)。即便他们年龄一样(over函数值一样),它给这几个孩子定的家庭地位分别为4,3,2,1
DENSE_RENK():显得更公正一点:既然定好了按年龄排序,那么年龄相同,地位就是相同。它给四个孩子定的家庭地位分别为:3,2,2,1
RENK():比较特殊,它觉得那个5岁的孩子的家庭地位不应该是第3位。因为家里明明有4个孩子,它是最小的,两个并列第二之后,下一个应该是4(所以直接把3给跳过了)。所以它给的家庭地位分别是4,2,2,1
名称
下面这些都是这个函数的名称:
窗口函数,分析函数,分区函数,一般称为窗口函数(window function)。
一般关系型数据库都支持。由于属于比较高级的函数,都是在数据库不断完善的过程中增加的。比如mysql就是8.x之后才有。
和聚合函数对比
聚合函数:sum(), avg() 等统计函数 配合 group by 称为聚合函数
得出的是分组后 每一组等统计数据,改变了数据条数
如果想保持数据原有的样子,则需要使用窗口函数
窗口函数前面除了前面介绍的常用的三种,还可以使用sum() avg()等统计函数,变成:
sum() over(partition by ...) x
这里得到的x,就是对这个组内的求和,组内每一条数据都得到一个相同的值
进阶-和排序函数对比
虽然前面说窗口函数的核心是partition by,但实际上partition by也可以去掉。
也就是说:xxx() over(…) 这个函数非常灵活。
其中partition by也可去掉,但此时必须要有order by。
变成:xxx() over(order by …) xxx
此时窗口函数 的窗口就只有一个了:所有数据都在同一个窗口里。 只剩下排序功能,比如
dense_renk() over(over by 成绩) 名次
常见作用:给班级学生成绩排名,成绩一样的,名次就一样
————————————————
版权声明:本文为CSDN博主「发现存在」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/yunduanyou/article/details/122583303
该文章在 2023/10/28 15:25:45 编辑过