我有一个运行一些集成测试的项目。该项目每次都会创建一个新数据库,并针对这个新数据库运行测试。最近我把这个项目搬到了一个新的服务器上,当从数据库中删除数据时我遇到了一些问题。
我执行以下查询:
DELETE FROM TABLE1;
DELETE FROM TABLE2;
DELETE FROM TABLE3;
在服务器A上,一切都按预期工作,但是使用服务器B我收到以下错误:
DELETE语句与REFERENCE约束冲突 " FK _....&#34 ;.冲突发生在数据库中 " TestDB",table" Table1",column ' ...'
两台服务器都具有相同版本的SQL Server
Microsoft SQL Server 2012 (SP1) - 11.0.3401.0 (X64)
Jan 9 2014 13:22:15
Copyright (c) Microsoft Corporation
Standard Edition (64-bit) on Windows NT 6.2 <X64> (Build 9200: ) (Hypervisor)
架构和数据都相同,并且使用相同的流程创建数据库。
任何想法?
答案 0 :(得分:3)
实际上,两个地方都可以使用相同的模式,甚至可以使用相同的数据,并且会遇到不同的行为。怎么样?因为可以禁用约束(CHECK和FOREIGN KEY)。烨。
要查看有问题的外键是启用还是禁用,只需运行以下命令,确保在WHERE子句中放入有问题的FK名称:
SELECT *
FROM sys.foreign_keys
WHERE [name] = N'{name_of_FK_in_question}';
查看名为is_disabled
的列。我怀疑它在服务器A上设置为1
(其中一切都“有效”)并且在服务器B上设置为0
(事情“不起作用”)。我把“工作”和“不工作”放在引号中,因为如果确实如此,那么现实就与你所经历的相反。这意味着,启用FK并获得错误的系统实际上正在工作,因为这就是FK应该做的事情。没有出错的系统可能允许孤立(即坏)数据。
要启用FK,请运行以下命令:
ALTER TABLE {table_name}
WITH CHECK -- verifies the data currently in the table
CHECK CONSTRAINT [{name_of_FK_in_question}];
当然,如果存在不良数据,您需要:
首先删除错误数据,或
在WITH NOCHECK
上指定ALTER
,以便接受错误数据:
ALTER TABLE {table_name}
WITH NOCHECK -- accept the bad data aleady there
CHECK CONSTRAINT [{name_of_FK_in_question}];
然而,这并不能100%解决问题。如果再次运行SELECT查询(如上所述),您应该会看到is_disabled
字段现在设置为0
。但是,如果您查看is_not_trusted
字段,则会将其设置为1
。如果某个约束已启用但尚未受信任,它将按预期强制执行其规则,但查询优化器(QO)将忽略它,这通常不是一件好事,因为约束实际上不仅用于强制执行数据完整性规则,而且也作为QO的线索逻辑上减少某些查询中的某些步骤(即它们有时有助于提高性能)。为了使约束成为“受信任”,您必须删除错误数据并通过以下方式验证表中的所有约束:
ALTER TABLE {table_name}
WITH CHECK -- verifies the data currently in the table
CHECK CONSTRAINT [{name_of_FK_in_question}];
但是,如果由于某种原因你需要“坏”数据,那么你将只有一个外键来强制数据完整性,但没有提高性能的潜力(仍然是比没有定义FK更好:)。
有关详细信息,请参阅ALTER TABLE的MSDN页面。
为了完整起见,我还要提到在服务器A(没有错误的地方)上可能会使用选项ON DELETE CASCADE
来定义FK,该选项会在之前自动删除和相关数据从正在删除的表中删除行,而服务器B(存在错误)没有指定ON DELETE
操作(或指定为NO ACTION
)。但是,这是在进行模式比较时应该显示的内容(除非指定忽略ON DELETE
和ON UPDATE
操作),而是约束是启用还是禁用在架构比较中更有可能被忽略。
答案 1 :(得分:2)
有一个外键(在错误消息中命名)阻止您从Table1
删除项目,因为它会违反外键(即另一个表中会有一行引用你要删除的那一行)
两个数据库之间的区别是:
要查找外键所在的表,请参阅问题How can I list all foreign keys referencing a given table in SQL Server?
EXEC sp_fkeys 'TableName'
答案 2 :(得分:0)