Skip to content

The Dummy Programmer

Stories of daily programming

  • Home
  • My other dummy projects
  • Games
    • Space Y: An Asteroids clone
  • Services
    • What’s my user agent
    • What’s my IP address
  • About
  • Toggle search form

Delete all rows from all tables in a Sql Server database

Posted on May 16, 2019January 29, 2022 By

Delete all rows from all tables in a Sql Server database may not be an easy task.

This because in a relational database you have foreign keys between tables, and to empty all tables you have to write delete statements in the correct order to avoid foreign key violations.

I know that there are scripts to disable and enable all foreign keys so you can easily delete the content of all tables, but suppose you cannot use such a script. The other way is trying to delete data in the correct order.

And here lies the problem: it can be difficult to delete the tables in the right order if the database has big number of tables with a big number of foreign keys.

It would be nice to have a something that tells us in which order we have to make delete statements. Moreover, given the possible presence of circular references between the tables, it would be useful to have evidence of these cases to be able to manage them manually.

The solution

So i decided to write a SQL script to do this job. The script broadly follow these steps:

  • populate a temporary tables with tables you want to exclude
  • read tables foreign keys from the view sys.foreign_keys
  • detect and mark circular references between tables
  • build the list of delete statements, using a recursive query that starts from tables that doesn’t reference other tables and recursively add referencing tables
  • Open a cursor and PRINT the delete statements

After the execution of the script, you will find the result in the tab “Messages” of Sql Server Management Studio.

Here is the script (download here):

