T-SQL Tip: Never Accidentally Update or Delete Data Again!

Reading Time: 12 minutes

Share:

What’s the secret to never accidentally updating or deleting SQL data again? Wrap your SQL code in a TRANSACTION whenever your SQL is modifying data.

Below is how to do so. The full SQL code we used is at the end of this post as well.

The Scenario

Say for instance, you need to update a single Vendor’s Name. Please note that normally we would never do anything directly in SQL that can and should be done using the application, but for demonstration purposes, we’re keeping it simple.

SELECT * FROM PM00200 WHERE VENDORID = ‘PAT’
T-SQL TipOnce we find the record we need to update, we are ready to run the update script.

Good habits are to always take backups of the data you’re about to modify. This tip assumes you follow good practice and have a backup strategy of your own. For this example, we only backed up the table we’re updating.

SELECT * INTO PM00200_04242018 FROM dbo.PM00200
T-SQL Tip

First, make sure you have records in that backup table.

SELECT * FROM PM00200_04242018
T-SQL tipOnce you confirm you have a good backup copy, you can issue the UPDATE statement.

BEGIN TRAN

UPDATE PM00200 SET VENDNAME = ‘PATRICK’

T-SQL tip

Evidently, we moved too quickly and affected all 104 records! The good news is that we started the statement with BEGIN TRAN. We can now issue a ROLLBACK, and it will UNDO all those 104 updates.

But before we do, let’s see what SQL is holding in memory.

SELECT * FROM PM00200
T-SQL tip

As we though, all 104 Vendors have been renamed to PATRICK. It’s a simple matter to undo it.

ROLLBACK
T-SQL tipOur typical practice is to run COMMIT or ROLLBACK multiple times to ensure there are no open TRANSACTIONS. If you run ROLLBACK again, it should error out, letting you know there are no open TRANSACTIONS.

ROLLBACK
T-SQL tipAlternatively, you can check for an open TRANSACTION.

DBCC OPENTRAN
T-SQL tip

There are no active open transactions. If there were, something like this would appear instead:

T-SQL tip

NOTE: When you use BEGIN TRAN, it starts a transaction and waits for the ROLLBACK and COMMIT to complete the TRANSACTION. Until the ROLLBACK or COMMIT is issued, those records are locked, impacting all users. Make sure you have your SQL code ready and are prepared to issue either a COMMIT or ROLLBACK relatively quickly as to not impact users of the system.

Now run the select again, and you should see the data back to the way it was.

T-SQL tip

Now that we’re back to where we started, we can see why our update affected all of the records instead of just one record.

Looks like we did not have the needed where clause. We can make the modification and run again. Remember to include the BEGIN TRAN!

BEGIN TRAN

UPDATE PM00200 SET VENDNAME = ‘PATRICK’ WHERE VENDORID = ‘PAT’
T-SQL tip

Much better result. Now we need to do one final check before we issue a COMMIT. Let’s make sure the update did what we anticipated.

SELECT * FROM PM00200 WHERE VENDORID = ‘PAT’
T-SQL tip

Yes, it did. While you are in the same session as the BEGIN TRAN, you can select the data and see what it is before you issue the COMMIT or ROLLBACK.  Above shows the change. Once you are happy with this change, you can COMMIT it. If you aren’t happy, ROLLBACK again.

COMMIT
T-SQL tipOur habit is to run it twice.
T-SQL tipNow that we’re happy with the change, we can clean up after ourselves. We don’t need that backup anymore, so let’s drop that table.

BEGIN TRAN

DROP TABLE PM00200_04242018

T-SQL tip
Yes, BEGIN TRAN works on all SQL statements. If we wanted to, we could ROLLBACK this as well and it would UNDO the DROP. Until we COMMIT or ROLLBACK, it remains in memory. Let’s quickly check to make sure the right table was dropped.

SELECT * FROM PM00200_04242018
T-SQL tip

This is expected. We just dropped it, so it should not exist. Make sure to complete this transaction and issue a ROLLBACK (which will put this table back) or COMMIT (which will drop the table, deleting it for good.)

ROLLBACK
T-SQL tipRun it again to make sure all transactions are complete.

SELECT * FROM PM00200_04242018
T-SQL tip

