暂时禁用所有外键约束

HaB*_*aBo 44 sql-server ssis constraints sql-server-2008

我正在运行一个SSIS包,它将从FlatFiles中的几个表的数据替换为数据库中的现有表.

我的包将截断表,然后插入新数据.当我运行我的SSIS包时,由于外键我得到一个例外.

我可以禁用约束,运行导入,然后重新启用它们吗?

Aar*_*and 81

要禁用外键约束:

DECLARE @sql NVARCHAR(MAX) = N'';

;WITH x AS 
(
  SELECT DISTINCT obj = 
      QUOTENAME(OBJECT_SCHEMA_NAME(parent_object_id)) + '.' 
    + QUOTENAME(OBJECT_NAME(parent_object_id)) 
  FROM sys.foreign_keys
)
SELECT @sql += N'ALTER TABLE ' + obj + ' NOCHECK CONSTRAINT ALL;
' FROM x;

EXEC sp_executesql @sql;
Run Code Online (Sandbox Code Playgroud)

要重新启用:

DECLARE @sql NVARCHAR(MAX) = N'';

;WITH x AS 
(
  SELECT DISTINCT obj = 
      QUOTENAME(OBJECT_SCHEMA_NAME(parent_object_id)) + '.' 
    + QUOTENAME(OBJECT_NAME(parent_object_id)) 
  FROM sys.foreign_keys
)
SELECT @sql += N'ALTER TABLE ' + obj + ' WITH CHECK CHECK CONSTRAINT ALL;
' FROM x;

EXEC sp_executesql @sql;
Run Code Online (Sandbox Code Playgroud)

但是,您将无法截断表,您必须按正确的顺序从中删除它们.如果需要截断它们,则需要完全删除约束,然后重新创建它们.如果外键约束都是简单的单列约束,这很容易做到,但如果涉及多个列,则肯定会更复杂.

这是你可以尝试的东西.为了使其成为SSIS包的一部分,您需要在SSIS包运行时存储FK定义的位置(您将无法在一个脚本中完成所有操作).所以在一些实用程序数据库中,创建一个表:

CREATE TABLE dbo.PostCommand(cmd NVARCHAR(MAX));
Run Code Online (Sandbox Code Playgroud)

然后在您的数据库中,您可以拥有执行此操作的存储过程:

DELETE other_database.dbo.PostCommand;

DECLARE @sql NVARCHAR(MAX) = N'';

SELECT @sql += N'ALTER TABLE ' + QUOTENAME(OBJECT_SCHEMA_NAME(fk.parent_object_id))
   + '.' + QUOTENAME(OBJECT_NAME(fk.parent_object_id)) 
   + ' ADD CONSTRAINT ' + fk.name + ' FOREIGN KEY (' 
   + STUFF((SELECT ',' + c.name
    FROM sys.columns AS c 
        INNER JOIN sys.foreign_key_columns AS fkc 
        ON fkc.parent_column_id = c.column_id
        AND fkc.parent_object_id = c.[object_id]
    WHERE fkc.constraint_object_id = fk.[object_id]
    ORDER BY fkc.constraint_column_id 
    FOR XML PATH(''), TYPE).value('.', 'nvarchar(max)'), 1, 1, '')
+ ') REFERENCES ' + 
QUOTENAME(OBJECT_SCHEMA_NAME(fk.referenced_object_id))
+ '.' + QUOTENAME(OBJECT_NAME(fk.referenced_object_id))
+ '(' + 
STUFF((SELECT ',' + c.name
    FROM sys.columns AS c 
        INNER JOIN sys.foreign_key_columns AS fkc 
        ON fkc.referenced_column_id = c.column_id
        AND fkc.referenced_object_id = c.[object_id]
    WHERE fkc.constraint_object_id = fk.[object_id]
    ORDER BY fkc.constraint_column_id 
    FOR XML PATH(''), TYPE).value('.', 'nvarchar(max)'), 1, 1, '') + ');
' FROM sys.foreign_keys AS fk
WHERE OBJECTPROPERTY(parent_object_id, 'IsMsShipped') = 0;

INSERT other_database.dbo.PostCommand(cmd) SELECT @sql;

IF @@ROWCOUNT = 1
BEGIN
  SET @sql = N'';

  SELECT @sql += N'ALTER TABLE ' + QUOTENAME(OBJECT_SCHEMA_NAME(fk.parent_object_id))
    + '.' + QUOTENAME(OBJECT_NAME(fk.parent_object_id)) 
    + ' DROP CONSTRAINT ' + fk.name + ';
  ' FROM sys.foreign_keys AS fk;

  EXEC sp_executesql @sql;
END
Run Code Online (Sandbox Code Playgroud)

现在,当您的SSIS包完成后,它应该调用另一个存储过程,它执行以下操作:

DECLARE @sql NVARCHAR(MAX);

SELECT @sql = cmd FROM other_database.dbo.PostCommand;

EXEC sp_executesql @sql;
Run Code Online (Sandbox Code Playgroud)

