【发布时间】:2017-04-03 13:53:40
【问题描述】:
要求是,
- 如果 DELETING,在 USER_INFO 表中创建的任何记录都不能被删除。尝试从此表中删除记录被捕获,在 AUDIT 表中创建一个条目。
-
如果正在插入,必填字段为 ID、LOGIN_USER
• 在插入表之前,验证不存在具有相同 LOGIN_USER 的现有记录并且记录状态为 True。
• 如果此验证失败,则返回错误代码和指示失败的消息。
• 当向表中插入记录时,事件后触发器将触发更新以下字段:ID 和序列、创建当前日期/时间和操作“记录创建”
-
如果更新,必填字段为 ID,LOGIN_USER
• 更新表中的记录时,将触发后事件触发器,执行以下操作:
o 将记录插入到受影响的表中,复制字段的当前值。
o 使用以下值填充或覆盖以下字段: 主动错误 事件“数据维护审计”
• 事件前触发器将触发并阻止更新非活动记录。
• 状态为 Active = False 的记录可能不会被更新。如果是这样,则必须创建一条新记录。
我已经编写了代码,它执行删除和插入没有任何问题。
问题在于 UPDATE,当它碰到 UPDATING 块时,在 else 块中插入;这里 INSERT 查询由 INSERTING 块递归触发。当我只想运行 UPDATING 块时不应该执行。
请建议,有没有其他方法可以遵循。这是我第一次使用触发代码。
CREATE OR REPLACE TRIGGER BEFORE_DML
BEFORE DELETE OR INSERT OR UPDATE OF ID,LOGIN_USER ON USER_INFO
REFERENCING NEW AS NEW OLD AS OLD
FOR EACH ROW
DECLARE
PRAGMA AUTONOMOUS_TRANSACTION;
V_USER VARCHAR2 (30);
V_NODE VARCHAR2 (50);
V_CNT NUMBER := 0;
V_ACTIVE VARCHAR2 (10);
BEGIN
SELECT SYS_CONTEXT ('USERENV', 'IP_ADDRESS')
INTO V_NODE
FROM DUAL;
IF DELETING THEN
INSERT
INTO AUDIT (IDS,
ACTION,
IP_ADDRESS,
LOGIN,
CREATED
)
VALUES(AUDIT_SEQ.NEXTVAL,
'Deletion',
V_NODE,
SYS.LOGIN_USER,
SYSDATE
);
COMMIT;
RAISE_APPLICATION_ERROR (-20002, 'USER_INFO table data can not be deleted');
END IF; --Close IF for DELETING
IF INSERTING THEN
SELECT COUNT (1)
INTO V_CNT
FROM USER_INFO
WHERE LOGIN_USER = :NEW.LOGIN_USER
AND STATUS='TRUE';
IF ( V_CNT >=1 ) THEN
RAISE_APPLICATION_ERROR (-20002, 'DATABASE LOGIN USER ALREADY EXISTS', TRUE);
END IF;
:NEW.ID := DBLOGIN_SEQ.NEXTVAL;
:NEW.CREATED := SYSDATE;
:NEW.ACTION := 'Record Creation' ;
END IF; --CLOSE IF FOR INSERTING
IF UPDATING THEN
IF :OLD.STATUS = 'INACTIVE'
THEN
RAISE_APPLICATION_ERROR (-20002, 'INACTIVE RECORDS CAN NOT BE UPDATED');
ELSE IF :OLD.STATUS = 'FALSE' THEN
INSERT INTO USER_INFO(ID,
STATUS,
LOGIN_USER,
CREATED,
ACTION
)
VALUES(DBLOGIN_SEQ.NEXTVAL,
'INVALID',
:OLD.LOGIN_USER,
SYSDATE,
'FALSE RECORD UPDATED '
);
COMMIT;
ELSE
INSERT INTO USER_INFO(ID,
STATUS,
LOGIN_USER,
CREATED,
ACTION
)
VALUES(DBLOGIN_SEQ.NEXTVAL,
'FALSE',
:OLD.LOGIN_USER, --NEW.LOGIN_USER
SYSDATE,
'Audit for data maintenance'
);
COMMIT;
END IF;
END IF;
END IF; --CLOSE IF FOR UPDATING
END BEFORE_DML;
/
【问题讨论】:
-
这是家庭作业,还是您正在尝试解决实际问题?你可以做一些hack-y,你有一个带有公共全局
in_before_dml_trigger变量的包,你在update块中设置并在触发器顶部检查。这将解决眼前的问题,但从维护和支持的角度来看,这是一种皇家痛苦。您在触发器中所做的事情也只能在单用户系统中工作——唯一索引实际上可以确保在多用户系统中login_user只有一行。 -
谢谢。这种做法正确吗?