2017-09-28 65 views
1

的组合,我使用的是Oracle SQL CREATE SEQUENCE名为MY_ID的字段的表。SQL根据日期和反

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; 

谢谢!

回答

2

你可能会想出一个方案来生成这个PREFIX_nn_date密钥,该密钥看起来可以在你的开发环境中工作,但我会给你一些不需要的建议:不要浪费你的时间。使您的主键成为一个简单的NUMBER列,从序列中填充它,然后继续。一旦你的代码投入生产,更多的用户将同时在你的桌子上敲击,那么你的精心制作的方案会产生这样的问题 - 很可能会失败 - 而且你用它来解决问题的手段越多,它就会越糟糕成为。

祝你好运。

+0

鲍勃感谢您的建议。然而在这种情况下,每年只会插入<= 20条记录,我认为它应该没问题。 –

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会更好。

+0

但这个触发器不会重置SEQ_MY_TABLE.NEXTVAL对吗?如果我今天插入1条记录,我会得到PREFIX_01_20170927,如果我明天再插入一条记录,我会得到PREFIX_02_20170928,有没有办法重置NEXTVAL,这样我明天就能得到PREFIX_01_20170928? –

+0

没有这样做,从调度程序在上午12:00调用此链接中描述的重置过程。 https://stackoverflow.com/questions/51470/how-do-i-reset-a-sequence-in-oracle –

1

继续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 

我没有做那么多工作甲骨文,但如果你要反复这样做,你可能希望将这一逻辑到函数或视图。

1

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

PREFIX_01_20170910 
PREFIX_02_20170910 
PREFIX_04_20170910 
PREFIX_07_20170910 

... 等等。例如,你有“缓存10”,你插入了2条记录并退出,或者回滚了,或者其他的东西。

对增量字段只使用数字并计算该伪造ID。

+0

你是对的!这不是一个可靠的方法。我应该在后端通过查询表并计算具有当前日期的记录并附加前缀和日期来生成该ID来代替在后端生成此ID。 –

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'),...);