【问题标题】:SQL CREATE SEQUENCE based on a combination of date and counterSQL CREATE SEQUENCE 基于日期和计数器的组合
【发布时间】:2017-09-28 16:35:12
【问题描述】:

我正在使用 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;

谢谢!

【问题讨论】:

    标签: sql oracle plsql


    【解决方案1】:

    您可能会想出一个方案来生成此PREFIX_nn_date 密钥,该密钥似乎可以在您的开发环境中工作,但我要给您一些不想要的建议:不要在上面浪费时间。将主键设为简单的 NUMBER 列,从序列中填充它,然后继续。一旦你的代码投入生产,更多的用户将同时敲打你的桌子,你精心设计的生成 PREFIX_nn_date 密钥的方案很可能会失败——你扔给它的创可贴越多来解决问题就越糟糕它会变成的。

    祝你好运。

    【讨论】:

    • 感谢 Bob 的建议。但是在这种情况下,每年只会插入
    【解决方案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 工作,但如果您要反复执行此操作,您可能希望将此逻辑合并到函数或视图中。

    【讨论】:

      【解决方案3】:

      您可以如下修改TRIGGER。由于您需要将序列中的每个数字作为 01,02,03 附加到您的前缀上,因此我在 TO_CHAR 中使用了 fm 说明符和 '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

      【讨论】:

      • 但是这个触发器不会重置 SEQ_MY_TABLE.NEXTVAL 对吧?如果我今天插入 1 条记录,我将获得 PREFIX_01_20170927,如果我明天插入另一条记录,我将获得 PREFIX_02_20170928,有没有办法重置 NEXTVAL,以便我明天获得 PREFIX_01_20170928?
      • 不这样做,在上午 12:00 从调度程序调用此链接中描述的重置过程。 stackoverflow.com/questions/51470/…
      【解决方案4】:

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

      PREFIX_01_20170910
      PREFIX_02_20170910
      PREFIX_04_20170910
      PREFIX_07_20170910
      

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

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

      【讨论】:

      • 你是对的!这不是一个可靠的方法。我可能应该通过查询表并计算具有当前日期的记录在后端生成此 ID,并附加前缀和日期以生成该 ID。
      【解决方案5】:

      您可以创建如下函数来获取新的 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'),...);
      

      【讨论】:

        猜你喜欢
        • 2017-03-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多