常用到的窗口函数


工作中要常对数据进行分析,分析前要对原始数据中找到想要的格式,数据原本存储的格式不一定时我们想要的,要在基础上进行一定的处理,下面介绍的几种方式是常用的数据排序的集中方式,包含 排名函数(row_number())、排序函数(rank(),dense_rank())、聚合函数(常用统计函数)、偏移函数(lag(),lead(),first_value(),last_value())等内容

数据源为上篇文章的最后添加样本数据,上篇文章的最后用到的几个窗口函数会在这篇文章中详细介绍

排名函数

Row_Number() :将数据行根据一定的规则进行排名,排列出1,2,3,4···的形式,此函数后必须跟over(),且over()必须指定排名列,以order by [列名]形式,此排列顺序一定是连续的,也可以添加分区,在不指定分区 partition by [列名]时默认在查询条件内排序,指定分区后在分区内排名

  1. 查找出所有用户最近一次的账单记录
--显然可以看出用一般的T-SQL语句 group by 是可以做到的
select actid,max(trandate) as trandate from transactions group by actid --如果在增加其余的几列显然想过不是我们想要的结果了,因为在账单中每个账单号对于用户来是唯一的,日期是账单号的唯一,执行下面的语句会显示出查出全部的内容
select actid,tranid,val,max(trandate) as trandate from transactions group by actid,tranid,val --当然还有其他办法,编写比较复杂,这里就不介绍了 下面我们看一下 窗口排名函数 row_number()的做法 with c as(
select actid,tranid,val,trandate,
ROW_NUMBER() OVER(partition by actid order by trandate desc)
as rownum from transactions
)
select actid,tranid,val,trandate from c where rownum=1

  1. 每个账号最近五次的消费记录

显然根据上面的查询方法只需要修改 最后查询后的where rownum<=5

  1. 每个账号消费最多的五条记录

首先要根据 actid 进行分区,然后根据 val 排序, 最后根据排序值 取出 rownum<=5

修改如下

with c as(
select actid,tranid,val,trandate,
ROW_NUMBER() OVER(partition by actid order by val desc)
as rownum from transactions
)
select actid,tranid,val,trandate from c where val=1

一般情况下相比于其他的窗口函数 row_number() 的使用率是最高的,使用场景页多种多样

比如:在SQL Server 2012之前没引入 offset / fetch时我们经常用它来进行分页工作,进行修改序列操作生成操作

例如上文中 虚拟表函数编写,和修改订单号让数据化

  1. 分页: 一般界面展示减少数据库访问压力,会每次返回一定量的数据
declare
@pagesize int =150, --模拟每页的显示数量
@currpage int = 500; --第几页 --把所有数据当作数据源
with c as(
select actid,tranid,val,trandate,
row_number() over(order by (select null)) as rownum
from transactions
)
-- top查询 和限制 rownum 值完成分页效果
select top (@pagesize) actid,tranid,val,trandate
from c where rownum>(@currpage-1)*@pagesize and rownum<@currpage*@pagesize+1

排序函数

排序函数 和排名函数用法类似,生成结果上有所差异

rank() 非连续 如果排序列值不唯一时出现相同值,且下值会出现跳跃现象;排序列值唯一是效果与row_number()函数一致

dense_rank() 连续排列,当列值不唯一时出现相同值,下值和上值会城现连续现象

rank()

select actid,tranid,val,trandate,
ROW_NUMBER() over(order by val) as rownum,
RANK() over(order by val) as rank
from transactions
order by val
offset 0 rows fetch first 1000 rows only;

dense_rank()

--dense_rank
select actid,tranid,val,trandate,
ROW_NUMBER() over(order by val) as rownum,
RANK() over(order by val) as rnk,
DENSE_RANK() over(order by val) as dense_rnk
from transactions
order by val
offset 0 rows fetch first 1000 rows only;

聚合、偏移函数

聚合函数

分区内逐条查找,遇见之后更新,

