我在MySQL中AFTER DELETE
触发器中引用当前行时遇到问题。假装我有以下books
表:
+----+------+----------+
| id | name | ordering |
+----+------+----------+
| 1 | It | 3 |
| 2 | Cujo | 1 |
| 3 | Rage | 2 |
+----+------+----------+
我想创建一个触发器,它会减少ordering
值大于删除行中ordering
值的所有行。例如,如果我DELETE FROM books WHERE id = 2
,我希望结果表看起来像:
+----+------+----------+
| id | name | ordering |
+----+------+----------+
| 1 | It | 2 |
| 3 | Rage | 1 |
+----+------+----------+
我试过了:
DROP TRIGGER IF EXISTS reorder_books_on_delete;
DELIMITER $$
CREATE TRIGGER reorder_books_on_delete
AFTER DELETE ON books
FOR EACH ROW
BEGIN
IF ordering > OLD.ordering
THEN
UPDATE books SET ordering = ordering - 1
WHERE id = id;
END IF;
END$$
DELIMITER ;
但是当我在桌面上执行DELETE
时,这会导致错误:
ERROR 1054(42S22):未知列'订购'在' where子句'
这是指if
语句,那么如何引用ON DELETE
触发器中的当前行?该列肯定存在。
答案 0 :(得分:1)
它失败的原因是因为没有current
行,因此ordering
列不存在,它应该在WHERE
子句中使用,如下所示:
DROP TRIGGER IF EXISTS reorder_books_on_delete;
DELIMITER $$
CREATE TRIGGER reorder_books_on_delete
AFTER DELETE ON books
FOR EACH ROW
BEGIN
UPDATE books SET ordering = ordering - 1
WHERE ordering > OLD.ordering;
END$$
DELIMITER ;
但是,根据MySQL的documentation,您无法执行此操作,它将返回以下错误:
SQL错误(1442):无法更新已存储的表“书籍” 函数/触发器,因为它已被调用的语句使用 这个存储的函数/触发器。
因此,您必须在单个事务中UPDATE
查询后运行另一个DELETE
查询才能实现此功能。
答案 1 :(得分:1)
如Darshan所说,你不能用触发器做到这一点......但是,程序可以为你制造!
DROP PROCEDURE IF EXISTS delete_book;
DELIMITER //
CREATE PROCEDURE delete_book(IN pId INT)
BEGIN
set @a = (
SELECT ordering
FROM books
WHERE id = pId
);
UPDATE books SET ordering = ordering - 1
WHERE ordering > @a;
delete from books
WHERE id = pId;
END
//
DELIMITER ;
而你只是而不是DELETE FROM books WHERE id = 4
来制作CALL delete_book(4);