数字范围格式转换

时间:2018-08-06 07:56:02

标签: sql oracle algorithm range cellular-network

给出一个范围为['7810000000','7819999999']的蜂窝电话号码,我需要一种算法,该算法将生成多个可能的最小长度的行,如果以'%'结尾,则该行将完全覆盖给定的范围。例如,从上方开始的范围将被表示为单个行“ 781”。换句话说,该范围内的任何数字都可以表示为781%。例如,此表示可能对存储关税有用。数据库中的单行可用于评估整个范围。有许多其他任务最好采用这种格式。范围为['526251630000','526251634999']的算法会产生

52625160
52625161
52625162
52625163
52625164

对于范围['12300345','12367000'],我们应该得到

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
12361
12362
12363
12364
12365
12366
12367000

我们需要这种转换才能在Oracle(SQL / PLQSL)中完成。任何信息或链接将不胜感激。预先谢谢你。

1 个答案:

答案 0 :(得分:0)

强力方法,范围开始/结束为绑定变量:

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和交叉联接意味着这需要做很多工作,并且随着范围的增大,它会变慢-可能会失败。

我敢肯定有更有效的方法可以做到这一点,希望有人提出来,但是这可能会让您入门。

相关问题