Reputation: 944
I have a huge database that has lots and lots of poorly documented constraints. I need to write some SQL to empty the data out of a subset of these tables, and I am not sure how to determine the order for the deletes. Obviously I need to delete the FK tables before the corresponding PK table, but as I say the relationships are tangled, and poorly documented.
Is there a tool available that will let me determine a correct order for my delete statements?
(I looked at Red Gate tools, and was absolutely amazed to find out they do not support SQL Server 2008R2 which is what I am using.)
Upvotes: 3
Views: 446
Reputation: 704
Just pasting the script from Fred Thomas' blog here for future reference. It worked well for me.
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(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
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 = rc.colid
left join syscolumns fc2 on r.fkeyid = fc2.id and r.fkey2 = fc.colid
where f.type = 'F'
ORDER BY cast(p.name as varchar(255))
Upvotes: 0
Reputation: 5957
I think you could build a procedure to get the order. Here is an idea:
CREATE PROCEDURE get_delete_order
@tablename varchar(MAX)
as
BEGIN
-- Get directed related tables
SELECT base.name base_name
, related.name rel_name
into #RELATED_TABLES
FROM sys.sysobjects base
left join sys.sysforeignkeys on fkeyid = base.id
left join sys.sysobjects related on related.id = rkeyid
and related.id <> base.id
and related.xtype = 'U'
WHERE base.xtype = 'U'
and base.name = @tablename
-- Get indirected related tables using recursive call
CREATE #ALL_RELATED_TABLES (rel_name varchar(max), del_order int)
INSERT INTO #ALL_RELATED_TABLES (rel_name, del_order)
SELECT rel_name
, -1
FROM #RELATED_TABLES
DECLARE @relate_table
DECLARE IND_REL CURSOR FOR
SELECT rel_Name
FROM #RELATED_TABLES
open IND_REL
fetch next from IND_REL into @relate_table
-- TODO: IMPORTANT!!! Avoid infinite loop here
while (@@FETCH_STATUS = 0)
begin
INSERT INTO #ALL_RELATED_TABLES (rel_name, del_order)
exec get_delete_order(@relate_table)
fetch next from IND_REL into @relate_table
end
close IND_REL
deallocate IND_REL
-- Return resultset
SELECT rel_name
, del_order + 1
FROM #ALL_RELATED_TABLES
ORDER BY del_order DESC
END
It is untested, just an idea. Real procedure would be more complicated :)
Upvotes: 1