SQL CREATE SEQUENCE基于日期和计数器的组合

时间:2017-09-28 16:35:13

标签: sql oracle plsql

我正在使用Oracle SQL:

Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production              0 
PL/SQL Release 12.1.0.2.0 - Production                                                    0 
CORE    12.1.0.2.0  Production                                                            0 
TNS for Linux: Version 12.1.0.2.0 - Production                                            0 
NLSRTL Version 12.1.0.2.0 - Production    

我需要帮助找出如何为下面的关键字段创建序列:

我有一个名为MY_ID的字段的表。

插入记录时,需要使用序列自动生成MY_ID。

序列的规则是字符串前缀,每天1个计数器增量,午夜重置和日期的组合。

例如: 在9月10日,我们插入了2条记录,然后MY_ID应为:

PREFIX_01_20170910
PREFIX_02_20170910

9月11日:

PREFIX_01_20170911
PREFIX_02_20170911
PREFIX_03_20170911

9月12日,整个表格看起来像这样

PREFIX_01_20170910
PREFIX_02_20170910
PREFIX_01_20170911
PREFIX_02_20170911
PREFIX_03_20170911
PREFIX_01_20170912

到目前为止,无论日期如何,我对序列的所有操作都会增加1:

CREATE SEQUENCE SEQ_MY_TABLE INCREMENT BY 1 MAXVALUE 9999999999999999999999999999 MINVALUE 1 NOCACHE;

和触发器:

create or replace TRIGGER MY_TABLE_TRG 
BEFORE INSERT ON MY_TABLE
FOR EACH ROW
BEGIN
  <<COLUMN_SEQUENCES>>
  BEGIN
    IF INSERTING AND :NEW.MY_ID IS NULL THEN
      SELECT SEQ_MY_TABLE .NEXTVAL INTO :NEW.MY_ID FROM SYS.DUAL;
    END IF;
  END COLUMN_SEQUENCES;
END;

谢谢!

5 个答案:

答案 0 :(得分:3)

您可能想出一个方案来生成这个PREFIX_nn_date密钥,它似乎在您的开发环境中起作用,但我会给您一些不必要的建议:不要浪费您的时间它。使主键成为一个简单的NUMBER列,从序列中填充它,然后继续。一旦你的代码进入生产阶段,同时会有更多的用户同时敲打你的桌面,你精心设计的生成PREFIX_nn_date密钥的方案可能会失败 - 而且你用它来修复问题的助攻器就越多它会变得越糟糕。

祝你好运。

答案 1 :(得分:2)

跟进Bob Jarvis的回答,您可以随时在需要时创建字符串。这是一个简单的例子。

with records as (
select 1 id, to_date('20170901', 'yyyymmdd') theDate
from dual
union
select 2 id, to_date('20170901', 'yyyymmdd') theDate
from dual
union
select 3 id, to_date('20170902', 'yyyymmdd') theDate
from dual

)

select 'prefix_' ||  
to_char(theDate, 'yyyymmdd') || '_' || 
to_char( rank() over (partition by theDate order by id)) prefix
from records

返回:

prefix_20170901_1                                        
prefix_20170901_2                                        
prefix_20170902_1

我没有那么多oracle工作,但如果你要重复这样做,你可能想把这个逻辑合并到一个函数或视图中。

答案 2 :(得分:1)

您可以按如下方式修改TRIGGER。由于您需要序列中的每个数字为01,02,03附加到您的前缀,因此我在fm中使用了TO_CHAR说明符'00'。如果每天的总插入次数超过99次,则需要使用fm000

create or replace TRIGGER MY_TABLE_TRG 
BEFORE INSERT ON MY_TABLE
FOR EACH ROW
DECLARE
BEGIN
  <<COLUMN_SEQUENCES>>
  BEGIN
    IF INSERTING AND :NEW.MY_ID IS NULL THEN
      SELECT 'PREFIX_'||TO_CHAR(SEQ_MY_TABLE.NEXTVAL,'fm00')||'_'||TO_CHAR(SYSDATE,'YYYYMMDD') INTO :NEW.MY_ID FROM SYS.DUAL;
    END IF;
  END COLUMN_SEQUENCES;
END;

注意:为了建议一个好的做法,我不建议将其用作PRIMARY KEY。最好在填充记录时简单地在所有应用程序代码中生成序列PRIMARY KEY

答案 3 :(得分:1)

最简单的方法是通过工作每个午夜重新创建序列。但使用序列并不是一个好主意。我认为这个ID对你很重要,但序列可以缓存一些值,某些值可能会丢失。所以你会得到:

PREFIX_01_20170910
PREFIX_02_20170910
PREFIX_04_20170910
PREFIX_07_20170910

... 等等。例如,您有“缓存10”,插入了2条记录并退出,或者进行了回滚,或者其他内容。

仅使用数字作为增量字段并计算此假身份证。

答案 4 :(得分:0)

您可以创建如下所示的函数来获取新ID并在插入查询中使用它。

CREATE OR REPLACE FUNCTION F_GETID (P_DT IN VARCHAR2) RETURN VARCHAR2
IS
V_NEW_ID VARCHAR2(50);
BEGIN
SELECT 'PREFIX_' || COUNT(*)+1 ||'_' || P_DT INTO V_NEW_ID FROM MY_TABLE 
WHERE MY_ID LIKE   'PREFIX%'||P_DT;
RETURN V_NEW_ID;
END;

然后

 insert into my_table(my_id , ...) values(F_GETID('20170927'),...);