我正在寻找一种暂时关闭所有数据库约束(例如表关系)的方法。
我需要将一个数据库的表复制(使用INSERT)到另一个数据库。我知道我可以通过按正确的顺序执行命令(不破坏关系)来实现这一点。
但是,如果我可以暂时关闭检查约束并在操作完成后将其重新打开,会更容易。
这可能吗?
sql-server
和sql-server-2005
标签。我给出的链接是针对SQL Server的,但是您可以在Oracle中执行相同的操作-请参见此处和此处。您也可以在PostgreSQL中做到这一点。
我正在寻找一种暂时关闭所有数据库约束(例如表关系)的方法。
我需要将一个数据库的表复制(使用INSERT)到另一个数据库。我知道我可以通过按正确的顺序执行命令(不破坏关系)来实现这一点。
但是,如果我可以暂时关闭检查约束并在操作完成后将其重新打开,会更容易。
这可能吗?
sql-server
和sql-server-2005
标签。我给出的链接是针对SQL Server的,但是您可以在Oracle中执行相同的操作-请参见此处和此处。您也可以在PostgreSQL中做到这一点。
Answers:
您只能在SQL 2005+中禁用FK和CHECK约束。见ALTER TABLE
ALTER TABLE foo NOCHECK CONSTRAINT ALL
要么
ALTER TABLE foo NOCHECK CONSTRAINT CK_foo_column
主键和唯一约束不能被禁用,但是如果我对您的理解正确的话,这应该可以。
-- Disable the constraints on a table called tableName:
ALTER TABLE tableName NOCHECK CONSTRAINT ALL
-- Re-enable the constraints on a table called tableName:
ALTER TABLE tableName WITH CHECK CHECK CONSTRAINT ALL
---------------------------------------------------------
-- Disable constraints for all tables:
EXEC sp_msforeachtable 'ALTER TABLE ? NOCHECK CONSTRAINT all'
-- Re-enable constraints for all tables:
EXEC sp_msforeachtable 'ALTER TABLE ? WITH CHECK CHECK CONSTRAINT all'
---------------------------------------------------------
check check
很多人忘记的那双!!
而且,如果您想确认自己没有破坏自己的关系并引入孤儿,则在重新武装好支票后,即
ALTER TABLE foo CHECK CONSTRAINT ALL
要么
ALTER TABLE foo CHECK CONSTRAINT FK_something
然后您可以重新运行并针对所有选中的列进行更新,如下所示:
UPDATE myUpdatedTable SET someCol = someCol, fkCol = fkCol, etc = etc
此时的任何错误都将归因于未能满足约束条件。
实际上,您可以在一个SQL命令中禁用所有数据库约束,然后通过调用另一个命令来重新启用它们。看到:
我目前正在使用SQL Server 2005,但几乎可以肯定,这种方法也可以用于SQL 2000
禁用和启用所有外键
CREATE PROCEDURE pr_Disable_Triggers_v2
@disable BIT = 1
AS
DECLARE @sql VARCHAR(500)
, @tableName VARCHAR(128)
, @tableSchema VARCHAR(128)
-- List of all tables
DECLARE triggerCursor CURSOR FOR
SELECT t.TABLE_NAME AS TableName
, t.TABLE_SCHEMA AS TableSchema
FROM INFORMATION_SCHEMA.TABLES t
ORDER BY t.TABLE_NAME, t.TABLE_SCHEMA
OPEN triggerCursor
FETCH NEXT FROM triggerCursor INTO @tableName, @tableSchema
WHILE ( @@FETCH_STATUS = 0 )
BEGIN
SET @sql = 'ALTER TABLE ' + @tableSchema + '.[' + @tableName + '] '
IF @disable = 1
SET @sql = @sql + ' DISABLE TRIGGER ALL'
ELSE
SET @sql = @sql + ' ENABLE TRIGGER ALL'
PRINT 'Executing Statement - ' + @sql
EXECUTE ( @sql )
FETCH NEXT FROM triggerCursor INTO @tableName, @tableSchema
END
CLOSE triggerCursor
DEALLOCATE triggerCursor
首先,将foreignKeyCursor游标声明为SELECT语句,该语句收集外键及其表名的列表。接下来,打开游标并执行初始的FETCH语句。该FETCH语句将第一行的数据读入局部变量@foreignKeyName和@tableName。在游标中循环时,可以检查@@ FETCH_STATUS的值为0,这表示提取成功。这意味着循环将继续前进,以便可以从行集中获取每个连续的外键。@@ FETCH_STATUS可用于连接上的所有游标。因此,如果要遍历多个游标,则在紧接FETCH语句后的语句中检查@@ FETCH_STATUS的值很重要。@@ FETCH_STATUS将反映该连接上最新的FETCH操作的状态。@@ FETCH_STATUS的有效值为:
0 = FETCH成功
-1 = FETCH不成功
-2 =所获取的行丢失在循环内部,代码根据意图是禁用还是启用外键约束(使用CHECK或NOCHECK关键字)以不同的方式构建ALTER TABLE命令。然后将该语句作为消息打印,以便可以观察其进度,然后执行该语句。最后,当所有行都经过迭代后,存储过程将关闭并释放游标。