我创建了一个以1开头但没有最大值的序列 我已经自动创建了一个主键插入触发器,如下所示 我还为表设置了一个约束,其中主键必须是唯一的而不是null
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已包含从Id字段<1/338开始的值
那么,我应该如何在触发器和插入语句中处理它。
答案 0 :(得分:1)
如果你真的希望选项在insert上指定你自己的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。
我认为你不能在触发器内处理这个或者你的直接问题;我相信如果你试图检查同一个表中的现有值,你会得到一个变异表错误,并且这个的变通方法只会增加复杂性(需要三个触发器)并且可能不稳定。据我所知,处理该场景的唯一简单方法是将插入包装在一个过程中,并阻止直接插入,这也许不是一种选择。如果您在不使用序列的情况下插入值,则只需要担心这一点。
答案 1 :(得分: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);
拥有触发器意味着您无法使用INSERT中的id
列:
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序列)。
答案 2 :(得分: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;
/