2

我创建了一个从 1 开始的序列,没有最大值我已经创建了一个自动插入主键的触发器,它在下面我还为表设置了一个约束,其中主键必须是唯一的并且不为空

create trigger MY_TEMP_TRIGGER
before insert on MY_TEMP
for each row

BEGIN

  SELECT MY_TEMP_SEQ.nextval 
    INTO :new.Id 
    FROM DUAL;

END;
/

INSERT INTO my_temp  
  (Id,Type, CreateDT, TypeId, TempType, DevType, Msg, File,User, Src, SrcDev)   
VALUES
 (MY_TEMP_SEQ.nextval,3434,2843,2453,2392,435,2390,'pension.txt','rereee',454545,3434)

结果:

第 1 行的错误:
ORA-00001:违反了唯一约束 (USER.PK_MY_TEMP)

表 MY_TEMP 已经包含从 1 到 338 的值,来自 Id 字段

那么,我应该如何在触发器和插入语句中处理这个问题。

4

3 回答 3

1

如果您确实希望在插入时指定您自己的 ID 值的选项,并且在其他时间依赖于使用该序列的触发器,那么您的触发器需要检查它是否传递了一个值 - 否则触发器生成的 ID 将优先(如果您MY_TEMP_SEQ.nextval在插入中指定,该值将被跳过)。

BEGIN
    IF :NEW.id IS NULL THEN
        SELECT MY_TEMP_SEQ.nextval 
        INTO :NEW.id 
        FROM DUAL;
    END IF;
END;

处理已经存在的值更加复杂。如果您不打算传递自己的(非序列)ID 值,那么您可以将序列前滚到现有的最高值,例如:

ALTER SEQUENCE MY_TEMP_SEQ INCREMENT BY 338; -- or however many you need to skip
SELECT MY_TEMP_SEQ.nextval FROM DUAL;
ALTER SEQUENCE MY_TEMP_SEQ INCREMENT BY 1;

如果您尝试在不使用序列的情况下手动插入一条记录并指定 ID 值,则会遇到问题,该序列大于序列(例如使用 500)。当序列(最终)达到该值时,您仍然会得到 ORA-00001。

我认为您无法在触发器内处理那个或您的直接问题。如果您尝试检查同一个表中的现有值,我相信您会收到一个变异表错误,而解决方法只是增加了复杂性(需要三个触发器)和潜在的不稳定。据我所知,处理这种情况的唯一简单方法是将插入包装在一个过程中并阻止直接插入,这也可能不是一种选择。不过,如果您在不使用序列的情况下插入值,您只需要担心这一点。

于 2011-05-19T08:33:21.227 回答
0

您不能同时使用两者——只能使用其中一种。
在您的示例中,该id值已作为序列的下一个值插入......这与触发器尝试使用的值相同。我可能会倒序,但结果是一样的。

如果您将在 INSERT 语句中引用序列,则不需要触发器:

INSERT INTO my_temp  
  (Id,Type, CreateDT, TypeId, TempType, DevType, Msg, File,User, Src, SrcDev)   
VALUES
  (MY_TEMP_SEQ.nextval,3434,2843,2453,2392,435,2390,'pension.txt','rereee',454545,3434);

如果使用触发器

拥有触发器意味着您不能使用idINSERT 中的列:

INSERT INTO my_temp  
  (Type, CreateDT, TypeId, TempType, DevType, Msg, File,User, Src, SrcDev)   
VALUES
  (3434, 2843, 2453, 2392, 435, 2390, 'pension.txt', 'rereee', 454545, 3434);

最喜欢触发方法,因为它们习惯于 MySQL AUTOINCREMENT 或 SQL Server 的 IDENTITY(Denali 最终将支持 ANSI 序列)。

于 2011-05-19T07:06:31.310 回答
0

您可以在安装触发器之前增加序列:

declare 
  v_max_id my_temp.id%type;
  v_curr_seq  NUMBER;
begin
  select max(id) into v_max_id from my_temp;

  loop
    select MY_TEMP_SEQ.nextval into v_curr_seq from dual;
    exit when v_curr_seq >= v_max_id;
  end loop;
end;
/
于 2011-05-19T08:31:08.560 回答