sql技巧-构造分组条件


create table PAPA(day DATE);
insert into PAPA (day) values (to_date('01-01-2016', 'dd-mm-yyyy'));
insert into PAPA (day) values (to_date('02-01-2016', 'dd-mm-yyyy'));
insert into PAPA (day) values (to_date('03-01-2016', 'dd-mm-yyyy'));
insert into PAPA (day) values (to_date('06-01-2016', 'dd-mm-yyyy'));
insert into PAPA (day) values (to_date('07-01-2016', 'dd-mm-yyyy'));
insert into PAPA (day) values (to_date('08-01-2016', 'dd-mm-yyyy'));
insert into PAPA (day) values (to_date('10-01-2016', 'dd-mm-yyyy'));
insert into PAPA (day) values (to_date('12-01-2016', 'dd-mm-yyyy'));
insert into PAPA (day) values (to_date('14-01-2016', 'dd-mm-yyyy'));
insert into PAPA (day) values (to_date('17-01-2016', 'dd-mm-yyyy'));
insert into PAPA (day) values (to_date('18-01-2016', 'dd-mm-yyyy'));
insert into PAPA (day) values (to_date('19-01-2016', 'dd-mm-yyyy'));
insert into PAPA (day) values (to_date('20-01-2016', 'dd-mm-yyyy'));
insert into PAPA (day) values (to_date('21-01-2016', 'dd-mm-yyyy'));
insert into PAPA (day) values (to_date('22-01-2016', 'dd-mm-yyyy'));
insert into PAPA (day) values (to_date('23-01-2016', 'dd-mm-yyyy'));
insert into PAPA (day) values (to_date('24-01-2016', 'dd-mm-yyyy'));
insert into PAPA (day) values (to_date('27-01-2016', 'dd-mm-yyyy'));
insert into PAPA (day) values (to_date('28-01-2016', 'dd-mm-yyyy'));
insert into PAPA (day) values (to_date('31-01-2016', 'dd-mm-yyyy'));
commit;
  
  
  1. with t1 as
  2. (select day,
  3. count(*) over(order by day range between current row and interval '1' day following) cnt1
  4. from papa),
  5. t2 as
  6. (select day,cnt1,lag(cnt1) over(order by day) cnt2 from t1),
  7. t3 as
  8. (select day,cnt1,cnt2,case when cnt2=1 or cnt2 is null then '1' else '0' end as kaishi from t2),
  9. t4 as
  10. (select day,sum(kaishi) over(order by day) sm from t3),
  11. t5 as
  12. (select day,row_number() over(partition by sm order by day) rn from t4)
  13. select day,case when rn<=6 then rn else mod(rn,6) end as jifen from t5;
  14. with t1 as
  15. (select day,
  16. count(*) over(order by day range between current row and interval '1' day following) cnt1
  17. from papa)
  18. select * from t1;
  19. DAY CNT1
  20. --------- ----------
  21. 01-JAN-16 2
  22. 02-JAN-16 2
  23. 03-JAN-16 1
  24. 06-JAN-16 2
  25. 07-JAN-16 2
  26. 08-JAN-16 1
  27. 10-JAN-16 1
  28. 12-JAN-16 1
  29. 14-JAN-16 1
  30. 17-JAN-16 2
  31. 18-JAN-16 2
  32. 19-JAN-16 2
  33. 20-JAN-16 2
  34. 21-JAN-16 2
  35. 22-JAN-16 2
  36. 23-JAN-16 2
  37. 24-JAN-16 1
  38. 27-JAN-16 2
  39. 28-JAN-16 1
  40. 31-JAN-16 1
  41. 找规律发现,上一行是1的,都是起始日
  42. with t1 as
  43. (select day,
  44. count(*) over(order by day range between current row and interval '1' day following) cnt1
  45. from papa),
  46. t2 as
  47. (select day,cnt1,lag(cnt1) over(order by day) cnt2 from t1)
  48. select * from t2;
  49. DAY CNT1 CNT2
  50. --------- ---------- ----------
  51. 01-JAN-16 2
  52. 02-JAN-16 2 2
  53. 03-JAN-16 1 2
  54. 06-JAN-16 2 1
  55. 07-JAN-16 2 2
  56. 08-JAN-16 1 2
  57. 10-JAN-16 1 1
  58. 12-JAN-16 1 1
  59. 14-JAN-16 1 1
  60. 17-JAN-16 2 1
  61. 18-JAN-16 2 2
  62. 19-JAN-16 2 2
  63. 20-JAN-16 2 2
  64. 21-JAN-16 2 2
  65. 22-JAN-16 2 2
  66. 23-JAN-16 2 2
  67. 24-JAN-16 1 2
  68. 27-JAN-16 2 1
  69. 28-JAN-16 1 2
  70. 31-JAN-16 1 1
  71. 于是lag一下,就确定了起始日,case when转换一下,1就是起始日,0就是连续日
  72. DAY CNT1 CNT2 K
  73. --------- ---------- ---------- -
  74. 01-JAN-16 2 1
  75. 02-JAN-16 2 2 0
  76. 03-JAN-16 1 2 0
  77. 06-JAN-16 2 1 1
  78. 07-JAN-16 2 2 0
  79. 08-JAN-16 1 2 0
  80. 10-JAN-16 1 1 1
  81. 12-JAN-16 1 1 1
  82. 14-JAN-16 1 1 1
  83. 17-JAN-16 2 1 1
  84. 18-JAN-16 2 2 0
  85. 19-JAN-16 2 2 0
  86. 20-JAN-16 2 2 0
  87. 21-JAN-16 2 2 0
  88. 22-JAN-16 2 2 0
  89. 23-JAN-16 2 2 0
  90. 24-JAN-16 1 2 0
  91. 27-JAN-16 2 1 1
  92. 28-JAN-16 1 2 0
  93. 31-JAN-16 1 1 1
  94. with t1 as
  95. 2 (select day,
  96. 3 count(*) over(order by day range between current row and interval '1' day following) cnt1
  97. 4 from papa),
  98. 5 t2 as
  99. 6 (select day,cnt1,lag(cnt1) over(order by day) cnt2 from t1),
  100. 7 t3 as
  101. 8 (select day,cnt1,cnt2,case when cnt2=1 or cnt2 is null then '1' else '0' end as kaishi from t2)
  102. 9 select day,sum(kaishi) over(order by day) sm from t3;
  103. DAY SM
  104. --------- ----------
  105. 01-JAN-16 1
  106. 02-JAN-16 1
  107. 03-JAN-16 1
  108. 06-JAN-16 2
  109. 07-JAN-16 2
  110. 08-JAN-16 2
  111. 10-JAN-16 3
  112. 12-JAN-16 4
  113. 14-JAN-16 5
  114. 17-JAN-16 6
  115. 18-JAN-16 6
  116. 19-JAN-16 6
  117. 20-JAN-16 6
  118. 21-JAN-16 6
  119. 22-JAN-16 6
  120. 23-JAN-16 6
  121. 24-JAN-16 6
  122. 27-JAN-16 7
  123. 28-JAN-16 7
  124. 31-JAN-16 8
  125. 构造partition by条件, 这个sum() over()很巧妙,每行都是unbounded precedingcurrent row,由于连续是0,所以连续日和起始日的sum值是一样的,这样就创造了分组条件
  126. 有了分组条件就可以用row_number() over()编号。
  127. 需要注意的是大于6的,用mod

