2010-04-11 131 views
8

我对FOREIGN KEY和CHECK约束之间的区别感到困惑 - 他们似乎达到了相同的结果。检查和外键有什么区别?

我的意思是我可以创建一个表并在另一个表上强制执行一个外键,但是我可以创建一个CHECK来确保另一个表中的值。

有什么区别以及何时使用这个或那个?

回答

6

一个外键约束确保项不存在

编辑 另一个表

按照正确的注释存在于另一个表...或相同的表。 - Mark Byers

CHECK约束确保条目遵循一些规则。

CHECK Constraints

CHECK约束通过限制由列接受的值执行域的完整性。它们与FOREIGN KEY约束类似,它们控制放在列中的值。 区别在于它们如何确定哪些值是有效的:FOREIGN KEY约束从另一个表中获取有效值的列表,并且CHECK约束根据不基于另一列中的数据的逻辑表达式确定有效值。

+4

存在于另一张桌子......或同一张桌子上。 – 2010-04-11 17:29:19

+0

CHECK约束确定不基于另一列中的数据的...。 不太正确,检查约束可以包含多列(至少10g)。更好的是说“不是基于另一个表中的数据”。 – Juraj 2010-04-19 20:43:38

2

外键约束比CHECK约束更强大。
外键约束意味着列(在当前表中)只能具有已存在于外表列中的值(可能包括相同的表,通常是为分层数据完成的)。这意味着随着值列表的变化 - 变大或变小 - 不需要更新约束。

检查约束不能引用当前表之外的任何列,也不能包含子查询。通常,这些值是硬编码的,如BETWEEN 100 and 999IN (1, 2, 3)。这意味着随着情况的变化,您必须每次更新CHECK约束。此外,外键关系在实体关系图(ERD)上可见,而CHECK约束永远不会。好处是有人可以读取ERD并从中构建查询,而无需使用大量的DESC表命令来知道哪些列是哪里以及哪些与构建适当的连接有关。

最佳做法是首先使用外键(和支持表)。使用CHECK约束作为不能使用外键的情况的备份,而不是验证数据的主要解决方案。

+2

外键不必是单列键。 – 2010-04-11 18:04:04

1

它取决于您的DBMS(您没有指定),但从某种意义上说,您是正确的:外键约束是检查约束的特定情况。有数据库管理系统不允许你制定一个外键约束作为检查约束。

检查约束的主要目的是描述适用于表中单个行的条件。例如,我有一张元素表(如氢,氦,...),并且元素的符号被限制为以大写字母开头,并且后面跟着零个,一个或两个小写字母(两个小写字母,但尚未被发现但预测的元素:Uus - ununseptium(117) ,它刚刚被隔离但尚未命名)。这可以是一个CHECK约束的主题:

CHECK(Symbol MATCHES "[A-Z][a-z]{0,2}") 

假设MATCHES存在并支持适当的正则表达式语言。

你也可以有一个比较值的检查约束:

CHECK(OrderDate <= ShipDate OR ShipDate IS NULL) 

为了表达一个外键约束的检查约束,你要允许CHECK子句中执行查询。假设:

CHECK(EXISTS(SELECT * FROM SomeTable AS s 
       WHERE ThisTable.pk_col1 = s.pk_col1 AND 
        ThisTable.pk_col2 = s.pk_col2)) 

此示例显示了一些问题。我没有一个方便的表格别名,用于编写检查约束的表格 - 我认为它是'ThisTable'。构造是冗长的。假设在SomeTable主键的列pk_col1pk_col2声明,那么外键子句是更加紧凑:

FOREIGN KEY (pk_col1, pk_col2) REFERENCES SomeTable 

或者,如果你引用一个替代键,而不是主键:

FOREIGN KEY (pk_col1, pk_col2) REFERENCES SomeTable(ak_col1, ak_col2) 

这在命名上更加紧凑 - 因此出错的可能性更小 - 并且可以由服务器进行特殊配置,因为特殊符号意味着它知道它正在处理外键约束,而通用检查子句必须仔细检查,看它是否符合许多可能的形式之一相当于外键。

问题问:何时使用检查约束以及何时使用外键约束?

  • 使用CHECK约束来指定可在单个行中检查的条件。
  • 使用FOREIGN KEY约束来指定当前行中的值必须与某个表的某个其他唯一键(候选键,通常是主键而非备选键)中的行的值匹配 - 这可能会成为同一张桌子或(更一般地)不同的桌子。