26

任何人都可以解释(或建议网站或论文)触发器、断言和检查之间的确切区别,还可以描述我应该在哪里使用它们吗?

编辑:我的意思是在数据库中,而不是在任何其他系统或编程语言中。

4

5 回答 5

63

触发器- 触发器是在数据库中更新、插入或删除之前或之后执行的一段 SQL。简单英语的触发器示例可能类似于:在更新客户记录之前,保存当前记录的副本。这看起来像:

CREATE TRIGGER triggerName
AFTER UPDATE
    INSERT INTO CustomerLog (blah, blah, blah)
    SELECT blah, blah, blah FROM deleted

断言和检查之间的区别有点模糊,许多数据库甚至不支持断言。

检查约束- 检查是一段 SQL,它确保在对记录采取操作之前满足条件。用简单的英语来说,这类似于:所有客户的账户中必须有至少 100 美元的账户余额。这看起来像:

ALTER TABLE accounts 
ADD CONSTRAINT CK_minimumBalance
CHECK (balance >= 100)

任何尝试在余额列中插入小于 100 的值都会引发错误。

断言- 断言是一段 SQL,它确保满足条件或停止对数据库对象执行的操作。这可能意味着锁定整个表甚至整个数据库。

让事情变得更加混乱 - 触发器可用于强制检查约束,并且在某些数据库中可以代替断言(通过允许您运行与正在修改的表无关的代码)。初学者的一个常见错误是在需要触发器时使用检查约束或在需要检查约束时使用触发器。

一个例子:所有新开户的客户必须有100美元的余额;但是,一旦开设帐户,他们的余额可能会低于该金额。在这种情况下,您必须使用触发器,因为您只希望在插入新记录时评估条件。

于 2010-03-14T20:39:04.837 回答
14

在 SQL 标准中,ASSERTIONS 和 CHECK CONSTRAINTS 都是关系理论所称的“约束”:数据库中实际包含的数据必须遵守的规则。

两者之间的区别在于 CHECK CONSTRAINTS 在某种意义上更“简单”:它们是仅与单行相关的规则,而 ASSERTION 可以涉及任意数量的其他表,或同一行中的任意数量的其他行桌子。这显然使 DBMS 构建者支持它(非常!)变得更加复杂,这反过来也是他们不支持它的原因:他们只是不知道如何去做。

TRIGGER 是可执行代码片段,可以向 DBMS 声明,每次在某个表上完成某种更新操作(插入/删除/更新)时,都应该执行这些代码片段。因为触发器可以引发异常,所以它们是实现与断言相同的事物的一种手段。但是,对于触发器,仍然是程序员必须完成所有编码,并且不能犯任何错误。

编辑

Onedaywhen 的评论重新。断言/检查 cnstr。是正确的。区别更加微妙(并且令人困惑)。该标准确实允许 CHECK 约束中的子查询。(虽然大多数产品不支持它,所以我的“与单行相关”对于大多数 SQL 产品都是正确的,但对于标准不支持。)那么还有区别吗?是的,还有。甚至不止一个。

第一种情况:TABLE MEN (ID:INTEGER) 和 TABLE WOMEN(ID:INTEGER)。现在想象一条规则,大意是“在 MEN 表和 WOMEN 表中都不能出现 ID 值”。这是一个单一的规则。ASSERTION 的意图恰恰是数据库设计者会陈述这个单一的规则[并完成它],并且 DBMS 会知道如何处理这个[当然是有效的]以及如何执行这个规则,无论什么特别对数据库进行更新。在该示例中,DBMS 将知道它必须在 INSERT INTO MEN 和 INSERT INTO WOMEN 时检查此规则,而不是在 DELETE FROM MEN/WOMEN 或 INSERT INTO <anyothertable> 时检查。

但是 DBMS 还不够聪明,无法做到这一切。那么需要做什么呢?数据库设计者必须将两个 CHECK 约束添加到他的数据库,一个到 MEN 表(检查新插入的 MEN ID 与 WOMEN 表)和一个到 WOMAN 表(检查相反的方式)。你的第一个区别是:一个规则,一个断言,两个检查约束。CHECK 约束是比 ASSERTION 更低的抽象级别,因为它们要求设计者自己做更多的思考(a)可能导致其 ASSERTION 被违反的所有类型的更新,以及(b)应该进行哪些特定检查他在 (a) 中发现的任何特定“更新类型”。(虽然我不太喜欢就什么是“什么”和什么是“如何”做出“绝对”的陈述,但我总结一下,检查约束需要数据库设计者更多的“如何”思考(程序),而断言允许数据库设计者专注于“WHAT”(声明性)。)

