无法从触发器内的 table 中删除

Can't delete from a table inside a trigger

我正在为我的一门课程 classes 构建这个关于大学的数据库,我正在尝试创建一个触发器,不允许教授未满 21 岁。

我有一个人 class,然后是一个教授 class。

我想要发生的是,您创建一个 Person 对象,然后使用该 Person 对象的 id 创建一个 Professor 对象,但是,如果该 Person 未满 21 岁,请删除该 Professor 对象,然后删除该 Person 对象。

一切正常,直到“删除 Person 对象”部分没有发生,我不确定为什么。有帮助吗?

这是我的sqlite代码:

AFTER INSERT ON Professor
FOR EACH ROW
WHEN strftime('%J', 'now') - strftime('%J', (SELECT dateOfBirth from Person WHERE personId = NEW.personId)) < 7665 -- 21 years in days
BEGIN
    SELECT RAISE(ROLLBACK, 'Professor cant be under 21');
    DELETE FROM Person WHERE (personId= new.personId);

END;```

一个常见的问题是有许多没有要回滚到的当前事务范围,这会导致此错误:

Error: cannot rollback - no transaction is active

如果发生这种情况,则触发器执行将中止并且删除永远不会执行。

如果ROLLBACK确实成功了,那么这就产生了一个悖论,通过回滚到在严格的ACID环境中执行触发器之前继续执行其余部分将无效这个触发器,因为 INSERT 从未真正发生过。为避免这种歧义状态,对 RAISE() 的任何调用 NOT IGNORE 都将中止触发器的处理。

CREATE TRIGGER - The RAISE()
When one of RAISE(ROLLBACK,...), RAISE(ABORT,...) or RAISE(FAIL,...) is called during trigger-program execution, the specified ON CONFLICT processing is performed and the current query terminates. An error code of SQLITE_CONSTRAINT is returned to the application, along with the specified error message.

NOTE: This behaviour is different to some other RDBMS, for instance see this explanation on MS SQL Server where execution will specifically continue in the trigger.

由于 OP 不提供演示场景的调用代码,因此值得一提的是 RAISE(ROLLBACK,)

上的 SQLite

If no transaction is active (other than the implied transaction that is created on every command) then the ROLLBACK resolution algorithm works the same as the ABORT algorithm.

一般来说,如果您想创建 Person 然后创建 Professor 作为单个操作,您会创建一个 Stored Procedure 来首先验证输入,防止原始在开头插入。

为了保持引用完整性,即使使用了 SP,您仍然可以在 Professor 记录上添加检查约束或从 [=] 引发 ABORT 44=]BEFORE 触发以防止 INSERT 首先发生:

BEFORE INSERT ON Professor
FOR EACH ROW
WHEN strftime('%J', 'now') - strftime('%J', (SELECT dateOfBirth from Person WHERE personId = NEW.personId)) < 7665 -- 21 years in days
BEGIN
    SELECT RAISE(ABORT, 'Professor can''t be under 21');
END

这样,由调用进程来管理如何处理错误。 ABORT 可以在调用逻辑中被捕获,并且会有效地导致回滚外部事务,但关键是调用逻辑应该处理负面影响。作为一般规则触发器,级联逻辑应该只执行积极的副作用,也就是说它们应该只在插入行成功时影响数据。在这种情况下,我们正在回滚插入,因此很难确定为什么 Person 会被删除。