如何将唯一约束写为触发器?

时间:2016-02-24 16:27:24

标签: sql oracle plsql triggers

我正在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行说错误。)

所以我假设有一个变量(或变量),我应该在某个地方宣布,但我不确定如何做到这一点。

1 个答案:

答案 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在他的评论中所说,无论如何这确实不是一个好主意 - 约束更加可靠和安全。使用这样的触发器,当两个不同会话中的用户在大致相同的时间插入相同的数据时,很容易得到重复。你也会遇到“桌子正在变异”的问题。