建表测试:
CREATE TABLE `partition_by_test` (
`ID` INT(10) NULL DEFAULT NULL,
`class` INT(10) NULL DEFAULT NULL,
`score` INT(10) NULL DEFAULT NULL
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB;
insert into partition_by_test values (1,1,80);
insert into partition_by_test values (2,1,75);
insert into partition_by_test values (3,1,90);
insert into partition_by_test values (4,1,95);
insert into partition_by_test values (5,2,105);
insert into partition_by_test values (6,2,58);
insert into partition_by_test values (7,2,67);
insert into partition_by_test values (8,2,87);
insert into partition_by_test values (9,2,99);
insert into partition_by_test values (10,2,96);
场景:
对 class进行分组,先按CLASS排序再按score降序排序(组内排序),并带上组内排序的序号。
场景应用:
如果有一张表有多个重复记录,可以根据此SQL找出组内排序后序号>1的自增ID全部删除之,达到去重的效果。
可能要达到去重,还有一种方法,根据所有字段group by后导出到文件,清空表,文件入库,完成。但是有时候是不容许清空表的,比如生产环境上的应用一般不允许直接清表,万一在清表的过程中,有新的数据插进来了,会导致表锁死或脏数据或数据不对。
SELECT @rownum:=@rownum+1 AS ROW_NUM,
A.ID,A.CLASS,A.SCORE,
IF(@tmp=A.class,@rank:=@rank+1,@rank:=1) AS RANK,
@tmp:=A.class AS TMP
FROM
(SELECT id,class,score FROM partition_by_test ORDER BY class ASC ,SCORE DESC) A
,
(SELECT @rownum :=0 , @tmp := NULL ,@rank:=NULL) B;
![]()
IF语法:IF(A=B,A++,A:=1) 如果A和B相等,则A加1,否则重新赋值A等于1。
SQL解析:
以SELECT id,class,score FROM partition_by_test ORDER BY class ASC ,SCORE DESC 这段SQL的结果为基准。
SELECT @rownum :=0 , @tmp := NULL ,@rank:=NULL;这一段为变量初始化语句,这个初始化,按需赋值,在此场景需求中@tmp和@rank无需初始化。
所谓按需初始化,如果不需要row_number,则可以精简为:
![]()
最后一列赋值了@tmp:=A.class,由于在IF语句结束后才会赋值@tmp:=@A.class, 刚开始@tmp的值为NULL, 在程序运行时, 第一次发现NULL<>A.class,赋值@rank:=1, 这一段的IF结束了,赋值@tmp:=A.class,此时的A.class=1,故@tmp=1=a.class,第二次@rank加1,当程序遍历到class=2时,由于IF循环(第五列)在 @tmp:=A.class(第六列) 之前,所以此时的tmp还是1,只有当IF结束,执行@tmp:=A.class(第六列)时,tmp的值才会变成2,所以(@tmp=1)<>(a.class=2),重新赋值@rank:=1,到此程序遍历此条记录结束,下次发现(@tmp=2)=(a.class=2),执行+1操作,以此类推.... ,直到遍历完所有记录。
推翻上述猜想的反例验证:
调换第五列(RANK)和第六列(TMP)的位置,发现没有得到想要的结果,反证,上述分析成立。
附sql以及结果:
SELECT @rownum:=@rownum+1 AS ROW_NUM,
A.ID,A.CLASS,A.SCORE,@tmp:=A.class AS TMP,
IF(@tmp=A.class,@rank:=@rank+1,@rank:=1) AS RANK
FROM
(SELECT id,class,score FROM partition_by_test ORDER BY class ASC ,SCORE DESC) A
,
(SELECT @rownum :=0 , @tmp := NULL ,@rank:=NULL) B;
![]()
解析,第五列赋值@tmp=a.class=1,结束执行if语句,条件成立,执行@rank:=@rank+1,此时的@rank=NULL,再加也是NULL,所以最后一列显示NULL