如果你只是为了能够截断而不是删除而完成所有这些,我建议只需要点击并运行删除.也许使用批量日志恢复模型来最小化日志的影响.总的来说,我没有看到这个解决方案如何比以正确的顺序使用删除更快.

2014年,我在这里发表了一篇更详细的帖子:

  • @HaBo尝试:`SELECT name,is_disabled FROM sys.foreign_keys;`PS这就是为什么你运行你不理解的代码示例,首先是在网站上的陌生人,在测试系统上给你的. (6认同)

Ed *_*all 34

使用内置的sp_msforeachtable存储过程.

要禁用所有约束:

EXEC sp_msforeachtable "ALTER TABLE ? NOCHECK CONSTRAINT ALL";
Run Code Online (Sandbox Code Playgroud)

要启用所有约束:

EXEC sp_msforeachtable "ALTER TABLE ? WITH CHECK CHECK CONSTRAINT ALL";
Run Code Online (Sandbox Code Playgroud)

删除所有表:

EXEC sp_msforeachtable "DROP TABLE ?";
Run Code Online (Sandbox Code Playgroud)

  • 也许有人试图在生产数据库上执行这3个查询,尤其是最后一个查询:-) (5认同)
  • 遗憾的是,Azure SQL 中不存在“sp_msforeachtable” (2认同)

Trầ*_*ong 8

有一个简单的方法可以做到这一点。

\n
-- Disable all the constraint in database\nEXEC sp_msforeachtable \'ALTER TABLE ? NOCHECK CONSTRAINT all\'\n\n-- Enable all the constraint in database\nEXEC sp_msforeachtable \'ALTER TABLE ? WITH CHECK CHECK CONSTRAINT all\'\n
Run Code Online (Sandbox Code Playgroud)\n

参考SQL SERVER \xe2\x80\x93 禁用数据库中的所有外键约束 \xe2\x80\x93 启用数据库中的所有外键约束

\n


NG.*_*NG. 5

一个很好的参考:http://msdn.microsoft.com/en-us/magazine/cc163442.aspx 在“禁用所有外键”部分下

受此启发,可以通过创建临时表并在该表中插入约束,然后删除约束,然后从该临时表重新应用它们来实现一种方法。说得够多了,这就是我要说的

 SET NOCOUNT ON

    DECLARE @temptable TABLE(
       Id INT PRIMARY KEY IDENTITY(1, 1),
       FKConstraintName VARCHAR(255),
       FKConstraintTableSchema VARCHAR(255),
       FKConstraintTableName VARCHAR(255),
       FKConstraintColumnName VARCHAR(255),
       PKConstraintName VARCHAR(255),
       PKConstraintTableSchema VARCHAR(255),
       PKConstraintTableName VARCHAR(255),
       PKConstraintColumnName VARCHAR(255)    
    )

    INSERT INTO @temptable(FKConstraintName, FKConstraintTableSchema, FKConstraintTableName, FKConstraintColumnName)
    SELECT 
       KeyColumnUsage.CONSTRAINT_NAME, 
       KeyColumnUsage.TABLE_SCHEMA, 
       KeyColumnUsage.TABLE_NAME, 
       KeyColumnUsage.COLUMN_NAME 
    FROM 
       INFORMATION_SCHEMA.KEY_COLUMN_USAGE KeyColumnUsage
          INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS TableConstraints
             ON KeyColumnUsage.CONSTRAINT_NAME = TableConstraints.CONSTRAINT_NAME
    WHERE
       TableConstraints.CONSTRAINT_TYPE = 'FOREIGN KEY'

    UPDATE @temptable SET
       PKConstraintName = UNIQUE_CONSTRAINT_NAME
    FROM 
       @temptable tt
          INNER JOIN INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS ReferentialConstraint
             ON tt.FKConstraintName = ReferentialConstraint.CONSTRAINT_NAME

    UPDATE @temptable SET
       PKConstraintTableSchema  = TABLE_SCHEMA,
       PKConstraintTableName  = TABLE_NAME
    FROM @temptable tt
       INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS TableConstraints
          ON tt.PKConstraintName = TableConstraints.CONSTRAINT_NAME

    UPDATE @temptable SET
       PKConstraintColumnName = COLUMN_NAME
    FROM @temptable tt
       INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE KeyColumnUsage
          ON tt.PKConstraintName = KeyColumnUsage.CONSTRAINT_NAME


    --Now to drop constraint:
    SELECT
       '
       ALTER TABLE [' + FKConstraintTableSchema + '].[' + FKConstraintTableName + '] 
       DROP CONSTRAINT ' + FKConstraintName + '

       GO'
    FROM
       @temptable

    --Finally to add constraint:
    SELECT
       '
       ALTER TABLE [' + FKConstraintTableSchema + '].[' + FKConstraintTableName + '] 
       ADD CONSTRAINT ' + FKConstraintName + ' FOREIGN KEY(' + FKConstraintColumnName + ') REFERENCES [' + PKConstraintTableSchema + '].[' + PKConstraintTableName + '](' + PKConstraintColumnName + ')

       GO'
    FROM
       @temptable

    GO
Run Code Online (Sandbox Code Playgroud)