求尚未使用的号段(读书笔记四)

求尚未使用的号段
建表语句:
CREATE TABLE t22(q VARCHAR2(8),
                 a NUMBER(4),
                 b NUMBER(4),
                 c NUMBER(4));
INSERT INTO t22 VALUES('A',0,999,1);
INSERT INTO t22 VALUES('A',100,199,2);
INSERT INTO t22 VALUES('A',300,499,2);
INSERT INTO t22 VALUES('A',555,666,2);
COMMIT;


取出包含在等级1里的,还没被录入等级2的号段
思路:将大号段的边界与小号段的边界相比,从大号段中将小号段”挖“掉,这样剩下的就是可用号段了

第一步:首先用lead和lag函数来取值,根据结果再思考第二步

SQL> SELECT t.*,
  2         LAG(a) OVER(ORDER BY a) aa,
  3         LAG(b) OVER(ORDER BY a) bb,
  4         LEAD(a) OVER(ORDER BY a) cc,
  5         LEAD(b) OVER(ORDER BY a) dd
  6  FROM t22 t;
 
Q            A     B     C         AA         BB         CC         DD
-------- ----- ----- ----- ---------- ---------- ---------- ----------
A            0   999     1                              100        199
A          100   199     2          0        999        300        499
A          300   499     2        100        199        555        666
A          555   666     2        300        499            

第二步:根据结果可以看到,cc列减去1可得到结果,而cc列的最后一行空行,可以填入max(b)。即
SQL> SELECT t.*,
  2         LAG(a) OVER(ORDER BY a) aa,
  3         LAG(b) OVER(ORDER BY a) bb,
  4         nvl(LEAD(a) OVER(ORDER BY a)-1,MAX(b) OVER(PARTITION BY q)) cc,
  5         LEAD(b) OVER(ORDER BY a) dd
  6  FROM t22 t;
 
Q            A     B     C         AA         BB         CC         DD
-------- ----- ----- ----- ---------- ---------- ---------- ----------
A            0   999     1                               99        199
A          100   199     2          0        999        299        499
A          300   499     2        100        199        554        666
A          555   666     2        300        499        <span style="color:#ff0000;">999</span> 


第三步:再次观察,可以看到b列加1得到一组数。即

SQL> SELECT t.*,
  2         LAG(a) OVER(ORDER BY a) aa,
  3         LAG(b) OVER(ORDER BY a) bb,
  4         b+1,
  5         nvl(LEAD(a) OVER(ORDER BY a)-1,MAX(b) OVER(PARTITION BY q)) cc,
  6         LEAD(b) OVER(ORDER BY a) dd
  7  FROM t22 t;
 
Q            A     B     C         AA         BB        B+1         CC         DD
-------- ----- ----- ----- ---------- ---------- ---------- ---------- ----------
A            0   999     1                             <span style="color:#3366ff;">1000</span>         99        199
A          100   199     2          0        999        200        299        499
A          300   499     2        100        199        500        554        666
A          555   666     2        300        499        667        999 


第四步:明显看到现在b+1和cc越来越接近答案,但是b+1的第一行应该写入0,那么此时可以想到使用AA列来做辅助,即若AA列与B+1列比较,
若AA不为空则返回b+1,否则返回min(a)。其余不相干的列去除,语句如下
SQL> SELECT nvl2(LAG(a) OVER(ORDER BY a),b+1,MIN(a) OVER(PARTITION BY q)) qian,
  2         nvl(LEAD(a) OVER(ORDER BY a)-1,MAX(b) OVER(PARTITION BY q)) hou
  3  FROM t22 t;
 
      QIAN        HOU
---------- ----------
         0         99
       200        299
       500        554
       667        999


这样做似乎结束了,其实没有结束

INSERT INTO t22 VALUES('A',280,340,2);
COMMIT;


若用
SQL> SELECT nvl2(LAG(a) OVER(ORDER BY a),b+1,MIN(a) OVER(PARTITION BY q)) qidian,
  2         nvl(LEAD(a) OVER(ORDER BY a)-1,MAX(b) OVER(PARTITION BY q)) hou
  3  FROM t22 t;
 
    QIDIAN        HOU
---------- ----------
         0         99
       200        279
      <span style="color:#ff0000;"> 341        299</span>
       500        554
       667        999


显然不对

此时的解决办法则是在外面套一层,同时加where过滤条件,即qian<=hou。如下

SQL> SELECT t.qian,t.hou
  2  FROM (SELECT nvl2(LAG(a) OVER(ORDER BY a),b+1,MIN(a) OVER(PARTITION BY q)) qian,
  3         nvl(LEAD(a) OVER(ORDER BY a)-1,MAX(b) OVER(PARTITION BY q)) hou
  4  FROM t22) t
  5  WHERE t.qian<=t.hou;
 
      QIAN        HOU
---------- ----------
         0         99
       200        279
       500        554
       667        999

若涉及到分组,则在lag和lead中加入分组即可


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值