check和外键有什么区别?

时间:2010-04-11 17:25:57

标签: sql oracle

我对FOREIGN KEY和CHECK约束之间的区别感到很困惑 - 在我看来它们实现了相同的结果。

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

有什么区别以及何时使用其中一种?

4 个答案:

答案 0 :(得分:7)

FOREIGN KEY约束确保条目在

中存在

修改 另一张表

根据正确评论存在于另一个表格......或同一个表格中。 - Mark Byers

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

CHECK Constraints

CHECK约束通过限制列接受的值来强制域完整性。它们类似于FOREIGN KEY约束,因为它们控制放入列中的值。 区别在于它们如何确定哪些值有效:FOREIGN KEY约束从另一个表获取有效值的列表,CHECK约束从不基于另一列中的数据的逻辑表达式确定有效值。 /强>

答案 1 :(得分:3)

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

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

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

答案 2 :(得分:1)

这取决于您的DBMS(您未指定),但从某种意义上说,您是正确的:外键约束是检查约束的特定情况。有些DBMS不允许您将外键约束表示为检查约束。

检查约束的主要目的是描述适用于表中单个行的条件。例如,我有一个元素表(如Hydrogen,Helium,...),元素的符号被约束为以大写字母开头,后跟零,一个或两个小写字母(尚未发现但预测元素的两个小写字母: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子句就更加紧凑:

FOREIGN KEY (pk_col1, pk_col2) REFERENCES SomeTable

或者,如果您要引用备用键,而不是主键:

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

这在概念上更紧凑 - 因此错误的可能性更小 - 并且可以由服务器进行特殊处理,因为特殊符号表示它知道它正在处理外键约束而普通检查子句有要仔细检查它是否与许多可能的形式相匹配,这些形式等同于外键。

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

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

答案 3 :(得分:0)

考虑这样的场景:

  1. 表A包含关键字列,其值必须在提供的数千个关键字中。
  2. 您希望如何实施约束?<​​br/> 硬编码检查条件,例如SELECT date , table_id , name as table_name FROM log_list join table_name_list on log_list.table_id = table_name_list.table_id and log_list.company_name like '%something%' WHERE date between @startdate and @enddate ,或者只是将提供的关键字作为另一个表导入,并将外键约束设置为表A的关键字列。