select * ,
max(val) over(partition by actid order by tranid) as max_val,
min(val) over(partition by actid order by tranid) as min_val,
sum(val) over(partition by actid order by tranid) as sum_val
from transactions

偏移函数

Lag() 前一条,未找到为null

Lead() 后一条,未找到默认null,可指定偏移量,和默认值

一个参数效果

select *,
LAG(val) over(partition by actid order by tranid,trandate) as pre_value,
LEAD (val) over(partition by actid order by tranid,trandate) as next_value
from transactions

可以看出偏移量,默认为1行,且未找到值为 null

两个参数偏移函数,第一个参数偏移列,二个参数偏移行

select *,
LAG(val,3) over(partition by actid order by tranid,trandate) as pre_value,
LEAD (val,3) over(partition by actid order by tranid,trandate) as next_value
from transactions

指定默认值,将null列默认值设置为0.00

select *,
LAG(val,3,0.00) over(partition by actid order by tranid,trandate) as pre_value,
LEAD (val,3,0.00) over(partition by actid order by tranid,trandate) as next_value
from transactions

first_value() 分区内第一个值

last_value() 分区内左后一个值


select *,
first_value(val) over(partition by actid order by tranid,trandate) as first_value,
last_value(val) over(partition by actid order by tranid,trandate
rows between current row and unbounded following
) as last_value
from transactions

数据透视

行变列方便操作

下面语句为查找出用户流水最大的五条记录编号,并变为列的形式

with c as(
select actid,tranid,
row_number() over (partition by actid order by val desc) as rownum
from transactions
)
select * from c
pivot(max(tranid)
for rownum in([1],[2],[3],[4],[5])
)as p
order by actid

字符串拼接

将上表中消费编号拼接为一列形式输出

with c as(
select actid,tranid,
row_number() over (partition by actid order by val desc) as rownum
from transactions
)
select actid,concat([1],',',[2],',',[3],',',[4],',',[5]) as tranids
from c
pivot(max(tranid)
for rownum in([1],[2],[3],[4],[5])
)as p
order by actid

