まず、最初の試みから、いくつかの構文エラーを回避します。
-
FOR EACH STATEMENT
の代わりに 、FOR EACH ROW
である必要があります 。 - 区切り文字を
//
に定義済みなので;//
を使用する必要があります (;
の代わりに )DROP TRIGGER IF EXISTS ..
ステートメント。 -
Row_Count()
Before Delete Trigger
の値は0になります 、行はまだ更新されていないため。したがって、このアプローチは機能しません。
ここでの秘訣は、セッションレベルのアクセス可能(および永続的)を使用することです。 ユーザー定義変数
。変数を定義できます。たとえば、@rows_being_deleted
、後でそれがすでに定義されているかどうかを確認します。
For Each Row
削除されるすべての行に対して同じステートメントのセットを実行します 。したがって、セッション変数がすでに存在するかどうかを確認するだけです。そうでない場合は、定義できます。したがって、基本的に、最初の行(削除される)については定義され、セッションが存在する限り存続します。
これで、削除する行がさらにある場合、Triggerは残りの行に対して同じステートメントのセットを実行します。 2行目では、以前に定義された変数が検出され、例外をスローすることができます。
注 同じセッション内で、複数の削除ステートメントがトリガーされる可能性があること。したがって、例外をスローする前に、@rows_being_deleted
を設定する必要があります 値をnull
に戻します 。
以下が機能します:
DELIMITER //
DROP TRIGGER IF EXISTS prevent_multiple_deletion //
CREATE TRIGGER prevent_multiple_deletion
BEFORE DELETE ON `test`
FOR EACH ROW
BEGIN
-- check if the variable is already defined or not
IF( @rows_being_deleted IS NULL ) THEN
SET @rows_being_deleted = 1; -- set its value
ELSE -- it already exists and we are in next "row"
-- just for testing to check the row count
-- SET @rows_being_deleted = @rows_being_deleted + 1;
-- We have to reset it to null, as within same session
-- another delete statement may be triggered.
SET @rows_being_deleted = NULL;
-- throw exception
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'Cannot delete more than one order per time!';
END IF;
END //
DELIMITER ;
DBフィドルデモ1 :複数の行を削除しようとしています。
DELETE FROM `test` WHERE `id`< 5;
結果:
DBフィドルデモ2 :1行だけを削除しようとしています
クエリ#1
DELETE FROM `test` WHERE `id` = 1;
クエリ#2
SELECT * FROM `test`;
| id | a | b |
| --- | --- | --- |
| 2 | 3 | 4 |