数字范围格式转换
number range format conversion
给定 ['7810000000', '7819999999'] 形式的一系列蜂窝 phone 数字,我需要一种算法来生成多行尽可能小的长度,如果后缀为“%”。例如,上面的范围将表示为单行“781”。换句话说,该范围内的任何数字都可以表示为 781%。例如,此表示可用于存储 tarrifs。数据库中的一行可用于对整个范围进行评级。还有许多其他任务最好使用这种格式。 ['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) 中完成此转换。任何信息或链接将不胜感激。提前谢谢你。
蛮力方法,范围start/end作为绑定变量:
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 然后交叉连接这些并计算每个 'sub-range' 中出现的单个数字的数量,通过除以 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 和交叉连接意味着这会做很多工作,并且随着范围变大它会变慢 - 可能会失败。
我相信有更有效的方法可以做到这一点,希望有人能想出一个,但这可能会让你入门。
给定 ['7810000000', '7819999999'] 形式的一系列蜂窝 phone 数字,我需要一种算法来生成多行尽可能小的长度,如果后缀为“%”。例如,上面的范围将表示为单行“781”。换句话说,该范围内的任何数字都可以表示为 781%。例如,此表示可用于存储 tarrifs。数据库中的一行可用于对整个范围进行评级。还有许多其他任务最好使用这种格式。 ['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) 中完成此转换。任何信息或链接将不胜感激。提前谢谢你。
蛮力方法,范围start/end作为绑定变量:
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 然后交叉连接这些并计算每个 'sub-range' 中出现的单个数字的数量,通过除以 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 和交叉连接意味着这会做很多工作,并且随着范围变大它会变慢 - 可能会失败。
我相信有更有效的方法可以做到这一点,希望有人能想出一个,但这可能会让你入门。