构造分组条件还有两种方法

  
  
  1. 方法2
  2. select day,case when day=lag(day) over(order by day)+1 then 0 else 1 end as fenzu from papa;
  3. DAY FENZU
  4. ---------- ----------
  5. 2016-01-01 1
  6. 2016-01-02 0
  7. 2016-01-03 0
  8. 2016-01-06 1
  9. 2016-01-07 0
  10. 2016-01-08 0
  11. 2016-01-10 1
  12. 2016-01-12 1
  13. 2016-01-14 1
  14. 2016-01-17 1
  15. 2016-01-18 0
  16. 2016-01-19 0
  17. 2016-01-20 0
  18. 2016-01-21 0
  19. 2016-01-22 0
  20. 2016-01-23 0
  21. 2016-01-24 0
  22. 2016-01-27 1
  23. 2016-01-28 0
  24. 2016-01-31 1
  25. 思路是上一行+1=本行日期,那么就是连续登陆日,否则就是起始日
  26. 再套一层sum 构造分组依据
  27. with t1 as
  28. (select day,case when day=lag(day) over(order by day)+1 then 0 else 1 end as fenzu from papa)
  29. select day,sum(fenzu) over(order by day) sm from t1;
  30. DAY SM
  31. ---------- ----------
  32. 2016-01-01 1
  33. 2016-01-02 1
  34. 2016-01-03 1
  35. 2016-01-06 2
  36. 2016-01-07 2
  37. 2016-01-08 2
  38. 2016-01-10 3
  39. 2016-01-12 4
  40. 2016-01-14 5
  41. 2016-01-17 6
  42. 2016-01-18 6
  43. 2016-01-19 6
  44. 2016-01-20 6
  45. 2016-01-21 6
  46. 2016-01-22 6
  47. 2016-01-23 6
  48. 2016-01-24 6
  49. 2016-01-27 7
  50. 2016-01-28 7
  51. 2016-01-31 8
  52. 然后就和前面一样了,用row_number() over()
  53. 方法3
  54. select day,day-rownum from papa;
  55. DAY DAY-ROWNUM
  56. ---------- ----------
  57. 2016-01-01 2015-12-31
  58. 2016-01-02 2015-12-31
  59. 2016-01-03 2015-12-31
  60. 2016-01-06 2016-01-02
  61. 2016-01-07 2016-01-02
  62. 2016-01-08 2016-01-02
  63. 2016-01-10 2016-01-03
  64. 2016-01-12 2016-01-04
  65. 2016-01-14 2016-01-05
  66. 2016-01-17 2016-01-07
  67. 2016-01-18 2016-01-07
  68. 2016-01-19 2016-01-07
  69. 2016-01-20 2016-01-07
  70. 2016-01-21 2016-01-07
  71. 2016-01-22 2016-01-07
  72. 2016-01-23 2016-01-07
  73. 2016-01-24 2016-01-07
  74. 2016-01-27 2016-01-09
  75. 2016-01-28 2016-01-09
  76. 2016-01-31 2016-01-11
  77. 思路是,因为rownum随行数递增,如果是连续日期,那么他们减rownum后得到的日期应该是相同的,这样直接就构造了分组条件,相同日期为一组
  78. select day,row_number() over(partition by fenzu order by day) rn from (
  79. select day,day-rownum fenzu from papa);
  80. DAY RN
  81. ---------- ----------
  82. 2016-01-01 1
  83. 2016-01-02 2
  84. 2016-01-03 3
  85. 2016-01-06 1
  86. 2016-01-07 2
  87. 2016-01-08 3
  88. 2016-01-10 1
  89. 2016-01-12 1
  90. 2016-01-14 1
  91. 2016-01-17 1
  92. 2016-01-18 2
  93. 2016-01-19 3
  94. 2016-01-20 4
  95. 2016-01-21 5
  96. 2016-01-22 6
  97. 2016-01-23 7
  98. 2016-01-24 8
  99. 2016-01-27 1
  100. 2016-01-28 2
  101. 2016-01-31 1






  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值