2014-05-01 245 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