SQL Server Stored Procedure to Safely Delete Data
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.
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.
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.
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.
- 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:
About the author
View all my tips