Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a simpler and faster way of dropping a table that has foreign key references to other tables?

I have a new table that has foreign key references to a number of existing tables. When I create the new table for the first time, I created the foreign keys in the following way:

ALTER TABLE [dbo].[NewTable] WITH CHECK ADD FOREIGN KEY([SectionDatabaseID])
REFERENCES [dbo].[Section] ([SectionDatabaseID])

ALTER TABLE [dbo].[NewTable] WITH CHECK ADD FOREIGN KEY([TermDatabaseID])
REFERENCES [dbo].[Term] ([TermDatabaseID])

The above way will generate names for the foreign key constraints using it's own automated naming convention.

However, I want to drop the new table because I need to do some major modifications by creating it from scratch.

Obviously, if I just execute a drop statement, the SQL Server database will complain stating that the new table has foreign key references to other tables.

I've heard of running the following script to figure out what foreign keys exist so that we can drop them:

use perls;
SELECT 'ALTER TABLE ' + TABLE_SCHEMA + '.[' + TABLE_NAME +
'] DROP CONSTRAINT [' + CONSTRAINT_NAME + ']'
FROM information_schema.table_constraints
WHERE CONSTRAINT_TYPE = 'FOREIGN KEY' and TABLE_NAME = 'NewTable'

The above will give results that basically show alter statements which I need to run.

I need something more automated. Why do I have to drop each foreign key constraint separately, and then only be able to drop the table?

I want to drop the table in a simpler way. It's got to be easier than what I need to do above.

like image 211
user1338998 Avatar asked Oct 03 '12 18:10

user1338998


3 Answers

Relational databases are designed to enforce database integrity. Your statements are potentially destroying constraints that were carefully added to protect the data quality. Automating the dropping of integrity constraints from a production database could be a disaster for a company. So when the SQL language was developed, making it easy to drop tables that are referenced by other tables was not high on the priority of important tasks. With a database engine for enterprise data, the product is designed more for DBAs than for casual users.

What is the reason for wanting to drop multiple tables that are being referenced in foreign keys? Can you be sure that you are not going to be destroying somebody else's queries?

Assuming that you are working on a non critical system, your approach of writing a script to write a drop script is about the best solution that I know of.

like image 129
Bob Folkerts Avatar answered Oct 07 '22 20:10

Bob Folkerts


Yes you must drop the FKs first. I've ran into this before and have written just the script you need to automate the task. Replace DBName and TABLENAME below.

Warning to all: This script will drop a specific table (or group of tables) as well as all FK constraints! Use with caution, and always take a db backup before doing a major operation like this.

    use DBName
    /* 
    SCRIPT TO DROP TABLES WITH FK'S, INDEXES 
    https://mellodev.snipt.net/drop-tables-with-fk-contraints/
    */

    set nocount on

declare @tables table (tablename varchar(255));
insert into @tables
select name from sys.tables where name in 
('TABLENAME')

-- Iterate tables, drop FK constraints and tables
declare @tablename varchar(255);
declare cTable cursor for
select tablename from @tables
open cTable
fetch next from cTable into @tableName
while @@FETCH_STATUS=0
begin
    -- Identify any FK constraints
    declare @fkCount int;
    SELECT @fkCount = COUNT(*)
    FROM sys.foreign_keys
    WHERE referenced_object_id = object_id(@tablename)

    -- Drop any FK constraints from the table
    if (@fkCount>0) begin
        declare @dropFkSql nvarchar(max);set @dropFkSql='';
        declare @fkName nvarchar(max);
        declare cDropFk cursor for  
            SELECT 'ALTER TABLE [' + OBJECT_NAME(parent_object_id) + '] DROP CONSTRAINT [' + name + ']',name
            FROM sys.foreign_keys
            WHERE referenced_object_id = object_id(@tablename)
        open cDropFk
        fetch next from cDropFk into @dropfksql,@fkName
        while @@FETCH_STATUS=0
        begin       
            exec sp_executesql @dropFkSql;

            select 'Dropped FK Constraint: ' + @fkName
            fetch next from cDropFk into @dropfksql,@fkName
        end
        close cDropFk
        deallocate cDropFk          
    end

    -- Drop the table
    declare @dropTableSql nvarchar(max);
    set @dropTableSql='DROP TABLE [' + @tablename + ']';
    exec sp_executesql @dropTableSql;

    select 'Dropped table: ' + @tablename

    fetch next from cTable into @tableName
end
close cTable
deallocate cTable
like image 26
mellodev Avatar answered Oct 07 '22 20:10

mellodev


If you are using MSSQL then you can use this script that i wrote to purge the whole DB from data without dropping the tables themselves.

use [MyDataBase]
GO

EXEC sp_MSForEachTable 'ALTER TABLE ? NOCHECK CONSTRAINT ALL';

select tbl.* into dbo.DeleteQueries from (SELECT 'DELETE ' + name + ';' as query
FROM sys.tables
WHERE name <> 'DeleteQueries')  as tbl

Declare @query nvarchar(100)

While (Select Count(*) From dbo.DeleteQueries Where query <> '') > 0
Begin
    Select Top 1 @query = query From dbo.DeleteQueries Where query <> ''

    exec(@query);

    Update dbo.DeleteQueries Set query = '' Where query = @query 

End

DROP TABLE dbo.DeleteQueries

EXEC sp_MSForEachTable 'ALTER TABLE ? CHECK CONSTRAINT ALL'

you can add tables that you don't want to purge in the where clause of the "select into" query. Hope this helps

like image 26
Mr T. Avatar answered Oct 07 '22 21:10

Mr T.