蛮力方法,将范围开始/结束作为绑定变量:
var start_val varchar2(14);
var end_val varchar2(14);
exec :start_val := '526251630000';
exec :end_val := '526251634999';
with dns (dn) as (
select to_number(:start_val) + level - 1
from dual
connect by level <= to_number(:end_val) - to_number(:start_val) + 1
),
exponents (ex) as (
select level - 1 from dual
connect by level <= length(:start_val)
),
tmp (dn, ex, pow, root, cnt ) as (
select d.dn,
e.ex,
power(10, e.ex),
trunc(d.dn / power(10, e.ex)),
count(d.dn) over (partition by trunc(d.dn / power(10, e.ex)))
from dns d
cross join exponents e
)
select distinct to_char(min(root) keep (dense_rank first order by ex desc)
over (partition by dn)) as result
from tmp
where pow = cnt
order by result;
得到
RESULT
----------------------------------------
526251630
526251631
526251632
526251633
526251634
dns CTE 将范围扩展到它包含的所有值。 exponents CTE 生成您可能想要使用的所有可能的 10 次幂(即从范围值的右侧删除多少位数)。然后tmp CTE 将这些交叉连接并计算每个“子范围”中出现的数量,通过除以 10 的幂计算得出。最后的查询然后过滤整个子范围 - 其中值的数量该范围与子范围的大小相同,因此不会丢失拆分 - 并为每个 DN 找到最小(即最短)的子范围根。然后最终得到它们的不同值。
对于第二个范围:
exec :start_val := '12300345';
exec :end_val := '12367000';
同样的查询得到:
RESULT
----------------------------------------
12300345
12300346
12300347
12300348
12300349
1230035
1230036
1230037
1230038
1230039
123004
123005
123006
123007
123008
123009
12301
12302
12303
12304
12305
12306
12307
12308
12309
1231
1232
1233
1234
1235
12360
12361
12362
12363
12364
12365
12366
12367000
CTE 和交叉连接意味着这需要做很多工作,随着范围变大,它会变慢 - 可能会失败。
我确信有更有效的方法可以做到这一点,希望有人会想出一个,但这可能会让你开始。