Since we rolled back, the table is still there. Let’s do it again and COMMIT.

BEGIN TRAN

DROP TABLE PM00200_04242018
T-SQL tip

COMMIT
T-SQL tipAlways run two or more times to make sure all transactions are complete.

Now that we know it has been both dropped and committed, if we try and select from it, we should get the following error.

SELECT * FROM PM00200_04242018
T-SQL tip

Summary

Whenever running SQL that updates, inserts, or deletes, you should get into the habit of using the BEGIN TRAN statement and then always make sure you COMMIT or ROLLBACK to complete the transactions.

Our Experience

The reason we started using the BEGIN TRAN, as you can imagine, was because of a simple SQL statement that was not fully validated and was executed before it was intended to be and the data was forever modified. From that point forward we made it a habit (even for the most simple updates) to use the BEGIN TRAN. It has saved us lots of work over the years. It follows the same idea of a carpenter to “measure twice, cut once.” Take a little extra time the first time, and it can prove to benefit you in the long run. The extra two minutes to wrap your code in BEGIN TRAN could save you a late night of trying to recover lost data.

Why do we run the ROLLBACK or COMMIT multiple times? I had at one point in my career ran a statement wrapped in a TRANSACTION and did not realize I had another TRANSACTION already open. I then went to lunch. (I left my SQL session open). When I came back from lunch, there were many upset users not to mention my boss and his boss, because the system was unusable. The records I had updated were common records used by most modules in the system. Since I used a BEGIN TRAN and did not COMMIT or ROLLBACK, it put a LOCK on every record I updated and no user could access the data. It basically brought the system to a halt. Of course, at that time I did not realize I had been the cause of this, and it had taken some additional time before realizing I had these records locked. I had not realized I had not COMMITTED all of my open TRANSACTIONS. Once I did everything was fine again.

What had happened was, while executing my scripts, I had run the BEGIN TRAN statement more than once without completing them by running the ROLLBACK or COMMIT statement. Sometimes when you run your SQL, it fails. If you start that SQL with a BEGIN TRAN, in some cases it starts a TRANSACTION, even if the SQL fails. I did not realize this. So now, to be safe, we always issue COMMIT or ROLLBACK more than one time to make sure there are no left TRANSACTIONS hanging open and potentially causing issues.

If you don’t have a dedicated IT partner to help you with your technology needs big and small, contact Sikich today and let’s see how we can help.

Full SQL Code Used

Below is the SQL we used for this example.

/*
Tip for updating records in SQL
Use TRANSACTIONS
Use Comments
I’m a big fan of commenting out my SQL statements when I have multiple and then I highlight and execute the ones I want, when I need to
Main purpose: If I accidentally press F5 or click the Execute button I won’t inadvertently run all the SQL. It will only
run what is not commented

Purpose:
By wrapping your SQL INSERT UPDATE or DELETE statement in a TRANSACTION you have the ability to ROLLBACK or COMMIT your changes.
This gives you an additional layer of checks and balances to make sure you update only what you intend to update.
If not, you can issue a ROLLBACK and it will be as-if you did not issue the SQL statement at all

PROS:
– Additional checks and balances. It allows you to control when the COMMIT happens and more importantly
gives you the option to ROLLBACK in the event something was off
– Piece of mind knowing if even the most simple of update statements goes wrong you can ROLLBACK

CONS:
– It holds onto that record and the records around it until the COMMIT or ROLLBACK is issued, potentially locking other users
– If you have many records to update it could take time and memory
– Can take a little more time to execute your statements because you have to wrap the code in the TRAN statement
– You can forget to issue the COMMIT or ROLLBACK and that locks the record and potentially other records around it
*/

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
EXAMPLE:
Here’s a simple UPDATE statement scenario:

Need to update the Vendor Name for 1 specific vendorid
You write a SELECT statement to make sure you find this vendor and only this 1 vendor
You then write your update statement.
However, in a rush you forget to add the WHERE clause and it updates all records in the table.
If you wrap the SQL in a TRAN statement you can run the ROLLBACK command and undo what you accidentally did.

We’ve all been here and wish there were a way to undo what was done.

Hopefully a backup was taken. At minimum you had taken a backup of that table you updated.

