【问题标题】:Oracle APEX, autonumber not working?Oracle APEX,自动编号不起作用?
【发布时间】:2012-09-28 05:48:32
【问题描述】:

我是 Oracle 的新手,也是 Oracle Application Express 的新手。

我正在阅读手册,我正在尝试创建一个包含 3 个字段的表格:

USER_ID:编号、主键、自动编号

USER_NAME:VARCHAR2,唯一

密码:VARCHAR2

我使用 APEX SQL Workshop 向导创建表,但是当我尝试执行以下操作时:

INSERT INTO Schema.USERS (USER_NAME,PASSWORD) VALUES ('planet','password');

...我被告知违反了对主键的唯一约束。

表创建向导自动创建了一个触发器。它看起来像这样:

create or replace trigger "BI_USERS" 
  before insert on "USERS"               
  for each row  
begin   
  if :NEW."USER_ID" is null then
    select "USERS_SEQ".nextval into :NEW."USER_ID" from sys.dual;
  end if;
end; 

我的印象是,这会自动找到 USERS 的 USER_ID 字段中的最高数值,并自动为每个新 INSERT 分配一个递增的值,但这似乎没有发生。

谁能建议我做错了什么?

非常感谢

【问题讨论】:

    标签: oracle plsql sequence oracle-apex


    【解决方案1】:

    序列http://www.techonthenet.com/oracle/sequences.php

    (引用自链接文章)
    在 Oracle 中,您可以使用序列创建自动编号字段。一种 sequence 是Oracle中用于生成数字的对象 顺序。当您需要创建唯一编号时,这可能很有用 充当主键。

    ...

    此插入语句将向供应商插入一条新记录 桌子。供应商 ID 字段将被分配下一个数字 供应商序列。供应商名称字段将设置为 卡夫食品。

    你说:

    我的印象是这会自动找到最高的 USERSUSER_ID 字段中的数值并自动 为每个新的 INSERT 分配一个递增的值,但这不会 似乎正在发生。

    没有。序列将根据最后一个值和增量简单地生成下一个值,并且与您的数据无关。

    select nvl(max(user_id), 0) + 1 
      into v_next_val 
      from users 
    

    会查看您的数据并将最高的USER_ID 增加到1

    如果您现在由于USER_ID 上的主键而违反约束,这可能意味着您已将数据插入到用户表中,并且该数据包含USER_ID 列的值。 例如,假设创建了 3 条记录并手动将值分配给 USER_ID,而不使用序列

    insert into users (user_id, user_name) values (1, 'John');
    insert into users (user_id, user_name) values (2, 'Jerry');
    insert into users (user_id, user_name) values (3, 'Bob');
    

    当您随后开始使用该序列(或仅在那时创建它)时,该序列将从 value = 1 的指定起点开始。 就这样吧

    insert into users (user_name) values ('planet');
    

    会产生约束冲突,因为 sequence.nextval 将为 1。

    【讨论】:

    • 谢谢汤姆,非常感谢您的回答!点
    【解决方案2】:

    正如@Tom 所说,如果您在表中插入了为 USER_ID 指定值的行,则该序列的使用被绕过,您现在可能在表中的行中包含 USER_ID 值的重复值,这些值将从序列;因此,在插入新行时,您会收到 PRIMARY KEY CONSTRAINT VIOLATION 错误。要解决此问题,请编写一个小脚本,该脚本“使用”序列中的值并丢弃它们,如下所示:

    DECLARE
      n       NUMBER := 122;  -- or however many sequence values you need to consume
      seqVal  NUMBER;
    BEGIN
      FOR i IN 1..n LOOP
        SELECT USERS_SEQ.NEXTVAL INTO seqVal FROM DUAL;
      END LOOP;
    END;
    

    另一种选择是删除序列并重新创建它,其最小值大于 USERS.USER_ID 的最大值。

    分享和享受。

    【讨论】:

    • 或者,正如 techonthenet 文章所述:将增量设置为 121,执行一次 nextval,并将增量重置为 1。此外,如果您重新创建序列,我不一定会触及最小值,而是以价值开头。
    • 谢谢 Bob,希望我可以将多个帖子标记为答案——我什至还没有达到点赞帖子的门槛。但是,我仍然感谢您的意见!点
    【解决方案3】:

    这可能会有所帮助:

    create or replace TRIGGER  "TR_USER"
    before insert on "USER"
    for each row
    begin   
       if :NEW."IDUSER" is null then
         select max("IDUSER")+1 into :NEW."IDUSER" from USER;
      end if;
    end;
    

    【讨论】:

    • 永远不要使用 max(id)+1 来填充序列。这将在多用户环境中失败。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-01
    • 1970-01-01
    • 2014-04-22
    相关资源
    最近更新 更多