2014-05-01 246 views
0

我试图在delete之前创建一个触发器,所以如果用户输入了错误的id,他会收到一条错误消息。
我用下面的代码...删除SQL上的触发器之前。

CREATE TRIGGER pos_id 
BEFORE DELETE ON CLIENTS 
FOR EACH ROW 
BEGIN 

DECLARE TOTAL INT; 
SET TOTAL = (SELECT COUNT(*) FROM CLIENTS) ; 

IF(old.id <0 OR old.id > total) 
    THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Error. Client doesn't exist'; 

END IF ; 
END 

此外,这是行不通的。该消息没有出现,并且触发似乎不起作用。当我正在寻找解决我在互联网上遇到的问题时,我学到了一些关于触发器的知识,而我发现这些触发器非常有趣。

但是当我尝试...

CREATE TRIGGER pos_id 
    INSTEAD OF DELETE ON CLIENTS 
    BEGIN 
(...) 

或...

CREATE TRIGGER pos_id 
ON CLIENTS 
INSTEAD OF DELETE 
BEGIN 
(...) 

我得到一个syntax error。所以我真的有两个问题:

1º为什么我之前删除触发器不起作用?我真的错过了什么吗?
2º与删除触发器相关的语法错误是什么?

非常感谢。

+0

PhPMyAdmin。我意识到我犯了一个很大的错误,''IF(old.id <0 OR old.id> total)'',因为如果我删除了客户端,可能会有一个id = 4的客户端,但count(*)会返回一个次要号码。 –

回答

0

你不能用触发器做到这一点。触发器将只火了删除匹配至少一个排,因此,如果用户试图删除一个不存在的客户端,而不是让你自定义的错误,他们将刚刚得到这个:

mysql > delete from clients where id = -1; 
Query OK, 0 rows affected (0.00 sec) 

此外,你应该显式检查行的存在,而不是依赖于输入是否小于零或大于表中的行数等。还需要在错误消息中转义撇号。

您可以使用存储过程完成此操作。如果您可以让用户使用存储过程删除行而不是对客户端表执行显式删除,那么您可以抛出自定义错误。

例如(我不知道id列的数据类型,我认为INT,但你应该改变它来匹配您的表中的实际数据类型):

delimiter $$ 

drop procedure if exists delete_client $$ 

create procedure delete_client (p_client_id int) 
begin 
    declare v_client_exists int default 0; 

    select count(*) 
    into v_client_exists 
    from clients 
    where id = p_client_id; 

    if (v_client_exists = 0) 
    then 
    SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Error. Client doesn''t exist'; 
    else 
    delete from clients where id = p_client_id; 
    end if; 

end $$ 

delimiter ; 

然后做像这样删除:

mysql > call delete_client(-1); 
ERROR 1644 (45000): Error. Client doesn't exist 
mysql > call delete_client(2); 
Query OK, 1 row affected (0.00 sec) 
mysql > call delete_client(2); 
ERROR 1644 (45000): Error. Client doesn't exist 
+0

此外,触发器中的'old.id'是表中的现有值,而不是您尝试使用的值。加上@IKE关于_“输入是否...大于表中的行数”的评论@这是第二种方式的错误编码,因为如果行被删除,则count(*)'< >'max(id)'。 – Turophile