我正在Oracle数据库中创建一个新表,我正在尝试学习如何创建触发器。首先,我想我会尝试创建一个基本触发器,在插入或更新之前检查现有值。在未来,这将作为约束处理,但我还需要一些比较其他现有行和列之间的值的触发器,所以我想知道如何将其写为触发器。 / p>
我想要实现的目标:创建一个触发器,如果表中没有其他行包含试图在新行中输入的相同TEMPLATE_ID和PRE_TEMPLATE_ID值,则只允许创建行。
我的代码:
CREATE TRIGGER check_redundancy
BEFORE INSERT OR UPDATE
ON SCHEMA.TABLE
FOR EACH ROW
BEGIN
IF NEW.TEMPLATE_ID NOT IN
(SELECT
A.TEMPLATE_ID
FROM
SCHEMA.TABLE A
WHERE
NEW.PRE_TEMPLATE_ID = A.PRE_TEMPLATE_ID)
THEN
INSERT INTO SCHEMA.TABLE (ID, TEMPLATE_ID, PRE_TEMPLATE_ID, DATE_CREATED, CREATED_BY)
VALUES (NEW.ID, NEW.TEMPLATE_ID, NEW.PRE_TEMPLATE_ID, NEW.DATE_CREATED, NEW.CREATED_BY);
END IF;
END;
运行时,我收到以下错误:
" ORA-06502:PL / SQL:数字或值错误:字符串缓冲区太小" " ORA-06512:第14行"
(值得注意的是 - 它始终告诉我第14行的错误......即使我删除了BEGIN和END之间的所有内容,它仍然在第14行说错误。)
所以我假设有一个变量(或变量),我应该在某个地方宣布,但我不确定如何做到这一点。
答案 0 :(得分:1)
before insert
触发器会在插入之前触发,而不是激活它。如果没有引发异常,插入将在此触发后自然发生。如果使用这样的触发器进行验证,代码应该更像这样:
CREATE TRIGGER check_redundancy
BEFORE INSERT OR UPDATE
ON SCHEMA.TABLE
FOR EACH ROW
BEGIN
IF :NEW.TEMPLATE_ID IN
(SELECT
A.TEMPLATE_ID
FROM
SCHEMA.TABLE A
WHERE
NEW.PRE_TEMPLATE_ID = A.PRE_TEMPLATE_ID)
THEN
RAISE_APPLICATION_ERROR (-20001, 'Your error message here');
END IF;
END;
正如@Alex在他的评论中所说,无论如何这确实不是一个好主意 - 约束更加可靠和安全。使用这样的触发器,当两个不同会话中的用户在大致相同的时间插入相同的数据时,很容易得到重复。你也会遇到“桌子正在变异”的问题。