3. 问题的解决
有了基础知识的积累,我们就可以解决前面提到的问题。
3.1 已知号码求号段
3.1.1 题例
我有一个表结构,
fphm,kshm
2014,00000001
2014,00000002
2014,00000003
2014,00000004
2014,00000005
2014,00000007
2014,00000008
2014,00000009
2013,00000120
2013,00000121
2013,00000122
2013,00000124
2013,00000125
(第二个字段内可能是连续的数据,可能存在断点。)
怎样能查询出来这样的结果,查询出连续的记录来。
就像下面的这样?
2014,00000001,00000005
2014,00000009,00000007
2013,00000120,00000122
2013,00000124,00000125
3.1.2 解答
思路:利用lead取得下一行的kshm,然后和本行的kshm想比,如果差值为1,说明这一行和下一行是连续的。由于首尾的特殊性,故而需要先用max和min来获得首尾点。
select fphm, nvl(lag(e)over(partition by fphm order by s),minn) ST, nvl(S,maxn) EN from
(select fphm, lag(kshm,1) over(partition by fphm order by kshm) S, kshm E, min(kshm)over(partition by fphm) minn, max(kshm) over(partition by fphm) maxn from t)
where nvl(E-S-1,1)<>0;
FPHM ST EN
---------- ---------- ----------
2013 00000120 00000122
2013 00000124 00000125
2014 00000001 00000005
2014 00000007 00000009
3.2 根据号段求出包含的数
3.2.1 题例
有表及测试数据如下:
CREATE TABLE T20
(
ID NUMBER(2),
S NUMBER(5),
E NUMBER(5)
);
INSERT INTO T20 ( ID, S, E ) VALUES ( 1, 10, 11);
INSERT INTO T20 ( ID, S, E ) VALUES ( 2, 1, 5);
INSERT INTO T20 ( ID, S, E ) VALUES ( 3, 88, 92);
COMMIT;
S为号段起点,E为号段终点,求出起点和终点之间的数(包括起点和终点)
3.2.2 解答
很明显,这需要构造序列来解决问题
select a.id, a.s, a.e,b.dis, a.S+b.dis-1 h from
t20 a,
(select rownum dis from
(select max(e-s)+1 gap from t20)
connect by rownum<=gap) b
where a.e>=a.s+b.dis-1
order by a.id, 4
运行结果:
ID S E DIS H
---------- ---------- ---------- ---------- ----------
1 10 11 1 10
1 10 11 2 11
2 1 5 1 1
2 1 5 2 2
2 1 5 3 3
2 1 5 4 4
2 1 5 5 5
3 88 92 1 88
3 88 92 2 89
3 88 92 3 90
3 88 92 4 91
3 88 92 5 92
我们再看下面这种做法:
select a.id, a.s, a.e,rownum, a.S+rownum-1 h from
t20 a ,
(select id, e-s+1 gap from t20 where id=2) b
where a.id=b.id
connect by rownum<=gap
ID S E ROWNUM H
---------- ---------- ---------- ---------- ----------
2 1 5 1 1
2 1 5 2 2
2 1 5 3 3
2 1 5 4 4
2 1 5 5 5
嗯,得到的结果也是正确的,若我们把粗斜体字部分去掉后,看看结果是什么样:
ID S E ROWNUM H
---------- ---------- ---------- ---------- ----------
1 10 11 1 10
1 10 11 2 11
2 1 5 3 3
2 1 5 4 4
2 1 5 5 5
2 1 5 6 6
3 88 92 7 94
这样的结果,显然不是我们需要的,更何况,这是错误的。由此更能深入理解,伪列是只针对结果集的。