Showing posts with label Table/Index. Show all posts
Showing posts with label Table/Index. Show all posts

Saturday, April 17, 2021

SQL Server Script to Drop and Recreate All Foreign Keys for Database Resets

Summary: Use these T-SQL scripts to automate the dropping and recreating of foreign key constraints. This is essential for resetting database contents, performing bulk data loads, or reseeding identities.

Automating Foreign Key Management for Database Resets

Maintaining ready-to-use scripts for resetting database contents is a lifesaver for dev and QA environments. When you need to truncate tables or reseed identities, foreign key constraints often get in the way.

The following workflow captures your existing FK metadata into a temporary table, generates "Drop" scripts, and prepares "Recreate" scripts so you can restore your constraints instantly after your data cleanup.


1. Prepare Metadata Storage

We start by ensuring our temporary workspace is clean and then capture the complex relationships, including multi-column keys.


-- Drop temp table if it exists
IF OBJECT_ID('tempdb..#Fkey') IS NOT NULL
    DROP TABLE #Fkey;

-- Capture Foreign Key Information
;WITH cte AS (
    SELECT 
        fkc.constraint_column_id AS consColumn,
        fk.NAME AS foreignKeyName,
        parentSchema.name AS parentSchema,
        parentTable.NAME AS parentTableName,
        parent_col.NAME AS parentColName,
        refSchema.name AS refSchema,
        refTable.NAME AS refTableName,
        ref_col.NAME AS refColName
    FROM sys.foreign_keys fk
    INNER JOIN sys.foreign_key_columns fkc ON fk.object_id = fkc.constraint_object_id
    INNER JOIN sys.tables parentTable ON parentTable.object_id = fkc.parent_object_id
    INNER JOIN sys.schemas parentSchema ON parentSchema.schema_id = parentTable.schema_id
    INNER JOIN sys.columns parent_col ON fkc.parent_column_id = parent_col.column_id 
        AND parent_col.object_id = parentTable.object_id
    INNER JOIN sys.tables refTable ON refTable.object_id = fkc.referenced_object_id
    INNER JOIN sys.schemas refSchema ON refSchema.schema_id = refTable.schema_id
    INNER JOIN sys.columns ref_col ON fkc.referenced_column_id = ref_col.column_id 
        AND ref_col.object_id = refTable.object_id
    WHERE parentTable.type = 'U' AND refTable.type = 'U'
)
SELECT DISTINCT 
    foreignKeyName,
    parentSchema,
    parentTableName,
    SUBSTRING((
        SELECT ',' + a.parentColName
        FROM cte a
        WHERE a.foreignKeyName = c.foreignKeyName
        ORDER BY a.consColumn
        FOR XML PATH('')
    ), 2, 300000) AS parentColName,
    refSchema,
    refTableName,
    SUBSTRING((
        SELECT ',' + b.refColName
        FROM cte b
        WHERE b.foreignKeyName = c.foreignKeyName
        ORDER BY b.consColumn
        FOR XML PATH('')
    ), 2, 300000) AS refColName
INTO #Fkey
FROM cte c;
        

2. Generate "DROP" Scripts

Run the query below and copy the results to safely remove constraints.


SELECT DISTINCT 
    'IF EXISTS (SELECT * FROM sys.foreign_keys 
        WHERE object_id = OBJECT_ID(N''[' + parentSchema + '].[' + foreignKeyName + ']'') 
        AND parent_object_id = OBJECT_ID(N''[' + parentSchema + '].[' + ParentTableName + ']''))
    ALTER TABLE [' + parentSchema + '].[' + ParentTableName + '] DROP CONSTRAINT [' + foreignKeyName + ']' 
AS foreignKey_drop_script
FROM #Fkey;
        

3. Generate "RECREATE" Scripts

After your data operations are complete, run these generated scripts to restore referential integrity.


SELECT DISTINCT 
    'ALTER TABLE [' + parentSchema + '].[' + ParentTableName + '] WITH CHECK 
    ADD CONSTRAINT [' + foreignKeyName + '] FOREIGN KEY(' + parentColName + ') 
    REFERENCES [' + refSchema + '].[' + refTableName + '](' + refColName + ')' 
AS Add_constraints_script
FROM #Fkey;
        

Additional Resources:

Working with Truncate? Remember that TRUNCATE TABLE is not allowed if a table is referenced by a Foreign Key, even if the table is empty. Use these scripts to drop them first!