create procedure dbo.qrym_DropOrRestoreForeignKeys
@TableList varchar(255) = null, -- leave null, and it will do all of them in the database. This won't work if there are table names with spaces in them.
@DropRestoreFlag char(1) = 'R', -- 'D' = Drop all foreign key constraints for one or more tables
-- 'R' = Retstore all foreign key constraints for one or more tables
@TestOnly bit = 0 -- set to 1 to just see the statements that would be applied. This will still update the FKeys table when 0.
as
begin
if isnull(@DropRestoreFlag, ' ') not in ('D','R')
begin
raiserror 50001 '@DropRestoreFlag parameter must be either ''D'' or ''R'''
return
end
/* create/populate table to store all of the foreign key constraints in the system */
if not exists (select 1 from sysobjects where type='u' and uid=1 and name = 'FKeys')
CREATE table dbo.FKeys
(foreign_key_name varchar(255),
keycnt smallint,
foreign_table varchar(255),
foreign_column_1 varchar(255),
foreign_column_2 varchar(255),
foreign_column_3 varchar(255),
foreign_column_4 varchar(255),
primary_table varchar(255),
primary_column_1 varchar(255),
primary_column_2 varchar(255),
primary_column_3 varchar(255),
primary_column_4 varchar(255),
WhenDropped datetime,
WhoDropped varchar(255),
WhenRestored datetime,
WhoRestored varchar(255),
primary key (foreign_key_name))
insert FKeys
select cast(f.name as varchar(255)) as foreign_key_name
, r.keycnt
, cast(c.name as varchar(255)) as foreign_table
, cast(fc.name as varchar(255)) as foreign_column_1
, cast(fc2.name as varchar(255)) as foreign_column_2
, cast(fc3.name as varchar(255)) as foreign_column_3
, cast(fc4.name as varchar(255)) as foreign_column_4
, cast(p.name as varchar(255)) as primary_table
, cast(rc.name as varchar(255)) as primary_column_1
, cast(rc2.name as varchar(255)) as primary_column_2
, cast(rc3.name as varchar(255)) as primary_column_3
, cast(rc4.name as varchar(255)) as primary_column_4
, null
, null
, null
, null
from sysobjects f
inner join sysobjects c on f.parent_obj = c.id
inner join sysreferences r on f.id = r.constid
inner join sysobjects p on r.rkeyid = p.id
inner join syscolumns rc on r.rkeyid = rc.id and r.rkey1 = rc.colid
inner join syscolumns fc on r.fkeyid = fc.id and r.fkey1 = fc.colid
left join syscolumns rc2 on r.rkeyid = rc2.id and r.rkey2 = rc2.colid
left join syscolumns fc2 on r.fkeyid = fc2.id and r.fkey2 = fc2.colid
left join syscolumns rc3 on r.rkeyid = rc3.id and r.rkey3 = rc3.colid
left join syscolumns fc3 on r.fkeyid = fc3.id and r.fkey3 = fc3.colid
left join syscolumns rc4 on r.rkeyid = rc4.id and r.rkey4 = rc4.colid
left join syscolumns fc4 on r.fkeyid = fc4.id and r.fkey4 = fc4.colid
left outer join FKeys fk on f.name = fk.foreign_key_name
where f.type = 'F' and fk.foreign_key_name is null
/* intermediate variables for the add/drop loop */
create table #t (
foreign_key_name varchar(255),
keycnt smallint,
foreign_table varchar(255),
foreign_column_1 varchar(255),
foreign_column_2 varchar(255),
foreign_column_3 varchar(255),
foreign_column_4 varchar(255),
primary_table varchar(255),
primary_column_1 varchar(255),
primary_column_2 varchar(255),
primary_column_3 varchar(255),
primary_column_4 varchar(255))
declare @Condition varchar(2000)
, @tempTableList varchar(255)
, @currTableList varchar(255)
, @Query varchar(4000)
, @FKName varchar(255)
if rtrim(ltrim(isnull(@TableList, ''))) = ''
select @Condition = ''
else
select @Condition = ' where primary_table in (''' + replace(replace(isnull(@TableList, ''), ',', ''','''), ' ', '') + ''')'
--select 'insert #t select foreign_key_name, keycnt, foreign_table, foreign_column_1, foreign_column_2, foreign_column_3, foreign_column_4, primary_table,
-- primary_column_1, primary_column_2, primary_column_3, primary_column_4 from FKeys' + @Condition
select @Query =
'insert #t select foreign_key_name, keycnt, foreign_table, foreign_column_1, foreign_column_2, foreign_column_3, foreign_column_4, primary_table,
primary_column_1, primary_column_2, primary_column_3, primary_column_4 from FKeys' + @Condition
--select @Query
exec (@Query)
while (select count(1) from #t) > 0
begin
/* drop foreign key constraints */
if @DropRestoreFlag = 'D'
begin
select top 1 @Query = 'ALTER TABLE ' + foreign_table + '
DROP CONSTRAINT ' + foreign_key_name
, @FKName = foreign_key_name
from #t order by foreign_table
if @TestOnly = 1
begin
select 'update FKeys set WhenDropped = getdate(), WhoDropped = suser_sname() where foreign_key_name = ' + @FKName
select @Query
end
else
begin
update FKeys set WhenDropped = getdate(), WhoDropped = suser_sname() where foreign_key_name = @FKName
exec(@Query)
end
delete #t where foreign_key_name = @FKName
end
/* restore foreign key restraints */
else
begin
select top 1 @Query = 'ALTER TABLE ' + foreign_table + ' ADD CONSTRAINT ' + foreign_key_name + '
FOREIGN KEY (' + foreign_column_1 + ')
REFERENCES ' + primary_table + ' (' + primary_column_1 + ')'
, @FKName = foreign_key_name
from #t order by foreign_table
if exists (select 1 from sysobjects where name = @FKName and type='F')
begin
print @FKName + ' already exists. Skipping the restore for this constraint.'
end
else if @TestOnly = 1
begin
select 'update FKeys set WhenRestored = getdate(), WhoRestored = suser_sname() where foreign_key_name = ' + @FKName
select @Query
end
else
begin
update FKeys set WhenRestored = getdate(), WhoRestored = suser_sname() where foreign_key_name = @FKName
exec(@Query)
end
delete #t where foreign_key_name = @FKName
end
end
end