> ## Content Index
> Fetch the complete content index at: https://nolongerset.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# Using PRINT to Improve Safety of Live SQL Server Updates
- URL: https://nolongerset.com/sql-server-print-statement/
- Published: 2024-10-15T16:15:03.000Z
- Updated: 2026-05-08T12:42:13.000Z
- Description: [Me]: Let's DELETE 5 records. [SSMS]: (7,393,253 rows affected) [Me]: {Updates LinkedIn profile: "#OPENTOWORK"} Avoid nasty SQL surprises with this easy technique.
- Author: Mike Wolfe
- Tags: SQL Server, Defensive Programming, #Import 2026-05-20 02:59

One of my more underrated posts was the B-BEAR technique I use to test changes to production SQL Server data before making them:

[B-BEAR: Quick and Dirty SQL Server TestingBegin, Before, Execute, After, Rollback. This technique makes testing your SQL Server statements a snap.![](https://nolongerset.com/content/images/size/w256h256/2020/09/NLS_Icon_square.png)No Longer SetMike Wolfe![](https://nolongerset.com/content/images/2023/04/B-BEAR.png)](https://nolongerset.com/quick-and-dirty-sql-server-testing/)

I now use this technique whenever I adjust live data. 

Here's the tl;dr version:

```sql
-- BEGIN: Begin a transaction
BEGIN TRAN  

-- BEFORE: One or more SELECT queries to show the starting state of the data
SELECT * FROM MyTable
SELECT * FROM MySubTable

-- EXECUTE: Execute some stored procedure or INSERT/UPDATE/DELETE query
EXEC dbo.MySproc

-- AFTER: Re-run the same SELECT queries as above to show the end state
SELECT * FROM MyTable
SELECT * FROM MySubTable

-- ROLLBACK: Roll back the transaction so we can 
--           tweak the Execute step and re-test
ROLLBACK 
```

## Checking the "Rows Affected" Counts

One of the benefits of using this technique is you can make sure you're not accidentally changing more data than you intend:

![](https://storage.ghost.io/c/eb/d7/ebd732c1-5f03-4f07-b386-5d08557e15c9/content/images/2024/10/image-7.png)

To that end, I always check the "Messages" tab of SSMS while developing my T-SQL script (i.e., while using `ROLLBACK TRAN`). The "Messages" tab shows how many records are affected by each SQL statement.

For example, let's say I have five records I want to update. Using the B-BEAR technique, I would execute three SQL statements:

1. **BEFORE**: A SELECT query that returns the five records as they currently exist in the database
2. **EXECUTE**: An UPDATE statement that makes changes to those five records
3. **AFTER**: The same SELECT query as above, showing the changes were applied as I expected

When I look at the Messages tab, I should see this:

```
(5 rows affected)

(5 rows affected)

(5 rows affected)
```

If I see something like this, I know there's a problem (and I'm *really* glad I tested first):

```
(5 rows affected)

(794 rows affected)

(5 rows affected)
```

## Executing Multiple Statements

Sometimes I need to make changes to multiple tables.

If I'm updating three tables, I suddenly have nine messages: 

- 3 messages for the SELECTs (BEFORE)
- 3 messages for the UPDATEs (EXECUTE)
- 3 messages for the SELECTs (AFTER)

In those situations, though, I often include additional queries in the BEFORE section. And I'll often have INSERT or DELETE queries in the EXECUTE section. Before long, I've got more than a dozen messages with different numbers of records being INSERTed, DELETEd, or UPDATEd. Keeping track of which counts go with which statements gets a bit hairy.

Here's a recent example from a particularly thorny issue I'm trying to resolve:

```
(5 rows affected)

(5 rows affected)

(5 rows affected)

(10 rows affected)

(2 rows affected)

(5 rows affected)

(24 rows affected)

(5 rows affected)

(5 rows affected)

(5 rows affected)

(5 rows affected)

(29 rows affected)
```

Most of those messages pertain to SELECT queries, but in the middle of all that are two UPDATE statements and an INSERT statement. Which ones are they? Beats me.

## PRINT Statement to the Rescue

Rather than rely on counting SQL statements and matching things up manually, I add `PRINT` statements to my B-BEAR script. 

The T-SQL PRINT statement is equivalent to the VBA `Debug.Print` statement.

Here's an example:

```sql
PRINT 'About to update 5 records in the Memberships table'
UPDATE Memberships ...

PRINT 'About to update 5 "DD" records in the Invoices table'
UPDATE Invoices ...

PRINT 'About to insert 5 Adjustment records ("AJ") in the Payments table'
INSERT INTO Payments ...
```

Now, when I execute this test script, this is what my Messages tab looks like:

```
(5 rows affected)

(5 rows affected)

(5 rows affected)

(10 rows affected)

(2 rows affected)

(5 rows affected)

(24 rows affected)
About to update 5 records in the Memberships table

(5 rows affected)
About to update 5 "DD" records in the Invoices table

(5 rows affected)
About to insert 5 Adjustment records ("AJ") in the Payments table

(5 rows affected)

(5 rows affected)

(29 rows affected)
```

Unfortunately, SSMS inserts a blank line before each row count line in the Messages pane, so the PRINT message doesn't group nicely with the row count. 

![](https://storage.ghost.io/c/eb/d7/ebd732c1-5f03-4f07-b386-5d08557e15c9/content/images/2024/10/image-8.png)

You could get around this by rewriting the PRINT messages ("About to update..." > "Just updated...") and placing them *after* their respective SQL statements. I don't think it's worth the tradeoff of having the PRINT statement come after its SQL statement in the SQL editing pane, though.