Oracle:生成一个数字序列,其值以某个数字开头

Posted

技术标签:

【中文标题】Oracle:生成一个数字序列,其值以某个数字开头【英文标题】:Oracle: generate a numeric sequence whose values start with a certain digit 【发布时间】:2020-08-28 10:52:56 【问题描述】:

我需要在 Oracle 中为我的表的列定义一个数字序列。 我得到的唯一约束要求所有值都以 9 开​​头。 因此,自动生成的值列表应如下所示:

9、90、91、92...99、900、901...999、9000、9001...9999、90000、...

您知道如何通过 SQL(通过适时创建和按顺序编辑)和/或 Java 代码来解决这个问题吗? 在我在网上阅读的一些帖子中,人们建议以这种方式修改序列:

ALTER SEQUENCE gokhan.sample_seq INCREMENT BY -500;
SELECT gokhan.sample_seq.NEXTVAL FROM dual;
ALTER SEQUENCE gokhan.sample_seq INCREMENT BY 1;

这需要每次都计算新的增量。如果可能的话,我想写一段 SQL 代码来自动化这个过程。

感谢支持。

【问题讨论】:

这听起来像是一个家庭作业。还有哪些额外的限制? 你不能只使用一个序列并添加一个 9 作为第一个数字吗?像 CONCAT('9',sequence.nextval)? 遗憾的是,这不是一个练习,但幸运的是没有其他限制。关于您的提示,是否可以将字符串与数值连接并将结果保存到数值列中? 【参考方案1】:

如果你想在 java 中实现它,我看到的唯一困难是计算给定数字的下一个值。但幸运的是,您的边界是十的幂(10、100、1000 ...),否则您会增加一。像下面这样的东西应该给你一个初步的方法

public class Test 

//A method to check if a given number is a power of ten :

    public static boolean powerOf10(int n) 
        int max_power10 = 1_000_000_000;
        if (n > max_power10 ) return false;
        int i = 1;
        while (i < n) i *= 10;   
        return i == n;
    

 //Then you can calculate the next value by either adding one or 
 //adding one and multipling by 9 if last value plus one is a power of ten

    public static int nextVal(int lastVal)        
        if(!powerOf10(lastVal + 1))
            return lastVal + 1;
        
        return 9 * (lastVal + 1);
    

//Note: for the sake of readability i omitted the check if the last value is a valid value (a number starting with 9)

//Demo 
    public static void main(String[] args)
        int MIN_VALUE = 9;
        for(int i = MIN_VALUE; i < 10000; i = nextVal(i))
            System.out.println(i);
        
    

【讨论】:

感谢您的回答,这或多或少是我在 Java 方面的想法。您将如何处理数据库序列?【参考方案2】:

使用普通序列 0,1,2,3,... 并且对于从此序列中检索到的任何 x,直接计算您的花哨序列的映射元素。

当序列的初始值为0时,元素1-10映射到90-99,元素11-110映射到900-999,元素111-1110映射到9000-9999等等。因此对于每个x输入序列(例如 500)的 em> 找到区间的下限(111),计算下限的对等点(900)并计算对等点的偏移量(9389)。

代码:

with sequence (x) as (
  select level - 1 from dual connect by level < 1001
), o (x,ones) as (
  select x, case x when 0 then 0 else to_number(rpad('1',to_char(1 + trunc(log(10,x))),'1')) end as ones
  from sequence
), m (x,ones,min) as (
  select x, ones, case when x >= ones then ones else (ones - 1) / 10 end as min 
  from o
)
select x, case x when 0 then 9 else x - min + 9 * power(10, 1 + trunc(log(10,min))) end as result from m;

翻译成 PLSQL 由您决定。请注意,将9 连接到正常序列的数字的建议不会产生所需的结果,因为这样的序列会增长 10/9 倍(在 9,90,900,... 元素之后,数字的数量会增加 1,而在你的序列中在 10,100,1000,... 个元素之后,位数增加 1)。不过会简单很多。尽管您没有描述这种逻辑的原因,但我还是会考虑用更简单的逻辑替换。

【讨论】:

以上是关于Oracle:生成一个数字序列,其值以某个数字开头的主要内容,如果未能解决你的问题,请参考以下文章

oracle 如何查找特定字母开头的某个字段?

回顾CSS,查缺补漏

oracle 去掉字符,剩下数字

变量与常量有什么区别?

将 Oracle 序列重置为现有列中的下一个值的最佳方法?

Oracle序列