我需要从一个表中删除记录,但删除之前需要检查是否最后一个满足某条件的 如:部门下最后一个用户不可删。
因为部门会有树状的层次结构,删除部门用的存储过程,现在想在用户表里添加一个触发器或是check约束能检查一下,哪一个能实现这种功能?
select count(*) from usertable t where t.deptid = '21'
如果count为1则不可以删
已做的工作
1、尝试使用check,但不知道用哪个操作符,而且好像check是对某行的记录做检查的,不知道能不能对某列的记录做统计检查
2、对触发器,before delete触发,但因为对表记录做了改变,上面的sql语句在触发期中执行错误
因为部门会有树状的层次结构,删除部门用的存储过程,现在想在用户表里添加一个触发器或是check约束能检查一下,哪一个能实现这种功能?
select count(*) from usertable t where t.deptid = '21'
如果count为1则不可以删
已做的工作
1、尝试使用check,但不知道用哪个操作符,而且好像check是对某行的记录做检查的,不知道能不能对某列的记录做统计检查
2、对触发器,before delete触发,但因为对表记录做了改变,上面的sql语句在触发期中执行错误
参考脚本如下:CREATE TABLE usertable
(
ID INT,
deptid CHAR(2)
);INSERT INTO usertable VALUES(1,'01');
INSERT INTO usertable VALUES(2,'01');
INSERT INTO usertable VALUES(3,'21');
INSERT INTO usertable VALUES(4,'21');
INSERT INTO usertable VALUES(5,'21');
COMMIT;
--------- 1 PACKAGE
CREATE OR REPLACE PACKAGE USER_DEPTID AS
V_DEPTID USERTABLE.DEPTID%TYPE;
END USER_DEPTID;
/
-------- 2 trigger1 保存当前要删除的deptid
CREATE OR REPLACE TRIGGER TRI_USERTABLE_1
BEFORE DELETE ON USERTABLE
FOR EACH ROW
BEGIN
USER_DEPTID.V_DEPTID := :old.DEPTID;
END;
/
--------- 3 trigger2 判断是否该删除
CREATE OR REPLACE TRIGGER TRI_USERTABLE_2
AFTER DELETE ON USERTABLE
DECLARE
V_COUNT INT;
BEGIN
DBMS_OUTPUT.put_line(USER_DEPTID.V_DEPTID);
SELECT COUNT(DEPTID)
INTO V_COUNT
FROM USERTABLE
WHERE DEPTID = USER_DEPTID.V_DEPTID;
DBMS_OUTPUT.put_line(V_COUNT);
IF V_COUNT = 0
THEN
RAISE_APPLICATION_ERROR(-20000,
'You can not delete the last deptid:' ||
USER_DEPTID.V_DEPTID);
END IF;
END;
/
----------------------- 测试过程
Connected to Oracle Database 11g Enterprise Edition Release 11.1.0.6.0
Connected as dc_etl
SQL> select * from usertable;
ID DEPTID
--------------------------------------- ------
1 01
2 01
3 21
4 21
5 21
SQL> delete from usertable where id = 1;
1 row deleted
SQL> commit;
Commit complete
SQL> select * from usertable;
ID DEPTID
--------------------------------------- ------
2 01
3 21
4 21
5 21
SQL> delete from usertable where id = 2;
delete from usertable where id = 2
ORA-20000: You can not delete the last deptid:01
ORA-06512: 在 "DC_ETL.TRI_USERTABLE_2", line 12
ORA-04088: 触发器 'DC_ETL.TRI_USERTABLE_2' 执行过程中出错
SQL> select * from usertable;
ID DEPTID
--------------------------------------- ------
2 01
3 21
4 21
5 21
SQL> delete from usertable where id = 3;commit;
delete from usertable where id = 3;commit
ORA-00911: 无效字符
SQL> delete from usertable where id = 3;
1 row deleted
SQL> commit;
Commit complete
SQL> delete from usertable where id = 4;
1 row deleted
SQL> commit;
Commit complete
SQL> delete from usertable where id = 5;
delete from usertable where id = 5
ORA-20000: You can not delete the last deptid:21
ORA-06512: 在 "DC_ETL.TRI_USERTABLE_2", line 12
ORA-04088: 触发器 'DC_ETL.TRI_USERTABLE_2' 执行过程中出错
SQL> select * from usertable;
ID DEPTID
--------------------------------------- ------
2 01
5 21
SQL>
INTO V_COUNT
FROM USERTABLE
WHERE DEPTID = USER_DEPTID.V_DEPTID;
DBMS_OUTPUT.put_line(V_COUNT);
IF V_COUNT = 0
这个地方:where 后面的做什么用?不是只判断要删的数据是不是最后一条就可以了吗?直接就是SELECT COUNT(DEPTID)INTO V_COUNT FROM USERTABLE IF V_COUNT = 0,这样不就已经是最后一条了吗
注意suncrafted强调的几个点,第一,变异表的触发器也就是说,触发器里有对表的select操作。这样的操作多于for each row是不允许的,除非是自治事务第二,主要看suncrafted的实现,定义了一个package,里面定义了一个变量定义了两个trigger,第一个是for each row的before,第二个是表级的after。这里的每个代码都是有作用的。仔细研究一下suncrafted的实现吧。如果你的有错,把你的和suncrafted对照一下,你们的实现思路肯定不一样。