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 <> :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 中进行更新,则新值与旧值相同
sql - INSTEAD OF INSERT 触发器 - 插入前清除值