【问题标题】:Turn off constraints temporarily (MS SQL)暂时关闭约束 (MS SQL)
【发布时间】:2010-10-18 17:41:34
【问题描述】:

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

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

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

这可能吗?

【问题讨论】:

  • 这不是完整的副本我只是想复制选定的表之间
  • 我担心这样做会关闭所有人的约束,而不仅仅是你。如果必须这样做,请先将数据库置于单用户模式。否则,您最终可能会出现数据完整性问题。
  • 来自未来的亲爱的人们:您可以一次禁用和重新启用数据库中的所有约束;见stackoverflow.com/a/161410
  • 完成后不要忘记启用约束!
  • @NicolasBarbulesco 很公平;我要关闭sql-serversql-server-2005 标签。我提供的链接适用于 SQL Server,但您可以在 Oracle 中执行相同的操作 - 请参阅 herehere。你也可以在PostgreSQL.

标签: sql sql-server sql-server-2005 constraints entity-relationship


【解决方案1】:
-- 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 in the database:
EXEC sp_msforeachtable 'ALTER TABLE ? NOCHECK CONSTRAINT ALL'

-- Re-enable constraints for all tables in the database:
EXEC sp_msforeachtable 'ALTER TABLE ? WITH CHECK CHECK CONSTRAINT ALL'
---------------------------------------------------------

【讨论】:

  • @kevinc 没有。只要你坚持,没关系。
  • 我相信使用带引号的标识符是 ANSI 标准设置,这意味着您不应该将它们用于字符串。与保持一致无关。见stackoverflow.com/questions/1992314/…
  • 感谢您的程序!顺便说一句,它的正确大小写是“sp_MSforeachtable”(MS 大写)。谢谢!
  • 这应该被标记为正确答案,因为它完全回答了问题。不仅如此,@Donal 还包含一个通配符版本,这对我很有帮助。
  • 感谢您重新启用位。尤其是很多人忘记的双重check check!!
【解决方案2】:

禁用和启用所有外键

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_STATUS 的值很重要 紧跟在 FETCH 语句之后。 @@FETCH_STATUS 将反映 连接上最近的 FETCH 操作的状态。 @@FETCH_STATUS 的有效值为:

0 = FETCH 成功
-1 = FETCH 失败
-2 = 获取的行丢失了

在循环内部,代码以不同方式构建 ALTER TABLE 命令 取决于意图是禁用还是启用外部 键约束(使用 CHECK 或 NOCHECK 关键字)。声明是 然后打印为消息,以便可以观察其进度,然后 语句被执行。最后,当所有行都被迭代时 通过,存储过程关闭并释放游标。

Disabling Constraints and Triggers from MSDN Magazine

【讨论】:

    【解决方案3】:

    而且,如果你想确认你没有破坏你的关系并引入孤儿,一旦你重新武装你的支票,即

    ALTER TABLE foo CHECK CONSTRAINT ALL
    

    ALTER TABLE foo CHECK CONSTRAINT FK_something
    

    然后您可以重新运行并对任何已检查的列进行更新,如下所示:

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

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

    【讨论】:

    • 更好的方法是 ALTER TABLE FOO WITH CHECK CHECK CONSTRAINT FK_something
    • ALTER TABLE foo CHECK CONSTRAINT ALL 或 ALTER TABLE foo CHECK CONSTRAINT FK_something 将启用约束但不检查数据,这意味着约束将不受信任(is_no_trusted = 1,is_disabled = 0)。
    【解决方案4】:

    您可以禁用 FK 和 CHECK 约束仅在 SQL 2005+ 中。见ALTER TABLE

    ALTER TABLE foo NOCHECK CONSTRAINT ALL
    

    ALTER TABLE foo NOCHECK CONSTRAINT CK_foo_column
    

    不能禁用主键和唯一约束,但如果我理解正确的话应该没问题。

    【讨论】:

    • 但这不是暂时的。
    • @NicolasBarbulesco:这取决于。是的,您可以使用 DROP/CREATE 重新启用它们
    • 这个答案只是解决方案的前半部分。我一直在寻找一种简单的方法来暂时关闭约束,我得出的结论是它在 Oracle 上不存在。
    • 不能禁用 PK 和唯一约束是不正确的。至少在更新版本的 SQL Server 中它可以工作。例如,请参阅:techonthenet.com/sql_server/primary_keys.php
    • @NicolasBarbulesco 在 Oracle 上? ALTER TABLE some_table 禁用约束 some_table_fk1; //做一些违反约束的事情 ALTER TABLE some_table ENABLE CONSTRAINT some_table_fk1;
    【解决方案5】:

    您实际上可以在单个 SQL 命令中禁用所有数据库约束,然后调用另一个单个命令重新启用它们。见:

    我目前正在使用 SQL Server 2005,但我几乎可以肯定这种方法也适用于 SQL 2000

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多