窗口函数至排序——SQLServer2012可高用的更多相关文章

  1. 虚拟数字存储表——SQLServer2012可高用

    窗口函数之虚拟数字辅助表 数字辅助表是一个整数序列,可以用它来完成多种不同的查询任务.数字表有很多任务,如生成日期和时间值序列,及分裂值列表.通常,建议在数据库中保存这样一个永久表,并填充尽可能多的数 ...

  2. MySQL8.0 ROW_NUMBER、RANK、DENSE_RANK窗口函数 分组排序排名

    MySQL8.0 (ROW_NUMBER)窗口函数 排名 暂时理解函数意义,后面再进行优化,如果有关变量排序,查看这个大哥的 mysql的分组排序和变量赋值顺序 先查看一个例子: # 按照每科课程分数 ...

  3. java排序,效率高的是哪种排序方法

    和所有其他语言是一样的.应该还是快速排序效率最高. public static void bubbleSort(int a[]) {int len = a.length;for (int i = 0; ...

  4. Hive窗口函数保姆级教程

    在SQL中有一类函数叫做聚合函数,例如sum().avg().max()等等,这类函数可以将多行数据按照规则聚集为一行,一般来讲聚集后的行数是要少于聚集前的行数的.但是有时我们想要既显示聚集前的数据, ...

  5. 几种排序算法的学习,利用Python和C实现

    之前学过的都忘了,也没好好做过总结,现在总结一下. 时间复杂度和空间复杂度的概念: 1.空间复杂度:是程序运行所以需要的额外消耗存储空间,一般的递归算法就要有o(n)的空间复杂度了,简单说就是递归集算 ...

  6. 对文本行按特定字段排序(前N个字符或后N个字符),TCPL 练习5-17

    The C programming language 的关于文本行排序的问题有很多种要求的方式,在对每行的字段排序方面,最简单的是例如对前N个字符或者末位N个字符进行排序,更高一点的要求是,对特殊符号 ...

  7. 谷歌的网页排序算法(PageRank Algorithm)

    本文将介绍谷歌的网页排序算法(PageRank Algorithm),以及它如何从250亿份网页中捞到与你的搜索条件匹配的结果.它的匹配效果如此之好,以至于“谷歌”(google)今天已经成为一个被广 ...

  8. Machine Learning for hackers读书笔记(四)排序:智能收件箱

    #数据集来源http://spamassassin.apache.org/publiccorpus/ #加载数据 library(tm)library(ggplot2)data.path<-'F ...

  9. Java基础知识强化之IO流笔记51:IO流练习之 键盘录入学生信息按照总分排序写入文本文件中的案例

    1.  键盘录入学生信息(姓名,语文成绩,数学成绩,英语成绩),按照总分排序写入文本文件中 分析:   A:创建学生类   B:创建集合对象      TreeSet<Student>   ...

随机推荐

  1. js排序——sort()排序用法

    sort() 方法用于对数组的元素进行排序,并返回数组.默认排序顺序是根据字符串Unicode码点. 语法:array.sort(fun):参数fun可选.规定排序顺序.必须是函数.注:如果调用该方法 ...

  2. Redis挂了,流量把数据库也打挂了,怎么办?

    你好呀,我是歪歪. 是这样的,前几天有个读者给我发消息,说面试的时候遇到一个场景题: 他说他当时,一时间竟然找不到回答问题的角度,感觉自己没有回答到点子上. 我仔细想了一下,确实是感到这个问题有一丝丝 ...

  3. leetcode最短无序连续子数组

    平民解法: 既然是找最小数组,那就得到一个排序好的数组,然后直接和初试数组比对,用一个left,right分别记录从最初开始不同,到最后不同的小标,最后左右做差再加一,就能得到长度. 其他解法: 双指 ...

  4. Vue学习笔记(三)条件渲染和循环渲染

    目录 一.条件渲染 1. v-if 2. 与v-else配合使用 3. 与v-else-if配合使用 4. v-show的使用 5. 类型切换案例 二.列表渲染 1. 遍历数组 2. 遍历对象 获取v ...

  5. k8s之Service详解-Service使用

    实验环境准备 在使用service之前,首先利用deployment创建出3个pod,注意要为pod设置app=nginx-pod的标签 创建deployment.yaml,内容如下 apiVersi ...

  6. 我这三年被kafka坑惨了

    前言 我的上家公司是做餐饮系统的,每天中午和晚上用餐高峰期,系统的并发量不容小觑.为了保险起见,公司规定各部门都要在吃饭的时间轮流值班,防止出现线上问题时能够及时处理. 我当时在后厨显示系统团队,该系 ...

  7. 问题求解与程序设计(C重新回顾:个人版)一

    一.容易遗忘之转义字符 转义序列 含义 \n 换行 \t 水平制表 \\ 输出反斜杠 \a 响铃符 \'' 输出双引号 \' 输出单引号 \? 输出问号 \r 输出回车符(不换行,光标定位当前行的开始 ...

  8. Redis分布式锁的原理和实现

    前言 我们之前聊过redis的,对基础不了解的可以移步查看一下: 几分钟搞定redis存储session共享--设计实现:https://www.cnblogs.com/xiongze520/p/10 ...

  9. NOIP 模拟 $22\; \rm f$

    题解 \(by\;zj\varphi\) 对于一个数,如果它二进制下第 \(i\) 位为 \(1\),那么 \(\rm x\) 在这一位选 \(1\) 的贡献就是和它不同的最高为为 \(i\) 的数的 ...

  10. 【spring 注解驱动开发】Spring AOP原理

    尚学堂spring 注解驱动开发学习笔记之 - AOP原理 AOP原理: 1.AOP原理-AOP功能实现 2.AOP原理-@EnableAspectJAutoProxy 3.AOP原理-Annotat ...