How can foreign key constraints be temporarily disabled using T-SQL?

后端 未结 16 1931
Happy的楠姐
Happy的楠姐 2020-11-22 04:57

Are disabling and enabling foreign key constraints supported in SQL Server? Or is my only option to drop and then re-create

相关标签:
16条回答
  • 2020-11-22 05:21

    The SQL-92 standard allows for a constaint to be declared as DEFERRABLE so that it can be deferred (implicitly or explicitly) within the scope of a transaction. Sadly, SQL Server is still missing this SQL-92 functionality.

    For me, changing a constraint to NOCHECK is akin to changing the database structure on the fly -- dropping constraints certainly is -- and something to be avoided (e.g. users require increased privileges).

    0 讨论(0)
  • 2020-11-22 05:25

    One script to rule them all: this combines truncate and delete commands with sp_MSforeachtable so that you can avoid dropping and recreating constraints - just specify the tables that need to be deleted rather than truncated and for my purposes I have included an extra schema filter for good measure (tested in 2008r2)

    declare @schema nvarchar(max) = 'and Schema_Id=Schema_id(''Value'')'
    declare @deletiontables nvarchar(max) = '(''TableA'',''TableB'')'
    declare @truncateclause nvarchar(max) = @schema + ' and o.Name not in ' +  + @deletiontables;
    declare @deleteclause nvarchar(max) = @schema + ' and o.Name in ' + @deletiontables;        
    
    exec sp_MSforeachtable 'alter table ? nocheck constraint all', @whereand=@schema
    exec sp_MSforeachtable 'truncate table ?', @whereand=@truncateclause
    exec sp_MSforeachtable 'delete from ?', @whereand=@deleteclause
    exec sp_MSforeachtable 'alter table ? with check check constraint all', @whereand=@schema
    
    0 讨论(0)
  • 2020-11-22 05:26

    Find the constraint

    SELECT * 
    FROM sys.foreign_keys
    WHERE referenced_object_id = object_id('TABLE_NAME')
    

    Execute the SQL generated by this SQL

    SELECT 
        'ALTER TABLE ' +  OBJECT_SCHEMA_NAME(parent_object_id) +
        '.[' + OBJECT_NAME(parent_object_id) + 
        '] DROP CONSTRAINT ' + name
    FROM sys.foreign_keys
    WHERE referenced_object_id = object_id('TABLE_NAME')
    

    Safeway.

    Note: Added solution for droping the constraint so that table can be dropped or modified without any constraint error.

    0 讨论(0)
  • 2020-11-22 05:27

    If you want to disable all constraints in the database just run this code:

    -- disable all constraints
    EXEC sp_MSforeachtable "ALTER TABLE ? NOCHECK CONSTRAINT all"
    

    To switch them back on, run: (the print is optional of course and it is just listing the tables)

    -- enable all constraints
    exec sp_MSforeachtable @command1="print '?'", @command2="ALTER TABLE ? WITH CHECK CHECK CONSTRAINT all"
    

    I find it useful when populating data from one database to another. It is much better approach than dropping constraints. As you mentioned it comes handy when dropping all the data in the database and repopulating it (say in test environment).

    If you are deleting all the data you may find this solution to be helpful.

    Also sometimes it is handy to disable all triggers as well, you can see the complete solution here.

    0 讨论(0)
  • 2020-11-22 05:32

    To disable the constraint you have ALTER the table using NOCHECK

    ALTER TABLE [TABLE_NAME] NOCHECK CONSTRAINT [ALL|CONSTRAINT_NAME]
    

    To enable you to have to use double CHECK:

    ALTER TABLE [TABLE_NAME] WITH CHECK CHECK CONSTRAINT [ALL|CONSTRAINT_NAME]
    
    • Pay attention to the double CHECK CHECK when enabling.
    • ALL means for all constraints in the table.

    Once completed, if you need to check the status, use this script to list the constraint status. Will be very helpfull:

        SELECT (CASE 
            WHEN OBJECTPROPERTY(CONSTID, 'CNSTISDISABLED') = 0 THEN 'ENABLED'
            ELSE 'DISABLED'
            END) AS STATUS,
            OBJECT_NAME(CONSTID) AS CONSTRAINT_NAME,
            OBJECT_NAME(FKEYID) AS TABLE_NAME,
            COL_NAME(FKEYID, FKEY) AS COLUMN_NAME,
            OBJECT_NAME(RKEYID) AS REFERENCED_TABLE_NAME,
            COL_NAME(RKEYID, RKEY) AS REFERENCED_COLUMN_NAME
       FROM SYSFOREIGNKEYS
    ORDER BY TABLE_NAME, CONSTRAINT_NAME,REFERENCED_TABLE_NAME, KEYNO 
    
    0 讨论(0)
  • 2020-11-22 05:33

    I have a more useful version if you are interested. I lifted a bit of code from here a website where the link is no longer active. I modifyied it to allow for an array of tables into the stored procedure and it populates the drop, truncate, add statements before executing all of them. This gives you control to decide which tables need truncating.

    /****** Object:  UserDefinedTableType [util].[typ_objects_for_managing]    Script Date: 03/04/2016 16:42:55 ******/
    CREATE TYPE [util].[typ_objects_for_managing] AS TABLE(
        [schema] [sysname] NOT NULL,
        [object] [sysname] NOT NULL
    )
    GO
    
    create procedure [util].[truncate_table_with_constraints]
    @objects_for_managing util.typ_objects_for_managing readonly
    
    --@schema sysname
    --,@table sysname
    
    as 
    --select
    --    @table = 'TABLE',
    --    @schema = 'SCHEMA'
    
    declare @exec_table as table (ordinal int identity (1,1), statement nvarchar(4000), primary key (ordinal));
    
    --print '/*Drop Foreign Key Statements for ['+@schema+'].['+@table+']*/'
    
    insert into @exec_table (statement)
    select
              'ALTER TABLE ['+SCHEMA_NAME(o.schema_id)+'].['+ o.name+'] DROP CONSTRAINT ['+fk.name+']'
    from sys.foreign_keys fk
    inner join sys.objects o
              on fk.parent_object_id = o.object_id
    where 
    exists ( 
    select * from @objects_for_managing chk 
    where 
    chk.[schema] = SCHEMA_NAME(o.schema_id)  
    and 
    chk.[object] = o.name
    ) 
    ;
              --o.name = @table and
              --SCHEMA_NAME(o.schema_id)  = @schema
    
    insert into @exec_table (statement) 
    select
    'TRUNCATE TABLE ' + src.[schema] + '.' + src.[object] 
    from @objects_for_managing src
    ; 
    
    --print '/*Create Foreign Key Statements for ['+@schema+'].['+@table+']*/'
    insert into @exec_table (statement)
    select 'ALTER TABLE ['+SCHEMA_NAME(o.schema_id)+'].['+o.name+'] ADD CONSTRAINT ['+fk.name+'] FOREIGN KEY (['+c.name+']) 
    REFERENCES ['+SCHEMA_NAME(refob.schema_id)+'].['+refob.name+'](['+refcol.name+'])'
    from sys.foreign_key_columns fkc
    inner join sys.foreign_keys fk
              on fkc.constraint_object_id = fk.object_id
    inner join sys.objects o
              on fk.parent_object_id = o.object_id
    inner join sys.columns c
              on      fkc.parent_column_id = c.column_id and
                       o.object_id = c.object_id
    inner join sys.objects refob
              on fkc.referenced_object_id = refob.object_id
    inner join sys.columns refcol
              on fkc.referenced_column_id = refcol.column_id and
                       fkc.referenced_object_id = refcol.object_id
    where 
    exists ( 
    select * from @objects_for_managing chk 
    where 
    chk.[schema] = SCHEMA_NAME(o.schema_id)  
    and 
    chk.[object] = o.name
    ) 
    ;
    
              --o.name = @table and
              --SCHEMA_NAME(o.schema_id)  = @schema
    
    
    
    declare @looper int , @total_records int, @sql_exec nvarchar(4000)
    
    select @looper = 1, @total_records = count(*) from @exec_table; 
    
    while @looper <= @total_records 
    begin
    
    select @sql_exec = (select statement from @exec_table where ordinal =@looper)
    exec sp_executesql @sql_exec 
    print @sql_exec 
    set @looper = @looper + 1
    end
    
    0 讨论(0)
提交回复
热议问题