巧妙利用PARTITION分组排名递增特性解决合并连续相同数据行
问题提出
先造一些测试数据以说明题目:
declare @testdata table(id int,col1 varchar(20),col2 varchar(20)) insert into @testdata(id,col1,col2) select 1,'new','approved' union all select 2,'approved','commited' union all select 3,'commited','in progress' union all select 4,'new','approved' union all select 5,'new','approved' union all select 6,'new','approved' union all select 7,'approved','removed' select * from @testdata
数据说明,id列连续自增,列1和列2都是tfs中pbi的状态记录,就是从什么变更到什么,如新建到批准,批准到提交神马的
现在要求连续且相同的状态变更记录合并,不连续或者不同的状态变更保留,例如:
以上图为例,id为1,4,5,6的记录都是从new到approved状态,但是记录1与记录4、5、6不相邻,或者说不连续,那么就要分成两组,
记录1一组,记录4、5、6一组,其它记录因为状态变更不相同所以全部保留,最后的查询结果应该长成下图这个样子:
继续之前你可以先自己试下,这可能会带来新的解题思路,
解题思路
该问题的关键在于group by会把记录1、4、5、6合并在一起,而这不符合要求,仅需要合并4、5、6,源表里没有这样一个字段可以将记录1与记录4、5、6区分开来,这是解题的关键
这里可以利用rank函数配合使用partition关键字,首先把1456分到一组去,同时产生一个组内排名的新字段r,这个排名r很关键,后边会用到,见下图:
rank函数不了解的点这里
rank函数以col1 + col2为分组条件,这样分成了四组,分别是new-approved、approved-commited、commited-in progress、approved-removed
在new-approved组内,记录1、4、5、6分别排名1、2、3、4;其它组内仅一条记录,在其组内排名均为1
现在制造了一个r字段,r字段标识了每条记录在其组内的排名,排名自1开始递增,
源表内id自增,组内排名r递增,这就是解题的关键,
当连续相同的记录出现时,其id与其排名r在同时递增,则其差值是相同的,拿到这个差值就可以很容易解决题目了,看下图:
记录4、5、6相同且连续出现,其id与其排名在同时增长,其差值则保持不变,这里使用col1 + col2 + gap作为分组条件即可将记录4、5、6合并,再取个最小id出来,问题解决,完整脚本如下:
可是如果id不连续时怎么办呢?这个不难,参考[mssql]row_number函数
上一篇: 总结一周内学习的Sql经验(一)
下一篇: ai散点画笔不能用显示灰色的该怎么办?