问题 SQL Server:使用FK删除表


在表“A”上依赖于30个其他表格通过FK到“A.Id”。

对于集成测试,我必须删除表并重新创建它以创建已定义的状态。由于依赖对象,它们似乎无法删除和重新创建表。错误消息是:

无法删除对象'dbo.A'   因为它是由FOREIGN引用的   关键约束

问题(S): 

  • 如何删除并重新创建表“A”
  • (或)有没有办法全局关闭架构依赖关系?
  • (或)有没有办法在删除和恢复表“A”之前备份(所有!)依赖项并在之后恢复所有依赖项?

3125
2018-03-09 17:24


起源

为什么不使用单独的DB进行集成测试,每次都从头开始生成整个状态? - Morfildur
数据库只是大(数百个具有许多依赖对象的表)。通过这种方式,每次集成测试大约需要45秒+ x仅用于启动时间而无需任何实际测试。另外一些表包含数据。 (没有任何自定义数据的总数据库转储大约是35MB)。我们将有 许多 集成测试,我们希望在每次签入时使用集成服务器执行。 - Robert
每个集成状态是否需要DB的相同初始状态,或者您是否可以支付一次启动惩罚并让每个测试撤消它可能对状态所做的任何瞬态更改? - Mikeb
一次是支付启动惩罚的想法。要“回滚”更改,我们的想法是重新创建表+一组已定义的数据。 (它的巨大遗留应用程序,这是我们迄今为止最好的。目标是单元测试,但我们目前可以达到的只是集成测试。) - Robert


答案:


转到SSMS中的数据库并右键单击。选择任务,生成脚本。然后浏览选项并按照你想要的方式设置它们(Probaly只选择表中的外键并创建依赖对象并删除并重新创建,不要;在我面前的选项但你会看到它们。然后选择表格你想要为FK编写脚本并将它们编写脚本到文件。打开文件并将drop语句分成一个文件,将创建语句分成另一个文件。现在你有可以运行的tweo文件自动执行你想要的运行时运行我建议在运行第一次测试之前重新创建文件(如果它们自上次运行测试后已经更改),但不是每次单独测试。


3
2018-03-09 17:52



谢谢,我非常感激。这对我来说最有效! - Robert


探索 sys.foreign_key_columns 系统表。这是我放置的一个例子,给定一个表,告诉你哪个列被键入另一个表:

DECLARE @tableName VARCHAR(255)
SET @tableName = 'YourTableName'

SELECT OBJECT_NAME(fkc.constraint_object_id) AS 'FKName', OBJECT_NAME(fkc.[referenced_object_id]) AS 'FKTable', c2.[name] AS 'FKTableColumn', @tableName AS 'Table', c1.[name] AS 'TableColumn'
    FROM sys.foreign_key_columns as fkc
        JOIN sys.columns AS c1 ON c1.[object_id] = fkc.[parent_object_id] AND c1.[column_id] = fkc.[parent_column_id]
        JOIN sys.columns AS c2 ON c2.[object_id] = fkc.[referenced_object_id] AND c2.[column_id] = fkc.[referenced_column_id]
    WHERE fkc.[parent_object_id] = OBJECT_ID(@tableName)
    ORDER BY OBJECT_NAME(fkc.constraint_object_id)

有了这个,或者它的一些变化,你可以找到外键,删除它们,做你的东西,然后重新创建外键。

我应该补充一点,我知道这适用于SQL2005和SQL2008。我真的不知道它是否适用于SQL2000 / MSDE。


5
2018-03-09 17:52





在Management Studio中,您可以右键单击该表并编写CREATE和DROP脚本,其中包含所有外键。


更具体地说,这将为您提供表所依赖的所有约束。但是,它没有提供依赖于此表的外键列表。因此,除了通过右键单击SMS中的表生成的脚本之外,还需要查找并编写所有外键的脚本。要获取它们的列表,您可以运行如下查询:

select FKConstraint.TABLE_NAME, FKConstraint.CONSTRAINT_NAME
from INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS 
    Join INFORMATION_SCHEMA.TABLE_CONSTRAINTS As UniqueConstraint
        On UniqueConstraint.CONSTRAINT_NAME = INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS.UNIQUE_CONSTRAINT_NAME
    Join INFORMATION_SCHEMA.TABLE_CONSTRAINTS As FKConstraint
        On FKConstraint.CONSTRAINT_NAME = INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS.CONSTRAINT_NAME        
Where UniqueConstraint.TABLE_NAME = 'TableA'

对于其中的每一个,您都需要编写创建和删除脚本。您可以将drop添加到drop script的顶部,并将create添加到create script的末尾。


4
2018-03-09 17:27



这不包含引用依赖项,这是问题所在。 - Robert
你什么意思? SMS将创建一个脚本,该脚本将删除正在删除的表的所有外键,然后在最后删除该表。此外,create将创建所有外键。 - Thomas
嗯,我dit尝试这个...并得到了一个很多脚本:“如果EXISTS(SELECT * FROM sys.check_constraints WHERE”......但是当我执行它时,我仍然得到:“无法删除对象'dbo.A'因为它是由FOREIGN KEY约束引用的。“这真的很奇怪! - Robert
我很抱歉。我看到了这个问题。您需要找到指向要删除的表格的所有FK。我会修改我的回复。 - Thomas


在Sql Server Management Studio中展开表,展开Constraints文件夹。

记下您拥有的任何约束,以便重新创建它们。删除约束并删除表。重建表并重新创建约束。


2
2018-03-09 17:35



我也考虑过这一点,但由于许多表有很多约束和依赖,这将是很多工作。 (还有很多工作,我试图避免:-)) - Robert
是的,我希望Mircosoft能够更轻松地完成这项任务。每次我必须这样做,我都会大声抱怨。 ;-) - Joe Pitz


使用交易。 在测试结束时 - 回滚它。


2
2018-03-09 17:42



好主意,但我无法掌握SQL-Connection - 因此无法控制事务(?)。 - Robert


也许考虑在初始化测试设置中使用数据库维护虚拟服务器。引导VM,执行测试,然后丢弃已更改的VM。


0
2018-03-09 17:55



我想恢复数据库会比恢复虚拟机更快。 - Robert
不,根本没有恢复。如果需要,可能需要一两分钟来启动VM,这就是全部。 - Larry Lustig