Oracle SQL - 插入前触发器未触发

Posted

技术标签:

【中文标题】Oracle SQL - 插入前触发器未触发【英文标题】:Oracle SQL - Before-Insert Trigger not firing 【发布时间】:2017-03-31 14:40:37 【问题描述】:

我是 Oracle SQL 的新手,今天我想尝试一个与“UNIQUE”语句相同的示例触发器。因此,触发器应在插入之前检查数据集中是否已存在特定属性(“cityid”)。

问题是我的触发器没有触发!编译工作正常,但没有一个命令工作。

这里是:

CREATE OR REPLACE TRIGGER check_cityid
BEFORE INSERT
    ON city
    FOR EACH ROW
BEGIN

    IF :old.cityid <> :new.cityid THEN
        insert into city (cityid, name, country, province, population, latitude, longitude) values (:new.cityid, :new.name, :new.country, :new.province, :new.population, :new.latitude, :new.longitude);
        DBMS_OUTPUT.PUT_LINE('OK');
    ELSE
        DBMS_OUTPUT.PUT_LINE('The attribute CITYID is already present!');
    END IF;

END;
/

这是我的表“城市”,主键为 NAME+COUNTRY+PROVINCE:

SQL> describe city;
 Name                                                  Null?    Typ
 ----------------------------------------------------- -------- -------
 NAME                                                  NOT NULL VARCHAR2(35)
 COUNTRY                                               NOT NULL VARCHAR2(4)
 PROVINCE                                              NOT NULL VARCHAR2(32)
 POPULATION                                                     NUMBER
 LONGITUDE                                                      NUMBER
 LATITUDE                                                       NUMBER
 CITYID                                                         NUMBER(38)

顺便说一句,我知道 PK 应该指的是“cityid”,但这只是一个练习......

有人知道如何解决这个问题吗?

提前致谢。

【问题讨论】:

:old.city_id 对于插入触发器总是为空; the old pseudorecord is only populated for update and delete。我认为您误解了old 所指的内容,它不是表中的每个现有行。 (但是,查询触发器内的表会得到一个变异表错误......)。这并不意味着它没有开火。插入时会看到什么?您有set serveroutput on 或您的客户的等价物吗? 另外,before insert 在插入之前触发,而不是而不是插入。因此,如果您的触发器有效,它将在:old.cityid &lt;&gt; :new.cityid 时插入重复的行。好好阅读文档:docs.oracle.com/database/121/CNCPT/srvrside.htm#CNCPT88945 好的,首先谢谢。其次,我想我需要一个 INSTEAD-OF 触发器?我正在查询旧的 cityid 以进行比较:'select cityid into cityid_old from city where cityid=:new.cityid;' @MichaelGierer - :old.city_id 确实 not 给你相当于那个查询。 instead of 触发器适用于视图,而不是表。如果您的 before insert 触发器发现一个问题,意味着插入应该发生,您可以引发异常;否则它将正常完成。但是对现有行的测试将是一个问题——对于变异表错误和并发性。我知道你在做实验,但这不是通过触发器来完成的。 【参考方案1】:

嗯,我找到了合适的解决方案:

CREATE OR REPLACE TRIGGER check_cityid
BEFORE INSERT
    ON city
    FOR EACH ROW
DECLARE
    cityid_new city.cityid%TYPE := 0;
BEGIN

    select cityid into cityid_new from city where cityid = :new.cityid;

    IF cityid_new = :new.cityid THEN
        raise_application_error(-20001, 'FEHLER: Diese CITYID ist bereits vorhanden!');
    END IF;

EXCEPTION

    WHEN NO_DATA_FOUND THEN
    BEGIN
        DBMS_OUTPUT.PUT_LINE('CITYID check OK.');
    END;

END;
/

如果一行已经存在,我正确地得到错误 -20001。如果没有这样的 CITYID,则触发器会落入 EXCEPTION,但什么也不做。

非常感谢所有帮助我并向我展示可能性的人!

【讨论】:

你不需要if检查;如果选择没有找到 no-date-found 则 cityid_new = :new.cityid 将始终为真。但是....尝试从两个不同的 Oracle 会话中插入相同的城市 ID - 每个插入的触发器不会看到另一个的待处理数据。也尝试在一个语句中一次插入两行。

以上是关于Oracle SQL - 插入前触发器未触发的主要内容,如果未能解决你的问题,请参考以下文章

Oracle - 在插入前触发检查约束

如果在更新触发之前未在 oracle 中进行更新,则新值与旧值相同

sql - INSTEAD OF INSERT 触发器 - 插入前清除值

更新前Oracle SQL变异表触发器

触发器实现对插入数据的字段更改 Oracle+SQL Server

插入和更新后未触发 SQL Server 触发器