-- ************************************************************************
-- Generate a script to empty a SQL Server Database
-- By TheDummyProgrammer (https://www.thedummyprogrammer.com)
-- ************************************************************************
SET NOCOUNT ON;


IF OBJECT_ID('tempdb..#TO_BE_EXCLUDED') IS NOT NULL 
DROP TABLE #TO_BE_EXCLUDED

-- Preparare the table containing the tables to exclude
CREATE TABLE #TO_BE_EXCLUDED
(
TABLE_NAME VARCHAR(100)
)

-- Add here all the tables that you don't want to delete
INSERT INTO #TO_BE_EXCLUDED(TABLE_NAME) VALUES('sysdiagrams')
INSERT INTO #TO_BE_EXCLUDED(TABLE_NAME) VALUES('__RefactorLog')


IF OBJECT_ID('tempdb..#RELS') IS NOT NULL 
DROP TABLE #RELS

-- Prepare the table containing the database relationships
CREATE TABLE #RELS
(
PARENT VARCHAR(100),
REFERENCED VARCHAR(100),
CODE INT,
CIRCULAR INT
)

INSERT INTO #RELS(PARENT, REFERENCED, CODE, CIRCULAR)
SELECT PARENT, REFERENCED, ROW_NUMBER() OVER(ORDER BY PARENT), 0
FROM
(
SELECT DISTINCT 
OBJECT_NAME(FK.parent_object_id) AS PARENT, 
OBJECT_NAME(FK.referenced_object_id) AS REFERENCED
FROM sys.foreign_keys FK
) T


-- Assign the same code to circular references
UPDATE #RELS
SET CODE = (SELECT MIN(CODE)
FROM #RELS R_IN 
WHERE R_IN.PARENT = #RELS.PARENT AND R_IN.REFERENCED = #RELS.REFERENCED
OR R_IN.PARENT = #RELS.REFERENCED AND R_IN.REFERENCED = #RELS.PARENT)

-- Mark circular references
UPDATE #RELS
SET CIRCULAR = 1
WHERE CODE IN (SELECT CODE
FROM #RELS
GROUP BY CODE 
HAVING COUNT(*) > 1
)

IF OBJECT_ID('tempdb..#DBTABLES') IS NOT NULL 
DROP TABLE #DBTABLES


CREATE TABLE #DBTABLES
(
TABLE_NAME VARCHAR(100)
)

INSERT INTO #DBTABLES(TABLE_NAME)
SELECT [name] AS TABLE_NAME
FROM sys.tables

IF OBJECT_ID('tempdb..#DBTABLE_LEVELS') IS NOT NULL 
DROP TABLE #DBTABLE_LEVELS

;WITH 
RELS
AS
(
-- Get a new table removing second instances of circular references
SELECT PARENT, REFERENCED, CODE, CIRCULAR
FROM
(
SELECT PARENT, REFERENCED, CODE, CIRCULAR, ROW_NUMBER() OVER(PARTITION BY CODE ORDER BY PARENT) RN
FROM #RELS
) AS T
WHERE T.RN = 1
),
DBTABLE_LEVELS
AS
(
-- Start from tables that don't reference other tables...
SELECT T.TABLE_NAME, CONVERT(VARCHAR(MAX), T.TABLE_NAME) AS TABLE_PATH, R.CIRCULAR, 0 AS TABLE_LEVEL
FROM #DBTABLES T
LEFT JOIN RELS R ON T.TABLE_NAME = R.PARENT
WHERE R.PARENT IS NULL
UNION ALL
SELECT R.PARENT, CONVERT(VARCHAR(MAX), DL.TABLE_PATH) + '\' + R.PARENT, R.CIRCULAR, DL.TABLE_LEVEL + 1
FROM DBTABLE_LEVELS DL
INNER JOIN RELS R ON DL.TABLE_NAME = R.REFERENCED
WHERE NOT CONVERT(VARCHAR(MAX), DL.TABLE_PATH) LIKE '%\' + R.PARENT + '\%'
AND NOT RIGHT(CONVERT(VARCHAR(MAX), DL.TABLE_PATH), LEN(R.PARENT)) = R.PARENT
)
SELECT DISTINCT TABLE_NAME, CIRCULAR, TABLE_LEVEL
INTO #DBTABLE_LEVELS
FROM DBTABLE_LEVELS
ORDER BY TABLE_LEVEL DESC


DECLARE @TABLE_NAME VARCHAR(100)
DECLARE @CIRCULAR INT
DECLARE @TABLE_LEVEL INT
DECLARE @TABLE_LEVEL_PREV INT

DECLARE CUR CURSOR FOR 
SELECT D.TABLE_NAME, D.CIRCULAR, D.TABLE_LEVEL
FROM #DBTABLE_LEVELS D
LEFT JOIN #TO_BE_EXCLUDED EXC ON D.TABLE_NAME = EXC.TABLE_NAME
WHERE EXC.TABLE_NAME IS NULL
ORDER BY TABLE_LEVEL DESC

OPEN CUR

FETCH NEXT FROM CUR INTO @TABLE_NAME, @CIRCULAR, @TABLE_LEVEL
SET @TABLE_LEVEL_PREV = ''

WHILE @@FETCH_STATUS = 0
BEGIN
IF @TABLE_LEVEL_PREV <> @TABLE_LEVEL
BEGIN
SET @TABLE_LEVEL_PREV = @TABLE_LEVEL
PRINT '-- -------------'
PRINT '-- TABLE_LEVEL: ' + CONVERT(VARCHAR, @TABLE_LEVEL)
PRINT '-- -------------'
END

IF @CIRCULAR = 1
PRINT '-- CIRCULAR REFERENCE DETECTED FOR TABLE ' + @TABLE_NAME

PRINT 'DELETE FROM ' + @TABLE_NAME

FETCH NEXT FROM CUR INTO @TABLE_NAME, @CIRCULAR, @TABLE_LEVEL
END

CLOSE CUR
DEALLOCATE CUR
Sql Server, Sql Server 2016

Post navigation

Previous Post: Lock a Bitlocker drive again after unlocking
Next Post: Plesk panel update error on Linux CentOS 7: The GPG keys listed for the “dell-system-update_dependent” repository are already installed but they are not correct for this package

Related Posts

Sql Server add constraint WITH NOCHECK Sql Server
Get SQL Server version in T-SQL Sql Server
SQL Server and SARGables predicates Sql Server
Sql Server error: A severe error occurred on the current command.  The results, if any, should be discarded. Sql Server
Sql Server: apply an aggregate function to fields values in a row Sql Server
Merge two or more historical tables with Sql Server T-SQL – Part 1 Sql Server

Search

Related posts

  • Multi-tenant database in SQL Server
  • Sql Server error using a database with a CLR assembly
  • Merge two or more historical tables with Sql Server…
  • Merge two or more historical tables with Sql Server…

Categories

  • .NET 6 (1)
  • .NET 7 (1)
  • AJAX (1)
  • Android (2)
  • Apache (4)
  • ASP.NET (9)
  • ASP.NET MVC (3)
  • Avalonia UI (1)
  • BCP (1)
  • Bitlocker (2)
  • C# (14)
  • CentOS (4)
  • ClosedXML (1)
  • CLR (1)
  • DNS (1)
  • Encryption (3)
  • Excel (2)
  • FuelPHP (3)
  • Games (2)
  • Google Chrome (1)
  • GSuite (1)
  • HTML (1)
  • Imagick (2)
  • Javascript (1)
  • Kindle (1)
  • LAMP (3)
  • Linux (7)
  • MariaDB (2)
  • Mathematics (2)
  • MySql (4)
  • NPOI (1)
  • Office 365 (1)
  • Perl (1)
  • PHP (6)
  • Programming (1)
  • Remote desktop (1)
  • SFTP (2)
  • Sockets (3)
  • Sql Server (20)
  • Sql Server 2016 (14)
  • Sql Server 2019 (1)
  • SSL (4)
  • Task scheduler (1)
  • Telerik ASP.NET AJAX (2)
  • The Dummy Programmer Chat (2)
  • Threading (5)
  • Tools (1)
  • TPL (3)
  • TypeScript (3)
  • Ubuntu (4)
  • Virtualization software (3)
  • Visual Studio (1)
  • Visual Studio Code (2)
  • VueJS (1)
  • Web fonts (1)
  • Web programming (6)
  • Windows (12)
  • Windows 10 (15)
  • Windows Forms (1)
  • Windows Server (6)

Copyright © 2024 The Dummy Programmer | Privacy Policy | Terms of use |

Powered by PressBook Masonry Dark

Manage Cookie Consent
This site doesn’t collect user personal data and doesn’t install profiling or analytical cookies, either its own or from third parties. Read our privacy policy for more info.
Functional Always active
The technical storage or access is strictly necessary for the legitimate purpose of enabling the use of a specific service explicitly requested by the subscriber or user, or for the sole purpose of carrying out the transmission of a communication over an electronic communications network.
Preferences
The technical storage or access is necessary for the legitimate purpose of storing preferences that are not requested by the subscriber or user.
Statistics
The technical storage or access that is used exclusively for statistical purposes. The technical storage or access that is used exclusively for anonymous statistical purposes. Without a subpoena, voluntary compliance on the part of your Internet Service Provider, or additional records from a third party, information stored or retrieved for this purpose alone cannot usually be used to identify you.
Marketing
The technical storage or access is required to create user profiles to send advertising, or to track the user on a website or across several websites for similar marketing purposes.
Manage options Manage services Manage {vendor_count} vendors Read more about these purposes
View preferences
{title} {title} {title}