Login or Sign Up to become a member!
LessThanDot Sit Logo

LessThanDot

Data Management

Less Than Dot is a community of passionate IT professionals and enthusiasts dedicated to sharing technical knowledge, experience, and assistance. Inside you will find reference materials, interesting technical discussions, and expert tips and commentary. Once you register for an account you will have immediate access to the forums and all past articles and commentaries.

LTD Social Sitings

Lessthandot twitter Lessthandot Linkedin Lessthandot friendfeed Lessthandot facebook Lessthandot rss

Note: Watch for social icons on posts by your favorite authors to follow their postings on these and other social sites.

Your profile

    Search

    XML Feeds

    Google Ads

    « Transaction Log expanding on restore after shrinkVirtual Lab: Creating the Basic SQL 2008 R2 Virtual Machine »
    comments

    Sometimes you have to "empty" the database, meaning you have to keep everything except data.

    One way is to script "everything", drop DB and create it again.

    Another way is to delete data table by table, taking care of FK constraints, or to drop all FKs, then to remove data and at the end to restore FKs.

    Here are 2 scripts for creating SQL code to:

    1. a) Drop all existing FKs
    b) Truncate tables
    c) Create all FKs

    2. Delete data from all tables in proper order (kill children first parents later method :D)

    Script 1. TRUNCATE with drop/create FKs

    1. SET NOCOUNT ON
    2. GO
    3.  
    4. SELECT 'USE [' + db_name() +']';
    5.  
    6. SELECT 'ALTER TABLE ' +
    7.        '[' + s.name + '].[' + t.name + ']' +
    8.        ' DROP CONSTRAINT [' + f.name +']'
    9.   FROM sys.foreign_keys f
    10.  INNER JOIN sys.TABLES t ON f.parent_object_id=t.object_id
    11.  INNER JOIN sys.schemas s ON t.schema_id=s.schema_id
    12.  WHERE t.is_ms_shipped=0;
    13.  
    14.  
    15. SELECT 'TRUNCATE TABLE ' + '[' + s.name + '].[' + t.name + ']'      
    16.   FROM sys.TABLES t
    17.  INNER JOIN sys.schemas s ON t.schema_id=s.schema_id
    18.  WHERE t.is_ms_shipped=0;
    19.  
    20.  
    21. SELECT 'ALTER TABLE ' +
    22.        '[' + s.name + '].[' + t.name + ']' +
    23.        ' ADD CONSTRAINT [' + f.name + ']' +
    24.        ' FOREIGN KEY (' +        
    25.        Stuff( (SELECT ', ['+col_name(fk.parent_object_id, fk.parent_column_id) +']'
    26.                  FROM sys.foreign_key_columns fk
    27.                 WHERE constraint_object_id = f.object_id
    28.                 ORDER BY constraint_column_id
    29.                   FOR XML Path('')
    30.             ), 1,2,'') + ')' +
    31.        ' REFERENCES [' +
    32.        object_schema_name(f.referenced_object_id)+'].['+object_name(f.referenced_object_id) + '] (' +
    33.        Stuff((SELECT ', ['+col_name(fc.referenced_object_id, fc.referenced_column_id)+']'
    34.                 FROM sys.foreign_key_columns fc
    35.                WHERE constraint_object_id = f.object_id
    36.                ORDER BY constraint_column_id
    37.                  FOR XML Path('')),
    38.               1,2,'') +
    39.         ')' +
    40.         ' ON DELETE ' + REPLACE(f.delete_referential_action_desc, '_', ' ')  +
    41.         ' ON UPDATE ' + REPLACE(f.update_referential_action_desc , '_', ' ') collate database_default
    42.   FROM sys.foreign_keys f
    43.  INNER JOIN sys.TABLES t ON f.parent_object_id=t.object_id
    44.  INNER JOIN sys.schemas s ON t.schema_id=s.schema_id
    45.  WHERE t.is_ms_shipped=0;

    Script 2. DELETE in proper order

    1. SET NOCOUNT ON
    2. GO
    3.  
    4. SELECT 'USE [' + db_name() +']';
    5. ;With a AS
    6. (
    7.    SELECT 0 AS lvl,
    8.           t.object_id AS tblID
    9.      FROM sys.TABLES t
    10.     WHERE t.is_ms_shipped=0
    11.       AND t.object_id NOT IN (SELECT f.referenced_object_id FROM sys.foreign_keys f)
    12.    UNION ALL
    13.    SELECT a.lvl + 1 AS lvl,
    14.           f.referenced_object_id AS tblId
    15.      FROM a
    16.     INNER JOIN sys.foreign_keys f
    17.        ON a.tblId=f.parent_object_id
    18.       AND a.tblID<>f.referenced_object_id
    19. )
    20. SELECT 'Delete from ['+ object_schema_name(tblID) + '].[' + object_name(tblId) + ']'
    21.   FROM a
    22.  GROUP BY tblId
    23. ORDER BY Max(lvl),1

    Note. Don't forget to modify max column display size parameter in SSMS and preferably execute it in "result in text" mode (Ctrl-T)

    About the Author

    User bio image
    Social SitingsTwitterLinkedInLTD RSS Feed
    12900 views
    InstapaperVote on HN

    13 comments

    Comment from: SQLDenis [Member] Email
    SQLDenis Good post, here is another way, of course it uses the undocumented proc sp_MSForEachTable so it might not be allowed. I have used this in the past, I believe I saw this on Roman Rehak's site first but am not sure


    -- disable referential integrity
    EXEC sp_MSForEachTable 'ALTER TABLE ? NOCHECK CONSTRAINT ALL'
    GO

    EXEC sp_MSForEachTable 'TRUNCATE TABLE ?'
    GO

    -- enable referential integrity again
    EXEC sp_MSForEachTable 'ALTER TABLE ? CHECK CONSTRAINT ALL'
    GO
    05/21/10 @ 07:04
    Comment from: niikola [Member] Email
    niikola nice one, didn't cross my mind.

    in fact I use slightly modified version that allows me to select tables I want to truncate, but it would probably work with this approach too.
    05/21/10 @ 08:32
    Comment from: niikola [Member] Email
    niikola And I didn't know you can truncate table with disabled constraints. To be honest I misunderstood BoL.

    BoL: You cannot use TRUNCATE TABLE on tables that are referenced by a FOREIGN KEY constraint.

    There is another constraint for truncate - Indexed views. If you don't have large amount of data ordered delete should do the job.
    05/21/10 @ 10:22
    Comment from: SQLDenis [Member] Email
    SQLDenis Yeah also in order to do a TRUNCATE you need the following:

    The minimum permission required is ALTER on table_name. TRUNCATE TABLE permissions default to the table owner, members of the sysadmin fixed server role, and the db_owner and db_ddladmin fixed database roles, and are not transferable. However, you can incorporate the TRUNCATE TABLE statement within a module, such as a stored procedure, and grant appropriate permissions to the module using the EXECUTE AS clause.
    05/21/10 @ 10:56
    Comment from: niikola [Member] Email
    niikola IMO, this and similar operation should be allowed only to DBA and DBA must have approval for it - even in development environments :-)
    05/21/10 @ 13:58
    Comment from: Ted Krueger (onpnt) [Member]
    Ted Krueger (onpnt) I think most that are concerned about actually securing data share the same opinion :-)
    05/23/10 @ 07:48
    Comment from: Naomi Nosonovsky [Member]
    Naomi Nosonovsky Hi Nikola,

    I've tried to adapt your script for my case. I want to create a script creating several new tables (with foreign constraints, extended properties, etc.).

    I used the part of generating dropping FK constraints. Can you also show how to drop all extended properties as I'm getting errors trying to create them if they exist?

    Thanks.
    07/23/10 @ 13:20
    Comment from: Naomi Nosonovsky [Member]
    Naomi Nosonovsky Nikola,

    Take a look at the comments at this thread

    Relevant MSDN thread

    Looks like you have to make this script more robust
    07/28/10 @ 05:52
    Comment from: Adrian Parker [Visitor]
    Adrian Parker I've tried to post the full script here, but it keeps erroring. I'll repost it on the msdn forum linked to above by Naomi.

    07/28/10 @ 06:15
    Comment from: niikola [Member] Email
    niikola Although we use script without problem, it seems it has to be modified to support schema bind objects. 2nd script (ordered delete statements) will not work for self referencing tables and in this case only way is to disable that FK.

    Unfortunately I do not have time at the moment (at least next 2 weeks).

    07/30/10 @ 01:14
    Comment from: niikola [Member] Email
    niikola Here is my suggestion I posted in above mentioned msdn forum:

    I would suggest you to use above script just to generate "execution" script. That means, instead of exec (@cmd) use Print @cmd.

    Once you get it, you can test if it is correct, made necessary modifications (it is faster to add few modifications manually than spend weeks/months to make "generator" script smart enough). Once you are satisfied test generated script on pre-production (test) database (or at least make backup of production DB before you test it on live data - although I'll highly recommend you not to test anything on live DB) and once you are sure it's good enough you can run it in production DB.

    In addition, it's easy to modify script to test and handle possible errors (use TRANSACTION and use TRY CATCH or simple IF @@ERROR with RAISERROR).

    I rarely use immediate execution of generated batch of SQL statements, and never in production. There are a lot of reasons for it.
    07/30/10 @ 01:39
    Comment from: Naomi Nosonovsky [Member]
    08/12/10 @ 14:52
    Comment from: Naomi Nosonovsky [Member]
    Naomi Nosonovsky Denis,

    Your suggestion doesn't work, I just tried it and got an error.
    11/30/10 @ 13:36

    Leave a comment


    Your email address will not be revealed on this site.

    To mislead the spambots.

    Your URL will be displayed.
    (Line breaks become <br />)
    (Name, email & website)
    (Allow users to contact you through a message form (your email will not be revealed.)