第二种情况(尽管我对此并不完全确定——所以请谨慎对待):只是您的平均 RI 规则。当然,您习惯于使用一些 REFERENCES 子句来指定它。但是想象一下,REFERENCES 子句不可用。像“每个订单必须由已知客户下达”这样的规则实际上就是这样一个规则,因此:一个单一的断言。然而,我们都知道这样的规则总是可以通过两种方式被违反:插入一个 ORDER(在这个例子中),和删除一个 CUSTOMER。现在,根据前面的 MAN/WOMEN 示例,如果我们想使用 CHECK 约束来实现这个单一规则/ASSERTION,那么我们必须编写一个 CHECK 约束来检查 CUSTOMER 在插入 ORDER 时是否存在,但是什么 CHECK 约束可以我们写它会在删除时做任何需要的事情来自客户?据我所知,它们根本不是为此目的而设计的。您的第二个区别是:CHECK 约束仅与 INSERT 相关联,ASSERTIONS 可以定义也将在 DELETE 时检查的规则。

第三种情况:想象一个表 COMPOS (componentID:... percent:INTEGER),以及“所有百分比的总和必须始终等于 100”的规则。这是一个单一的规则,并且一个 ASSERTION 能够指定它。但是试着想象一下你将如何使用 CHECK 约束来执行这样的规则......如果你有一个有效的表,例如,三个非零行加起来一百,你将如何对这个表应用任何可以生存的更改你的 CHECK 约束?您不能删除或更新(减少)任何行,而无需添加其他替换行,或更新剩余的行,总和相同的百分比。同样对于插入或更新(增加)。您至少需要延迟约束检查,然后您要检查什么?你的第三个区别是:

于 2010-03-14T20:41:20.433 回答
7

断言不修改数据,它们只检查某些条件

触发器更强大,因为它可以检查条件并修改数据


断言未链接到数据库中的特定表,也未链接到特定事件

触发器链接到特定表和特定事件

于 2014-05-08T07:05:17.647 回答
3

数据库约束涉及更新数据库时必须满足的条件。在 SQL 中,如果约束条件评估为 false,则更新失败,数据保持不变并且 DBMS 生成错误。

CHECK和都是ASSERTIONSQL 标准定义的数据库约束。一个重要的区别是 aCHECK应用于特定的基表,而 anASSERTION应用于整个数据库。考虑一个约束,将表中的组合行限制T1T2总共 10 行,例如

CHECK (10 >= (
              SELECT COUNT(*)
                FROM (
                      SELECT *
                        FROM T1
                      UNION
                      SELECT * 
                        FROM T2
                     ) AS Tn
             ))

假设表是空的。如果这是作为ASSERTION唯一应用并且用户尝试插入 11 行,T1那么更新将失败。如果约束仅作为CHECK约束应用,则同样适用T1。但是,如果将约束作为CHECK约束应用到T2仅约束将成功,因为语句目标T1不会导致应用的约束T1被测试。

anASSERTION和 aCHECK都可以延迟(如果声明为DEFERRABLE),允许数据暂时违反约束条件,但仅限于事务中。

ASSERTIONCHECK涉及子查询的约束是核心标准 SQL 之外的功能,并且没有一个主要的 SQL 产品支持这些功能。MS Access(不完全是工业级产品)支持CHECK涉及子查询的约束,但不支持可延迟的约束,而且约束测试总是逐行执行,实际结果是功能非常有限。

CHECK约束一样,触发器应用于特定表。因此,触发器可用于实现与CHECK约束相同的逻辑,但不能用于实现ASSERTION. 触发器是过程代码,与约束不同,用户必须对性能和错误处理等问题承担更多责任。大多数商业 SQL 产品都支持触发器(前面提到的 MS Access 不支持)。

于 2012-02-06T09:35:01.077 回答
0

表达式应该为真才能触发触发器,但只要表达式为假,就会评估检查。

于 2013-04-18T08:26:29.443 回答