If not, this one very minor and simple update has now ruined your day and you will be spending the time trying to get back all of your vendor names

DBCC OPENTRAN

*/

/*
Here are the steps I follow:
*/
/*-=-=-=-=-=-=-=-= Step 1: Take a backup. =-=-=-=-=-=-=-=-=-=-=-=-=-

Some situations require a full database backup and others only a table. This tip is assuming you know when to do what.
In this scenario I simply do a SELECT into and make a copy of the Vendor Master

–Make a backup of the table I am updating
SELECT * INTO PM00200_04242018 FROM dbo.PM00200

–Make sure you have records in that backup table
SELECT * FROM PM00200_04242018
*/

/*-=-=-=-=-=-=-=-= Step 2: Find the record I want to update. =-=-=-=-=-=-=-=-=-=-=-=-=-
–I do this to also find the number of records that should be updated.
SELECT * FROM PM00200 WHERE VENDORID = ‘PAT’

/*-=-=-=-=-=-=-=-= Step 3: Execute my update statement, wrapped in a TRANSACTION =-=-=-=-=-=-=-=-=-=-=-=-=-
–Here’s where the update occurs, within a TRANSACTION statement
–Highlight from BEGIN TRAN to the end of ‘PATRICK’

BEGIN TRAN
UPDATE PM00200 SET VENDNAME = ‘PATRICK’

–Confirm the number of records updated. Should be 1 and only 1. Anything other than that and I want to ROLLBACK and then figure out why.

–In this example I left the WHERE clause off and it updated all 104 Vendor Records in my Vendor Master table
–I used the BEGIN TRAN statement so it is waiting for a COMMIT or ROLLBACK
–Until I issue one of those commands the update is held in memory, in my session.
–IMPORTANT: All of the vendor records are LOCKED until the COMMIT or ROLLBACK is issued as well, so do not take too long.
–If you are unsure of something, run the ROLLBACK and it will reset everything and release the locks while you figure out the issue

–In my case I expected 1 record to be updated and it updated all 104. I obviously want to run the ROLLBACK.
–Before I ROLLBACK, however, run a select to see the data held in memory
SELECT * FROM PM00200

–You will see every vendor now has a name PATRICK
–Simply highlight the word ROLLBACK and click execute or F5 to run it.

–TIP:
–I always run the ROLLBACK or COMMIT 2 or more times. The reason for this is you could have inadvertently created multiple transactions waiting for a
–COMMIT or ROLLBACK.
–If you run a COMMIT or ROLLBACK and there is no open TRANSACTION it will produce an error.
–Alternatively you could check for an open tran by using DBCC OPENTRAN

COMMIT
ROLLBACK

–Add the WHERE clause and re-run
BEGIN TRAN
UPDATE PM00200 SET VENDNAME = ‘PATRICK’ WHERE VENDORID = ‘PAT’

–This time I got the expected result. 1 record updated.
–Now I can run the COMMIT

/*-=-=-=-=-=-=-=-= Step 4: If you are satisfied with the results, you can delete the backup table you created in Step 1 =-=-=-=-=-=-=-=-=-=-=-=-=-

–Yes you can wrap a DROP statement into a TRANSACTION as well
BEGIN TRAN
DROP TABLE PM00200_04242018

–Before you COMMIT or ROLLBACK, select from that table
SELECT * FROM PM00200_04242018

–This should produce an error because this object no longer exists.
–If you issue a ROLLBACK, it will undo your DROP
–Otherwise COMMIT the DROP to permanently delete that table

COMMIT
ROLLBACK
*/

This publication contains general information only and Sikich is not, by means of this publication, rendering accounting, business, financial, investment, legal, tax, or any other professional advice or services. This publication is not a substitute for such professional advice or services, nor should you use it as a basis for any decision, action or omission that may affect you or your business. Before making any decision, taking any action or omitting an action that may affect you or your business, you should consult a qualified professional advisor. In addition, this publication may contain certain content generated by an artificial intelligence (AI) language model. You acknowledge that Sikich shall not be responsible for any loss sustained by you or any person who relies on this publication.

SIGN-UP FOR INSIGHTS

Join 14,000+ business executives and decision makers

Upcoming Events

Upcoming Events

Latest Insights

About The Author