我正在使用SQL Server 2012 Management Studio。以下是我要写的内容。我真的很感激一些帮助。
ALTER TABLE [tablename] WITH CHECK ADD CONSTRAINT [constraintname] CHECK
(([column]='A' OR [column]='B' OR [column]='C' OR [column]='D'))
但是当我们通过SQL Server 2012 Management Studio生成脚本时,我收到以下声明..
ALTER TABLE [tablename] WITH NOCHECK ADD CONSTRAINT [constraintname] CHECK
(([column]='A' OR [column]='B' OR [column]='C' OR [column]='D'))
GO
ALTER TABLE [tablename] CHECK CONSTRAINT [constraintname]
为什么生成的脚本首先使用nocheck构建,然后对表进行检查?如果我在没有nocheck的情况下创建检查约束会发生什么?
答案 0 :(得分:2)
生成的脚本使用NOCHECK,因此即使表中的值不符合,也始终会创建约束。这对于自动生成的脚本更好,因为它可以确保正确创建或修改数据库模式。
我首先想到,生成的脚本中的第二个语句是确保查询优化器将考虑约束。 (参见下面的参考文献。)然而,在进一步调查中,似乎第二个陈述没有任何影响 - 请参阅我的第二个答案。
当您手动执行此操作时,使用WITH CHECK,您可以立即看到该语句失败并采取纠正措施。然后再次运行该语句。
如果使用WITH NOCHECK选项,则可能不会注意到数据无效。就个人而言,我总是在做ALTER TABLE时使用WITH CHECK来添加约束。此外,联机丛书表示不建议使用WITH NOCHECK,除非在极少数情况下 - 请参阅下面的参考资料。
为了证明这种差异,我们首先创建一个表并插入一些值。
CREATE TABLE dbo.T
(
id int NOT NULL IDENTITY(1,1),
[column] nchar(1) NOT NULL
);
INSERT INTO dbo.T ([column])
VALUES (N'A'), (N'B'), (N'C'), (N'E');
尝试更改表并添加约束,指定WITH CHECK。这会失败,因为表中的某些数据不符合约束条件。
ALTER TABLE dbo.T
WITH CHECK
ADD CONSTRAINT CK_Column CHECK ([column] IN (N'A', N'B', N'C', N'D'));
通过使用sys.check_constraints系统目录视图,让我们看看是否已创建约束。这表明尚未创建约束。
SELECT *
FROM sys.check_constraints
WHERE [parent_object_id] = OBJECT_ID(N'dbo.T');
再次尝试,这次指定WITH NOCHECK。这次成功完成。但是,没有警告表中的数据无效,这可能是不合需要的。
ALTER TABLE dbo.T
WITH NOCHECK
ADD CONSTRAINT CK_Column CHECK ([column] IN (N'A', N'B', N'C', N'D'));
我们可以验证是否已创建检查约束。
请参阅联机丛书> ALTER TABLE(Transact-SQL):https://msdn.microsoft.com/en-GB/library/ms190273.aspx>与检查|没有检查
如果您不想针对现有数据验证新的CHECK或FOREIGN KEY约束,请使用WITH NOCHECK。除极少数情况外,我们不建议这样做。将在所有后续数据更新中评估新约束。添加约束时由WITH NOCHECK抑制的任何约束违规可能会导致将来更新失败,如果他们使用不符合约束的数据更新行。
此处显示第二个自动生成的语句的原因:
查询优化器不考虑使用NOCHECK定义的约束。在使用ALTER TABLE表WITH CHECK CHECK CONSTRAINT ALL重新启用它们之前,将忽略此类约束。
答案 1 :(得分:1)
在我之前的回答后深入挖掘......
如果在使用WITH NOCHECK选项创建CHECK约束后运行以下语句,我们可以看到约束已启用(is_disabled = 0),但它不受信任。
SELECT name, is_disabled, is_not_trusted
FROM sys.check_constraints
WHERE [parent_object_id] = OBJECT_ID(N'dbo.T');
运行SSMS生成的第二个语句没有任何区别。检查约束仍然不受信任,并且已经启用。
ALTER TABLE dbo.T
CHECK CONSTRAINT CK_Column;
我们必须修复数据。 (或改变约束。)
UPDATE dbo.T
SET [column] = N'D'
WHERE [column] = N'E';
然后运行此语句。请注意,这次我们指定WITH CHECK,以便验证数据。
ALTER TABLE dbo.T
WITH CHECK
CHECK CONSTRAINT CK_Column;
最后我们可以看到约束变得可信(is_not_trusted = 0),这意味着它可以被查询优化器使用。
SELECT name, is_disabled, is_not_trusted
FROM sys.check_constraints
WHERE [parent_object_id] = OBJECT_ID(N'dbo.T');
因此,总而言之,就我所见,SSMS生成的第二个语句没有用处,因为约束已经启用。
请参阅联机丛书> sys.check_constraints(Transact-SQL):https://msdn.microsoft.com/en-GB/library/ms187388.aspx
另见联机丛书> ALTER TABLE(Transact-SQL):https://msdn.microsoft.com/en-GB/library/ms190273.aspx> {检查| NOCHECK} CONSTRAINT
指定启用或禁用constraint_name。此选项只能与FOREIGN KEY和CHECK约束一起使用。指定NOCHECK时,将禁用约束,并且不会根据约束条件验证将来对列的插入或更新。无法禁用DEFAULT,PRIMARY KEY和UNIQUE约束。
SQLServerCentral.com>检查和外键约束提高了查询性能:http://www.sqlservercentral.com/articles/Performance+Tuning/71264/