Skip to content

Instantly share code, notes, and snippets.

@farseenmanekhan1232
Created July 15, 2025 10:20
Show Gist options
  • Save farseenmanekhan1232/8ba31bec347363308dd991dc3b4bad8f to your computer and use it in GitHub Desktop.
Save farseenmanekhan1232/8ba31bec347363308dd991dc3b4bad8f to your computer and use it in GitHub Desktop.
/*
================================================================================================
SCRIPT TO DELETE ALL BUT THE TOP 5000 ROWS FROM EACH TABLE IN A DATABASE (REVISED)
================================================================================================
--
-- HOW TO USE:
-- 1. Make a file copy of your .mdf and .ldf files.
-- 2. Attach the copied files as a NEW database in SSMS (e.g., 'Gas5000').
-- 3. CHANGE the database name in the 'USE' statement below to your new database.
-- 4. Execute this script.
--
-- WHAT IT DOES:
-- This script iterates through every user table in the specified database. For each table,
-- it identifies which rows to KEEP based on an ordering principle and deletes all others.
--
-- !! IMPORTANT NOTE ON "TOP 5000 ROWS" !!
-- SQL tables are inherently unordered. To determine the "top" rows, we must ORDER BY a
-- column. This script automatically tries to use the table's primary key. If no primary
-- key is found, it uses the first column of the table as a fallback.
--
================================================================================================
*/
-- <<-- 1. SET THE NAME OF YOUR COPIED DATABASE HERE
USE [Gas5000];
GO
SET NOCOUNT ON;
DECLARE @schemaName NVARCHAR(128);
DECLARE @tableName NVARCHAR(128);
DECLARE @orderByColumn NVARCHAR(128);
DECLARE @sql NVARCHAR(MAX);
DECLARE @fullTableName NVARCHAR(257); -- schema.table
PRINT 'Starting data trim process for database: ' + QUOTENAME(DB_NAME());
PRINT '================================================================';
-- Declare a cursor to loop through all user tables in the current database.
DECLARE table_cursor CURSOR FOR
SELECT s.name, t.name
FROM sys.tables AS t
INNER JOIN sys.schemas AS s ON t.schema_id = s.schema_id
WHERE t.type = 'U' -- User Table
AND t.is_ms_shipped = 0
ORDER BY s.name, t.name;
OPEN table_cursor;
FETCH NEXT FROM table_cursor INTO @schemaName, @tableName;
WHILE @@FETCH_STATUS = 0
BEGIN
SET @fullTableName = QUOTENAME(@schemaName) + '.' + QUOTENAME(@tableName);
PRINT 'Processing table: ' + @fullTableName;
-- Reset the ordering column for each table
SET @orderByColumn = NULL;
-- Try to find the primary key column to use for ordering.
SELECT TOP 1 @orderByColumn = c.name
FROM sys.indexes AS i
INNER JOIN sys.index_columns AS ic ON i.object_id = ic.object_id AND i.index_id = ic.index_id
INNER JOIN sys.columns AS c ON ic.object_id = c.object_id AND c.column_id = ic.column_id
WHERE i.is_primary_key = 1 AND i.object_id = OBJECT_ID(@fullTableName);
-- If no primary key, find the first column of the table as a fallback.
IF @orderByColumn IS NULL
BEGIN
SELECT TOP 1 @orderByColumn = name
FROM sys.columns
WHERE object_id = OBJECT_ID(@fullTableName)
ORDER BY column_id;
PRINT ' -> No primary key found. Using first column for ordering: ' + QUOTENAME(@orderByColumn);
END
ELSE
BEGIN
PRINT ' -> Using primary key for ordering: ' + QUOTENAME(@orderByColumn);
END
IF @orderByColumn IS NOT NULL
BEGIN
-- Construct the dynamic DELETE statement using a Common Table Expression (CTE).
-- This identifies all rows beyond the first 5000 and deletes them.
SET @sql = '
;WITH RowsToDelete AS (
SELECT ROW_NUMBER() OVER(ORDER BY ' + QUOTENAME(@orderByColumn) + ' ASC) AS RowNum
FROM ' + @fullTableName + '
)
DELETE FROM RowsToDelete WHERE RowNum > 5000;
';
BEGIN TRY
-- Execute the delete
EXEC sp_executesql @sql;
PRINT ' -> Successfully deleted rows. ' + CONVERT(NVARCHAR, @@ROWCOUNT) + ' rows affected.';
END TRY
BEGIN CATCH
PRINT ' -> ERROR trimming table ' + @fullTableName + ': ' + ERROR_MESSAGE();
END CATCH
END
ELSE
BEGIN
-- This case should be rare, only happening for tables with no columns.
PRINT ' -> ERROR: Could not determine a column to order by. Skipping table.';
END
PRINT '----------------------------------------------------------------';
FETCH NEXT FROM table_cursor INTO @schemaName, @tableName;
END;
CLOSE table_cursor;
DEALLOCATE table_cursor;
PRINT '================================================================';
PRINT 'Data trim process finished.';
PRINT 'RECOMMENDATION: You should now shrink the database files to reclaim disk space.';
GO
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment