如何在 Oracle SQL 中将 max(0.10)+1 设为 0.11

How to get max(0.10)+1 as 0.11 in Oracle SQL

我在 table 中的值为 0.0、0.1、0.2。我使用以下查询将 0.0、0.4、...0.10 填充到 table.

我正尝试在 table 中再添加 4 条记录,并期望值为 0.11、0.12、0.13、0.14。但是我的查询将它们全部填充为 0.10,因此重复。

以下是我的查询,请帮我解决这个问题。

--查询

SELECT nvl(MAX(substr(sequence_number, instr(sequence_number, '.') + 1, 1)) + 1, '0') 
FROM TESTING_TBL;

---示例 table 创建脚本

CREATE TABLE TESTING_TBL (SEQUENCE_NUMBER VARCHAR2(30));
INSERT ALL INTO TESTING_TBL ( sequence_number ) VALUES ( '0.0' )
    INTO  TESTING_TBL (SEQUENCE_NUMBER) VALUES ('0.1')
    INTO  TESTING_TBL (SEQUENCE_NUMBER) VALUES ('0.2')
    INTO  TESTING_TBL (SEQUENCE_NUMBER) VALUES ('0.3')
    INTO  TESTING_TBL (SEQUENCE_NUMBER) VALUES ('0.4')
    INTO  TESTING_TBL (SEQUENCE_NUMBER) VALUES ('0.5')
    INTO  TESTING_TBL (SEQUENCE_NUMBER) VALUES ('0.6')
    INTO  TESTING_TBL (SEQUENCE_NUMBER) VALUES ('0.7')
    INTO  TESTING_TBL (SEQUENCE_NUMBER) VALUES ('0.8')
    INTO  TESTING_TBL (SEQUENCE_NUMBER) VALUES ('0.9')
    INTO  TESTING_TBL (SEQUENCE_NUMBER) VALUES ('0.10')
SELECT '1' FROM dual;

谢谢!

您必须先将字符串分成两部分,然后将两部分转换为数字并应用 MAX 并增加 1。

这是一个示例查询

with tbl as (
select 
  SEQUENCE_NUMBER,
  to_number(substr(SEQUENCE_NUMBER,1,instr(SEQUENCE_NUMBER,'.')-1)) num1,
  to_number(substr(SEQUENCE_NUMBER,instr(SEQUENCE_NUMBER,'.')+1)) num2
from TESTING_TBL)
select SEQUENCE_NUMBER, NUM1, NUM2
from tbl
order by num1, num2;

提供数据为

SEQUENCE_NUMBER                      NUM1       NUM2
------------------------------ ---------- ----------
0.0                                     0          0
0.1                                     0          1
....
0.8                                     0          8
0.9                                     0          9
0.10                                    0         10

现在有了数字,您可以安全地找到 MAX 并加 1

with tbl as (
select 
  SEQUENCE_NUMBER,
  to_number(substr(SEQUENCE_NUMBER,1,instr(SEQUENCE_NUMBER,'.')-1)) num1,
  to_number(substr(SEQUENCE_NUMBER,instr(SEQUENCE_NUMBER,'.')+1)) num2
from TESTING_TBL)
select to_char(max(NUM1))||'.'||to_char(max(NUM2)+1) new_key
from tbl

产生预期结果

NEW_KEY                                                                          
---------------------------------------------------------------------------------
0.11 

请注意,如果这是最佳方法,您应该重新设计。作为更好更安全的选择,我会考虑存储两个 INT 列(类型安全!)并将文本表示仅定义为虚拟列:

CREATE TABLE TESTING_TBL2 (num1 int, num2 int);

alter table TESTING_TBL2 add  SEQUENCE_NUMBER AS (to_char(num1)||'.'||to_char(num2)) VIRTUAL  ;

添加测试数据

INSERT ALL INTO TESTING_TBL2 ( num1, num2 ) VALUES ( 0,0 )
-- ....
    INTO  TESTING_TBL2 (num1, num2) VALUES ( 0,9 )
    INTO  TESTING_TBL2 (num1, num2) VALUES ( 0,10)
SELECT '1' FROM dual;

现在这个简单的查询提供了新键

select max(num1) num1, max(num2)+1 num2 from TESTING_TBL2;

完整数据

select * from TESTING_TBL2;

      NUM1       NUM2 SEQUENCE_NUMBER                                                                  
---------- ---------- ------------------- 
         0          0 0.0                                                                              
         0          9 0.9                                                                              
         0         10 0.10        

还请记住,用于分配新密钥的 MAX + 1 算法在 单用户 环境中效果最佳。

抛开关于这是否是一个好主意的各种合理评论......

眼前的问题是您将子字符串的长度限制为 1:

SELECT nvl(MAX(substr(sequence_number, instr(sequence_number, '.') + 1 , 1)) + 1, '0')

当小数点后只有一位时,这可以正常工作,所以你可以插入 0.10。那时,substr returns “1”,而不是您可能想要的“10”。我的猜测是这会导致您再次尝试插入“0.2”,从而导致违反唯一性。

如果它适用于您的所有输入,您应该只删除该长度参数。但是如果你必须处理更复杂的字符串,比如'0.10.3',你可能需要使用正则表达式来进行解析。或者,正如其他人所建议的那样,将此字符串的子组件存储为单独的数值,并使用虚拟列或在插入到最终 table.

期间将它们连接起来

感谢大家花时间解决我的问题。感谢您的所有努力。

我将小数点前后分开,并使用下面的查询来增加小数点后的数字。它解决了我的问题。

SELECT NVL(MAX(SUBSTR(sequence_number, 3)+1),'0')
FROM TESTING_TBL;