暂时关闭约束(MS SQL)


208

我正在寻找一种暂时关闭所有数据库约束(例如表关系)的方法。

我需要将一个数据库的表复制(使用INSERT)到另一个数据库。我知道我可以通过按正确的顺序执行命令(不破坏关系)来实现这一点。

但是,如果我可以暂时关闭检查约束并在操作完成后将其重新打开,会更容易。

这可能吗?


3
这不是完整的副本,我只想在以下之间复制选定的表
Maciej,2009年

我对此的担心是,这消除了所有人的约束,而不仅仅是您。如果必须执行此操作,请首先将数据库置于单用户模式。否则,您可能会遇到数据完整性问题。
HLGEM

13
尊敬的未来人士:您可以立即禁用和重新启用数据库中的所有约束;参见stackoverflow.com/a/161410
brichins

1
完成后,别忘了启用约束!
迈克·克里斯蒂安

1
@NicolasBarbulesco足够公平;我正在离开sql-serversql-server-2005标签。我给出的链接是针对SQL Server的,但是您可以在Oracle中执行相同的操作-请参见此处此处。您也可以在PostgreSQL中做到这一点。
brichins 2013年

Answers:


214

只能在SQL 2005+中禁用FK和CHECK约束。见ALTER TABLE

ALTER TABLE foo NOCHECK CONSTRAINT ALL

要么

ALTER TABLE foo NOCHECK CONSTRAINT CK_foo_column

主键和唯一约束不能被禁用,但是如果我对您的理解正确的话,这应该可以。


10
但这不是暂时的。
萨科Barbulesco

@NicolasBarbulesco:取决于。是的,因为您可以使用DROP / CREATE重新启用它们
-gbn

这个答案只是解决方案的前半部分。我一直在寻找一种暂时关闭约束的简单方法,并且得出的结论是在Oracle上不存在约束。
Nicolas Barbulesco

不能禁用PK和唯一约束是不正确的。至少在最新版本的SQL Server中它可以工作。例如,请参阅:techonthenet.com/sql_server/primary_keys.php
Dejan

1
Oracle上的@NicolasBarbulesco?ALTER TABLE some_table DISABLE CONSTRAINT some_table_fk1; //做一些违反约束的事情ALTER TABLE some_table ENABLE CONSTRAINT some_table_fk1;
史蒂夫·斯温斯堡

237
-- 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'
---------------------------------------------------------

1
@kevinc没有 只要您愿意,就没关系。
坡脚趾

2
我相信使用带引号的标识符是ANSI标准设置,这意味着您不应该将它们用于字符串。与保持一致无关。参见stackoverflow.com/questions/1992314/…–
kevinc

1
感谢您的程序!顺便说一句,正确的大小写是“ sp_MSforeachtable”(MS大写)。谢谢!
Sielu '17

3
这应该被标记为正确答案,因为它可以完全回答问题。不仅如此,@ Donal还提供了通配符版本,这对我非常有帮助。
马特·杰克逊

2
感谢您的重新启用位。尤其是check check很多人忘记的那双!!
亚历克斯(Alex)

57

而且,如果您想确认自己没有破坏自己的关系并引入孤儿,则在重新武装好支票后,即

ALTER TABLE foo CHECK CONSTRAINT ALL

要么

ALTER TABLE foo CHECK CONSTRAINT FK_something

然后您可以重新运行并针对所有选中的列进行更新,如下所示:

UPDATE myUpdatedTable SET someCol = someCol, fkCol = fkCol, etc = etc

此时的任何错误都将归因于未能满足约束条件。


11
更好的方法是使用带有检查检查约束的ALTER TABLE FOO FK_something
Cody Konior 2013年

1
FK_something将启用约束但不检查数据,这意味着约束将不受信任(is_no_trusted = 1,is_disabled = 0)。
Bogdan Sahlean '17


0

禁用和启用所有外键

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命令。然后将该语句作为消息打印,以便可以观察其进度,然后执行该语句。最后,当所有行都经过迭代后,存储过程将关闭并释放游标。

请参阅《MSDN杂志》中的禁用约束和触发器

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.