SQL 技巧构造分组依据

题目

数据 













需求,000为一组,123为一组,444为一组,5678为一组,请用SQL实现

创建表
 
 
  1. create table pig(id number);
  2. insert into pig values(0);
  3. insert into pig values(0);
  4. insert into pig values(0);
  5. insert into pig values(1);
  6. insert into pig values(2);
  7. insert into pig values(3);
  8. insert into pig values(4);
  9. insert into pig values(4);
  10. insert into pig values(4);
  11. insert into pig values(5);
  12. insert into pig values(6);
  13. insert into pig values(7);
  14. insert into pig values(8);
Oracle

思路是构造分组条件列,为最后的 listagg 创造分组依据 
这里用 lag 折腾来折腾去,不太明白为什么,可能只是在找规律

 
 
  1. with t1 as
  2. (select id,lag(id) over(order by id) lag_id from pig),
  3. t2 as
  4. (select id, lag_id,case when id=lag_id then 0 else 1 end as flag from t1),
  5. t3 as (
  6. select id,lag_id,flag,lag(flag) over(order by id) lag2,lead(flag) over(order by id) lag3 from t2),
  7. t4 as (
  8. select id,lag_id,flag,lag2,lag3,case when lag2=1 and nvl(lag3,1)=1 then 0 else flag end as flag2 from t3),
  9. t5 as (
  10. select id,flag2,sum(flag2) over(order by id) gp from t4)
  11. select listagg(id,',') within group(order by id) from t5 group by gp


最后两个 lag lead 在操作 flag 列,如果都等于1就让他等于0,否则等于 flag 
最后的 flag2列用 sum() over()就可以构造出分组依据了 

最后用 listagg 就可以了

Mysql

这里完全是模仿 Oracle 的思路

 
 
  1. select GROUP_CONCAT(id order by id) from (
  2. select id,flag2,@sum:=@sum+flag2 sum from (
  3. select id,flag,lag_flag,lead,case when lag_flag=1 and ifnull(lead,1)=1 then 0 else flag end flag2,rownum from (
  4. select id,flag,lead,@lag lag_flag ,rownum,@lag:=flag from (
  5. select id,lag,flag,@flag lead,@flag:=flag,rownum from (
  6. select id,lag,case when id=lag then 0 else 1 end flag,rownum from (
  7. select id,@id lag,@rn rownum,@rn:=@rn+1 ,@id:=id from pig,
  8. (select @id:=null ,@rn:=1) b) a) a,(select @flag:=null) b order by rownum desc) a ,(select @lag:=null) b order by rownum) a)
  9. a ,(select @sum:=0) b ) a group by sum
lag
 
 
  1. select id,@id lag,@id:=id from pig,(select @id:=null) b ;
  2. +------+------+---------+
  3. | id | lag | @id:=id |
  4. +------+------+---------+
  5. | 0 | NULL | 0 |
  6. | 0 | 0 | 0 |
  7. | 0 | 0 | 0 |
  8. | 1 | 0 | 1 |
  9. | 2 | 1 | 2 |
  10. | 3 | 2 | 3 |
  11. | 4 | 3 | 4 |
  12. | 4 | 4 | 4 |
  13. | 4 | 4 | 4 |
  14. | 5 | 4 | 5 |
  15. | 6 | 5 | 6 |
  16. | 7 | 6 | 7 |
  17. | 8 | 7 | 8 |
  18. +------+------+---------+
  19. 13 rows in set (0.00 sec)

在这一行 sql 中,首先声明变量@id:=null,之后 select 出 id 和@id ( 此时 id 的初始值是 null ),然后赋值@id:=id,此时@id 等于 第一行的0 
在第二行是,id=0,@id=之前赋值的0,然后再次赋值@id 等于第二行的0 
加上 rownum,位置后 lead 做准备

 
 
  1. select id,@id lag,@rn rownum,@rn:=@rn+1 ,@id:=id from pig,(select @id:=null ,@rn:=1) b
