Problem
In my last tip, Best Practices for Deleting SQL Server Data, I showed some examples of how you can get into trouble when deleting data from the backend database. I also mentioned in the next steps that there are some ways you can protect yourself when you do have to delete data this way. This tip will give you one method for ensuring you are deleting the number of records you are expecting to be deleted.
Solution
When it comes to best practices I am always in favor all DML changes being made through an application and not being done directly against the database using T-SQL commands. When done this way we can ensure that the code has been tested to validate that it is going to do what it is intended to do. That said, there are always cases that come up, whether it be from a bug in an application adding/updating records incorrectly or someone running a script against the database that was not fully tested or even providing the incorrect file to a data loader service/application when we are tasked with removing this unwanted data from the database manually using T-SQL.
Through my years as a DBA I’ve used many different templates and processes to handle removing data from a database, but I have found that the best way to protect yourself is to validate the number of records you are deleting and make sure this count is correct. Many times I’ve seen template scripts where someone forgets to update an ID in the where clause and they delete the wrong data or they miss a condition in the where clause and delete too much data. I’ve even seen one case when the where clause was omitted and everything was deleted.
Sample Setup
To demonstrate how our stored procedure works we’ll need a simple table loaded with some random data. Below is the T-SQL to create this table.
-- table setup
CREATE TABLE Main (col1 INT primary key, col2 INT);
DECLARE @val INT
SELECT @val=1
WHILE @val < 50000
BEGIN
INSERT INTO Main VALUES (@val,round(rand()*100000,0));
SELECT @val=@val+1;
END;
Delete SQL Server Stored Procedure
Hopefully the reasons above are enough to convince you that checking the count is a good way to help avoid these issues, so let’s take a look at a stored procedure I put together that will validate the number of records we remove when we are performing a delete. Here is the T-SQL to create this SQL Server stored procedure.
-- create procedure
CREATE PROCEDURE sp_delete_from_table (@table sysname,
@whereclause varchar(7000),
@delcnt bigint,
@actcnt bigint output) AS
BEGIN
declare @sql varchar(8000)
begin transaction
select @sql='delete from ' + @table + ' ' + @whereclause
execute(@sql)
select @actcnt=@@rowcount
if @actcnt=@delcnt
begin
print cast(@actcnt as varchar) + ' rows have been deleted.'
commit transaction
end
else
begin
print 'Statement would have deleted ' + cast(@actcnt as varchar) +
' rows so the transaction has been rolled back.'
rollback transaction
select @actcnt=0
end
END
GO
The code for the procedure is pretty straightforward. The parameters required are the table you want to delete from, the where clause which identifies which records will be deleted and the count of records you expect to be deleted.
The first step of the procedure begins a new transaction which will allow us to rollback later if needed. It then builds and executes the delete statement based on the parameters passed to the stored procedure. It uses @@rowcount after the delete executes to determine if the expected number of records were deleted. If these match then a message is printed and the transaction is committed. If the record counts don’t match, then a message is printed to tell you how many rows would have been deleted and the transaction is rolled back.
One thing to note with the stored procedure is that you can pass in anything for the where clause. It is not checked so you could set this parameter to something like ‘WHERE 1=1’ if you wanted to delete the entire table and as long as you pass in the correct expected delete count the records will be deleted.
Example Usage
Now that we know how it all works let’s take a look at a couple examples.
The first stored procedure call below shows what would be output if the incorrect expected record count is passed to the stored procedure.
-- rollback example
declare @actcnt bigint
exec sp_delete_from_table 'Main','where col2=85942',1,@actcnt output
And here is the output from the above example.
-- rollback output
Statement would have deleted 6 rows so the transaction has been rolled back.
The second call shows what is output when the correct expected count is passed and the stored procedure successfully deletes the data from the table.
-- success example
declare @actcnt bigint
exec sp_delete_from_table 'Main','where col2=85942',6,@actcnt output
And here is the output from the above example.
-- success output
6 rows have been deleted.
Next Steps
- Investigate extending the functionality of this stored procedure to include table updates
- Use triggers to prevent accidental data updates/deletes
- Read other tips on deleting data:
Ben Snaidero has been a Database Administrator for just over 10 years. Starting out working mainly with Oracle he got into SQL Server in 2005 and has worked primarily with SQL Server for the last 3 years. His main focus with both Oracle and SQL Server is in the area of performance tuning.
- MSSQLTips Awards: Achiever (75+ tips) – 2018 | Author of the Year Contender – 2016-2017