lead

lead 的具体思路是 
1.生成 rownum 
2.根据 rownum 倒序 
3.按照 lag 方式实现 
4.再按照 rownum 正序

 
 
  1. select id,lag,flag,@flag lead,@flag:=flag,rownum from (
  2. select id,lag,case when id=lag then 0 else 1 end flag,rownum from (
  3. select id,@id lag,@rn rownum,@rn:=@rn+1 ,@id:=id from pig,
  4. (select @id:=null ,@rn:=1) b) a) a,(select @flag:=null) b order by rownum desc
  5. +------+------+------+------+-------------+--------+
  6. | id | lag | flag | lead | @flag:=flag | rownum |
  7. +------+------+------+------+-------------+--------+
  8. | 8 | 7 | 1 | NULL | 1 | 13 |
  9. | 7 | 6 | 1 | 1 | 1 | 12 |
  10. | 6 | 5 | 1 | 1 | 1 | 11 |
  11. | 5 | 4 | 1 | 1 | 1 | 10 |
  12. | 4 | 4 | 0 | 1 | 0 | 9 |
  13. | 4 | 4 | 0 | 0 | 0 | 8 |
  14. | 4 | 3 | 1 | 0 | 1 | 7 |
  15. | 3 | 2 | 1 | 1 | 1 | 6 |
  16. | 2 | 1 | 1 | 1 | 1 | 5 |
  17. | 1 | 0 | 1 | 1 | 1 | 4 |
  18. | 0 | 0 | 0 | 1 | 0 | 3 |
  19. | 0 | 0 | 0 | 0 | 0 | 2 |
  20. | 0 | NULL | 1 | 0 | 1 | 1 |
  21. +------+------+------+------+-------------+--------+

最后在按照 rownum 正序

sum() over()

没有 partition by 的情况就是

 
 
  1. @sum:=@sum+flag2
  2. (select @sum:=0) b

partition by

 
 
  1. SELECT empno,
  2. ename,
  3. sal,
  4. IF(@deptno = deptno, @sal := @sal, @sal := s_sal) AS s_sal,
  5. @deptno := deptno
  6. FROM
  7. (
  8. SELECT empno,
  9. ename,
  10. sal,
  11. IF(@deptno = deptno, @sal := @sal + sal, @sal := sal) AS s_sal,
  12. @deptno := deptno AS deptno
  13. FROM (SELECT @sal := 0, @deptno := 0) a0, emp t
  14. ORDER BY deptno, empno
  15. )e
  16. ORDER BY deptno, empno DESC;
  17. +-------+--------+------+-------+-------------------+
  18. | empno | ename | sal | s_sal | @deptno := deptno |
  19. +-------+--------+------+-------+-------------------+
  20. | 7934 | MILLER | 1300 | 8750 | 10 |
  21. | 7839 | KING | 5000 | 8750 | 10 |
  22. | 7782 | CLARK | 2450 | 8750 | 10 |
  23. | 7902 | FORD | 3000 | 10875 | 20 |
  24. | 7876 | ADAMS | 1100 | 10875 | 20 |
  25. | 7788 | SCOTT | 3000 | 10875 | 20 |
  26. | 7566 | JONES | 2975 | 10875 | 20 |
  27. | 7369 | SMITH | 800 | 10875 | 20 |
  28. | 7900 | JAMES | 950 | 9400 | 30 |
  29. | 7844 | TURNER | 1500 | 9400 | 30 |
  30. | 7698 | BLAKE | 2850 | 9400 | 30 |
  31. | 7654 | MARTIN | 1250 | 9400 | 30 |
  32. | 7521 | WARD | 1250 | 9400 | 30 |
  33. | 7499 | ALLEN | 1600 | 9400 | 30 |
  34. +-------+--------+------+-------+-------------------+
  35. 14 rows in set (0.01 sec)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值