<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://www2.sqlblog.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Merrill Aldrich : transactions</title><link>http://www2.sqlblog.com/blogs/merrill_aldrich/archive/tags/transactions/default.aspx</link><description>Tags: transactions</description><dc:language>en</dc:language><generator>CommunityServer 2.1 SP2 (Build: 61129.1)</generator><item><title>T-SQL Tuesday #31: Paradox of the Sawtooth Log</title><link>http://www2.sqlblog.com/blogs/merrill_aldrich/archive/2012/06/12/t-sql-tuesday-31-paradox-of-the-sawtooth-log.aspx</link><pubDate>Tue, 12 Jun 2012 07:10:29 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:43843</guid><dc:creator>merrillaldrich</dc:creator><slash:comments>0</slash:comments><comments>http://www2.sqlblog.com/blogs/merrill_aldrich/comments/43843.aspx</comments><wfw:commentRss>http://www2.sqlblog.com/blogs/merrill_aldrich/commentrss.aspx?PostID=43843</wfw:commentRss><description>Today’s T-SQL Tuesday, hosted by Aaron Nelson ( @sqlvariant | sqlvariant.com ) has the theme Logging . I was a little pressed for time today to pull this post together, so this will be short and sweet. For a long time, I wondered why and how a database...(&lt;a href="http://www2.sqlblog.com/blogs/merrill_aldrich/archive/2012/06/12/t-sql-tuesday-31-paradox-of-the-sawtooth-log.aspx"&gt;read more&lt;/a&gt;)&lt;img src="http://www2.sqlblog.com/aggbug.aspx?PostID=43843" width="1" height="1"&gt;</description><category domain="http://www2.sqlblog.com/blogs/merrill_aldrich/archive/tags/log/default.aspx">log</category><category domain="http://www2.sqlblog.com/blogs/merrill_aldrich/archive/tags/transactions/default.aspx">transactions</category><category domain="http://www2.sqlblog.com/blogs/merrill_aldrich/archive/tags/T-SQL+Tuesday/default.aspx">T-SQL Tuesday</category></item><item><title>Pop Quiz: Restore a Database to the Point in Time when a Full Backup Started?</title><link>http://www2.sqlblog.com/blogs/merrill_aldrich/archive/2010/11/01/pop-quiz-restore-a-database-to-the-point-in-time-when-a-full-backup-started.aspx</link><pubDate>Mon, 01 Nov 2010 18:26:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:30061</guid><dc:creator>merrillaldrich</dc:creator><slash:comments>6</slash:comments><comments>http://www2.sqlblog.com/blogs/merrill_aldrich/comments/30061.aspx</comments><wfw:commentRss>http://www2.sqlblog.com/blogs/merrill_aldrich/commentrss.aspx?PostID=30061</wfw:commentRss><description>Recently we've had to interview some SQL Server DBA candidates for our team, and we were looking for the type of open-ended technical questions that would draw out interviewees and let us get a sense of their thought process. A surprisingly simple question...(&lt;a href="http://www2.sqlblog.com/blogs/merrill_aldrich/archive/2010/11/01/pop-quiz-restore-a-database-to-the-point-in-time-when-a-full-backup-started.aspx"&gt;read more&lt;/a&gt;)&lt;img src="http://www2.sqlblog.com/aggbug.aspx?PostID=30061" width="1" height="1"&gt;</description><category domain="http://www2.sqlblog.com/blogs/merrill_aldrich/archive/tags/backup/default.aspx">backup</category><category domain="http://www2.sqlblog.com/blogs/merrill_aldrich/archive/tags/disaster+recovery/default.aspx">disaster recovery</category><category domain="http://www2.sqlblog.com/blogs/merrill_aldrich/archive/tags/transactions/default.aspx">transactions</category></item><item><title>Flow control in T-SQL Scripts</title><link>http://www2.sqlblog.com/blogs/merrill_aldrich/archive/2009/07/24/flow-control-in-t-sql-scripts.aspx</link><pubDate>Fri, 24 Jul 2009 15:17:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:15471</guid><dc:creator>merrillaldrich</dc:creator><slash:comments>15</slash:comments><comments>http://www2.sqlblog.com/blogs/merrill_aldrich/comments/15471.aspx</comments><wfw:commentRss>http://www2.sqlblog.com/blogs/merrill_aldrich/commentrss.aspx?PostID=15471</wfw:commentRss><description>&lt;P&gt;When many people, including me, began their early T-SQL efforts, the magic two letter GO statement was a bit mysterious. What was that for? Was it just decoration sprinkled through your scripts? What’s the difference when two SQL statements are separated by GO or not?&lt;/P&gt;
&lt;P&gt;Lately, though, I have noticed quite a lot of production code that still misses key elements of flow control in T-SQL scripts, which can cause unexpected results – especially in the realm of mishandled run-time errors. I was just perusing a script from a very well known vendor and I was struck by the fact that if it failed for some reason, the error handling was entirely wrong, and the script would not have actually done what its author seemed to expect, based on the code. Luckily it ran without issue.&lt;/P&gt;
&lt;P&gt;Articles and blog entries do exist on error handling in T-SQL; especially good are the series by &lt;A href="http://www.sommarskog.se/index.html"&gt;Erland Sommarskog&lt;/A&gt; and Itzik Ben-Gan’s book &lt;A href="http://www.microsoft.com/learning/en/us/books/8564.aspx"&gt;Inside SQL Server 2005: T-SQL Programming&lt;/A&gt;. There’s great stuff on handling errors and transactions in deployed stored procs, for example. So as not to tread over the same material, I want to point out some techniques in this post specific to script flow control – that is, when you run a T-SQL or SQLCMD script in Management Studio, how do you correctly trap errors and stop or continue execution at the right place in your script?&lt;/P&gt;
&lt;P&gt;Did you know that if you raise an error in a script, the script will not typically stop, but instead will continue on its merry way, at either the next statement or the next batch? More importantly, did you know that that is likely to happen even after you roll back an explicit transaction? If not, please read on! In this first installment I will talk about “old school” flow control, which works against both new and older versions of SQL Server.&amp;nbsp;A future&amp;nbsp;post will describe how the Try/Catch structure added in 2005 fits in. (Hint: if you can use Try/Catch, go for it; it's a lot better.)&lt;/P&gt;
&lt;H4&gt;GO is Vital&lt;/H4&gt;
&lt;P&gt;In order to make this clear I have to lay out a couple of basic terms, so that the later explanations make sense. First, a &lt;EM&gt;batch&lt;/EM&gt; is a series of one or more SQL statements that come one after the other, and that are only separated by the GO batch terminator at the end of the sequence. (B.O.L. describes how GO is not really a T-SQL statement at all, but is in fact just a separator, defined at the client, that causes batches of statements to be sent to SQL Server; each batch is treated as a single unit at the server, and is compiled and executed as one “thing.”) What is most important for our purposes is that GO is vital in flow control when there’s an error to be handled, because it can separate a series of SQL statements into distinct blocks. A batch of statements acts as a unit at the server in important ways.&lt;/P&gt;
&lt;P&gt;Second, I’ll use the term &lt;EM&gt;script&lt;/EM&gt; to mean a collection of one or many batches that are typically in the query editor together, get sent to the SQL Server in sequence when you execute, and perhaps are stored in a text file. Each batch in a script is separated by the batch separator (GO).&lt;/P&gt;
&lt;P&gt;For example:&lt;/P&gt;&lt;PRE&gt;&lt;CODE&gt;&lt;SPAN style="COLOR:green;"&gt;-- Batch 1
&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;PRINT &lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'This is the first statement in the first batch'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;;
&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;PRINT &lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'This is the second statement in the first batch'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;;
&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;GO &lt;/SPAN&gt;&lt;SPAN style="COLOR:green;"&gt;-- End of Batch 1
-- Batch 2
&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;PRINT &lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'This is the second batch'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;;
&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;GO &lt;/SPAN&gt;&lt;SPAN style="COLOR:green;"&gt;-- End of Batch 2
&lt;/SPAN&gt;
&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;A profiler trace when running this example will reveal that it executes in two discreet batches, even when the batches contain multiple individual statements. Worth noting: At the server, not only are the batches separate events, but there is very little relationship between them at all, other than that they came from the same client connection. They are executed almost as if they were two separate little programs. This accounts for why you can’t persist a variable “across” a GO statement; if a variable is defined in one batch, it is eliminated at the end of that batch’s execution at the server. In most respects, the next batch bears no relationship to the previous one. There are exceptions, including connection-level settings and transactions.&lt;/P&gt;
&lt;P&gt;From a flow-control point of view, then, I would like to point out two issues: 
&lt;UL&gt;
&lt;LI&gt;How does one correctly stop processing inside a batch, if a run-time error occurs?&lt;/LI&gt;
&lt;LI&gt;How does one stop processing a whole script, if an error occurs in one batch, perhaps near the beginning of a long and complex script?&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;These two problems imply that two things need to happen: what Erland Sommarskog calls Batch-Aborting events, and what could be called Script-Aborting events. Batch-Aborting events are those that prevent a batch from executing the statements following one that caused an error. Script-Aborting events prevent the execution of following batches from the script.&lt;/P&gt;
&lt;P&gt;Here is where the batch-script distinction becomes important: batches execute at the server, while a collection of batches, chained together, can only be controlled by the client. Put another way, a batch-aborting event has to be a server event: you have to direct the server to stop executing the batch in the middle. A script-aborting event has to be a client event, otherwise, collectively, the system will resume execution at beginning of the next batch that the client submits.&lt;/P&gt;
&lt;H4&gt;Perhaps RETURN needs to Become Popular&lt;/H4&gt;
&lt;P&gt;I don’t often see the RETURN statement in T-SQL scripts, which is a shame. The simplest way I know of to stop the execution of a batch, at the server, is with RETURN.&lt;/P&gt;
&lt;P&gt;RETURN “Exits unconditionally from a query or procedure. RETURN is immediate and complete and can be used at any point to exit from a procedure, batch, or statement block. Statements that follow RETURN are not executed.” – B.O.L&lt;/P&gt;
&lt;P&gt;The RETURN statement, in a script, will direct the server to stop executing the current batch, without doing any further work. It can be combined with error checking to cause a batch to stop for a run-time error:&lt;/P&gt;&lt;PRE&gt;&lt;CODE&gt;&lt;SPAN style="COLOR:blue;"&gt;DECLARE  &lt;/SPAN&gt;&lt;SPAN style="COLOR:#434343;"&gt;@pretendError &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;INT&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;;
&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;SET &lt;/SPAN&gt;&lt;SPAN style="COLOR:#434343;"&gt;@pretendError &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;= &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;1&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;;

&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;PRINT &lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'This is the first statement in the first batch'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;;

&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;IF &lt;/SPAN&gt;&lt;SPAN style="COLOR:#434343;"&gt;@pretendError &lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;!= &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;0
  &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;RETURN&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;;

&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;PRINT &lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'This second statement in the first batch will not execute'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;;
&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;GO &lt;/SPAN&gt;&lt;SPAN style="COLOR:green;"&gt;-- End of Batch 1

-- Batch 2
&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;PRINT &lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'This is the second batch'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;;
&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;GO &lt;/SPAN&gt;&lt;SPAN style="COLOR:green;"&gt;-- End of Batch 2
&lt;/SPAN&gt;
&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;When executed, the above sample will execute the first Print statement, then exit Batch 1, but will resume with the next batch the client submitted, so it will execute the last Print statement. The resulting output is:&lt;/P&gt;&lt;PRE&gt;&lt;CODE&gt;This is the first statement in the first batch
This is the second batch
&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;RAISERROR() is great, but unfortunately it does not have this behavior:&lt;/P&gt;&lt;PRE&gt;&lt;CODE&gt;&lt;SPAN style="COLOR:green;"&gt;-- Batch 1
&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;DECLARE  &lt;/SPAN&gt;&lt;SPAN style="COLOR:#434343;"&gt;@pretendError &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;INT&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;;
&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;SET &lt;/SPAN&gt;&lt;SPAN style="COLOR:#434343;"&gt;@pretendError &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;= &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;1&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;;

&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;PRINT &lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'This is the first statement in the first batch'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;;

&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;IF &lt;/SPAN&gt;&lt;SPAN style="COLOR:#434343;"&gt;@pretendError &lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;!= &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;0
  &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;RAISERROR &lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'Raise Error is great but does not stop the batch'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;, &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;11&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;, &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;1&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;);

&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;PRINT &lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'This second statement in the first batch will STILL execute'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;;
&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;GO &lt;/SPAN&gt;&lt;SPAN style="COLOR:green;"&gt;-- End of Batch 1

-- Batch 2
&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;PRINT &lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'This is the second batch'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;;
&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;GO &lt;/SPAN&gt;&lt;SPAN style="COLOR:green;"&gt;-- End of Batch 2
&lt;/SPAN&gt;
&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;The output for this example is:&lt;/P&gt;&lt;PRE&gt;&lt;CODE&gt;This is the first statement in the first batch
&lt;SPAN style="COLOR:red;"&gt;Msg 50000, Level 11, State 1, Line 6
Raise Error is great but does not stop the batch&lt;/SPAN&gt;
This second statement in the first batch will STILL execute
This is the second batch
&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;So, we can RAISERROR(s), but the remainder of the batch and script will still execute, unless we’re very careful to include some other structure like a RETURN, or a GOTO statement paired to a labeled error handler:&lt;/P&gt;&lt;PRE&gt;&lt;CODE&gt;&lt;SPAN style="COLOR:green;"&gt;-- Batch 1
&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;DECLARE  &lt;/SPAN&gt;&lt;SPAN style="COLOR:#434343;"&gt;@pretendError &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;INT&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;;
&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;SET &lt;/SPAN&gt;&lt;SPAN style="COLOR:#434343;"&gt;@pretendError &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;= &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;1&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;;

&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;PRINT &lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'This is the first statement in the first batch'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;;

&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;IF &lt;/SPAN&gt;&lt;SPAN style="COLOR:#434343;"&gt;@pretendError &lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;!= &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;0
  &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;BEGIN
    RAISERROR &lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'Raise Error is great but does not stop the batch'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;, &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;11&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;, &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;1&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;);
    &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;GOTO &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;handle_badness &lt;/SPAN&gt;&lt;SPAN style="COLOR:green;"&gt;-- This is the thing that stops batch execution
  &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;END

PRINT &lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'This second statement in the first batch will now be skipped'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;;

&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;GOTO &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;batch_end

handle_badness:
      &lt;/SPAN&gt;&lt;SPAN style="COLOR:green;"&gt;-- Perhaps clean up after the error
      &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;PRINT &lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'This is where the error handling code could go'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;;

&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;batch_end:
      &lt;/SPAN&gt;&lt;SPAN style="COLOR:green;"&gt;-- Do nothing

&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;GO &lt;/SPAN&gt;&lt;SPAN style="COLOR:green;"&gt;-- End of Batch 1

-- Batch 2
&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;PRINT &lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'This is the second batch'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;;
&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;GO &lt;/SPAN&gt;&lt;SPAN style="COLOR:green;"&gt;-- End of Batch 2
&lt;/SPAN&gt;
&lt;/CODE&gt;&lt;/PRE&gt;In any case, note that the following example does NOT do what one might imagine, though I have seen this in production code. It doesn’t work correctly because it has transaction handling but not flow control: &lt;PRE&gt;&lt;CODE&gt;&lt;SPAN style="COLOR:green;"&gt;-- Incorrect code - transactions implemented, but broken, because
-- flow control is missing:

&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;DECLARE  &lt;/SPAN&gt;&lt;SPAN style="COLOR:#434343;"&gt;@pretendError &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;INT&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;;
&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;SET &lt;/SPAN&gt;&lt;SPAN style="COLOR:#434343;"&gt;@pretendError &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;= &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;1&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;;

&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;BEGIN TRANSACTION

      INSERT INTO &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;test1 &lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;testcolumn&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;) &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;VALUES &lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'First Row'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;);

      &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;IF &lt;/SPAN&gt;&lt;SPAN style="COLOR:#434343;"&gt;@pretendError &lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;!= &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;0 &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;ROLLBACK&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;;

      &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;INSERT INTO &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;test1 &lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;testcolumn&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;) &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;VALUES &lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'Second Row'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;);

      &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;IF &lt;/SPAN&gt;&lt;SPAN style="COLOR:#434343;"&gt;@@ERROR &lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;!= &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;0 &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;ROLLBACK&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;;

      &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;INSERT INTO &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;test1 &lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;testcolumn&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;) &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;VALUES &lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'Third Row'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;);

      &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;IF &lt;/SPAN&gt;&lt;SPAN style="COLOR:#434343;"&gt;@@ERROR &lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;!= &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;0 &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;ROLLBACK&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;;

&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;COMMIT
&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;GO
&lt;/SPAN&gt;
&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;With the fake error I set near the top, a novice might think that none of the inserts succeed; in fact the second two inserts do succeed and commit, because nothing is done to stop the batch from continuing after an error, even with the ROLLBACK statements. The following example also doesn’t do what one might expect, because of the same problem:&lt;/P&gt;&lt;PRE&gt;&lt;CODE&gt;&lt;SPAN style="COLOR:green;"&gt;-- Incorrect code - transaction handing does not work
-- because RAISERROR doesn't stop the batch:
&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;DECLARE  &lt;/SPAN&gt;&lt;SPAN style="COLOR:#434343;"&gt;@pretendError &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;INT&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;;
&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;SET &lt;/SPAN&gt;&lt;SPAN style="COLOR:#434343;"&gt;@pretendError &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;= &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;1&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;;

&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;BEGIN TRANSACTION

      INSERT INTO &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;test1 &lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;testcolumn&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;) &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;VALUES &lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'First Row'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;);

      &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;IF &lt;/SPAN&gt;&lt;SPAN style="COLOR:#434343;"&gt;@pretendError &lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;!= &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;0
        &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;BEGIN
            RAISERROR &lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'Something Bad Happened'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;, &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;11&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;, &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;1&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;);
            &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;ROLLBACK&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;;
        &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;END

      INSERT INTO &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;test1 &lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;testcolumn&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;) &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;VALUES &lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'Second Row'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;);

      &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;IF &lt;/SPAN&gt;&lt;SPAN style="COLOR:#434343;"&gt;@@ERROR &lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;!= &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;0
        &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;BEGIN
            RAISERROR &lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'Something Bad Happened'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;, &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;11&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;, &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;1&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;);
            &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;ROLLBACK&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;;
        &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;END

      INSERT INTO &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;test1 &lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;testcolumn&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;) &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;VALUES &lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'Third Row'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;);

      &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;IF &lt;/SPAN&gt;&lt;SPAN style="COLOR:#434343;"&gt;@@ERROR &lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;!= &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;0
        &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;BEGIN
            RAISERROR &lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'Something Bad Happened'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;, &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;11&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;, &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;1&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;);
            &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;ROLLBACK&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;;
        &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;END

COMMIT
&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;GO
&lt;/SPAN&gt;
&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;RAISERROR() is great, but the batch will keep executing at the next statement. Erland’s article referenced above covers this quite well, so I won’t dwell on it. Suffice it to say, RETURN can be useful even in scripts:&lt;/P&gt;&lt;PRE&gt;&lt;CODE&gt;&lt;SPAN style="COLOR:green;"&gt;-- One more correct method - transaction handing
-- AND flow control implemented:
&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;DECLARE  &lt;/SPAN&gt;&lt;SPAN style="COLOR:#434343;"&gt;@pretendError &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;INT&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;;
&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;SET &lt;/SPAN&gt;&lt;SPAN style="COLOR:#434343;"&gt;@pretendError &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;= &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;1&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;;

&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;BEGIN TRANSACTION

      INSERT INTO &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;test1 &lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;testcolumn&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;) &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;VALUES &lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'First Row'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;);

      &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;IF &lt;/SPAN&gt;&lt;SPAN style="COLOR:#434343;"&gt;@pretendError &lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;!= &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;0
        &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;BEGIN
            RAISERROR &lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'Something Bad Happened'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;, &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;11&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;, &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;1&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;);
            &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;ROLLBACK&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;;
            &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;RETURN&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;;
        &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;END

      INSERT INTO &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;test1 &lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;testcolumn&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;) &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;VALUES &lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'Second Row'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;);

      &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;IF &lt;/SPAN&gt;&lt;SPAN style="COLOR:#434343;"&gt;@@ERROR &lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;!= &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;0
        &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;BEGIN
            RAISERROR &lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'Something Bad Happened'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;, &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;11&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;, &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;1&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;);
            &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;ROLLBACK&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;;
            &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;RETURN&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;;
        &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;END

      INSERT INTO &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;test1 &lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;testcolumn&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;) &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;VALUES &lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'Third Row'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;);

      &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;IF &lt;/SPAN&gt;&lt;SPAN style="COLOR:#434343;"&gt;@@ERROR &lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;!= &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;0
        &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;BEGIN
            RAISERROR &lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'Something Bad Happened'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;, &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;11&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;, &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;1&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;);
            &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;ROLLBACK&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;;
            &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;RETURN&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;;
        &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;END

COMMIT
&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;GO
&lt;/SPAN&gt;
&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;If RETURN and/or GOTO are too picky or involved for you, you can also investigate the connection setting XACT_ABORT. XACT_ABORT will rollback a transaction and abort the batch in the event of a runtime error. Problem is, it's OFF by default in Management Studio query connections. Consider this test table:&lt;/P&gt;&lt;PRE&gt;&lt;CODE&gt;&lt;SPAN style="COLOR:blue;"&gt;CREATE TABLE &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;[dbo].[TransTest]&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(
   &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;[id] [int] &lt;/SPAN&gt;&lt;SPAN style="COLOR:#434343;"&gt;IDENTITY&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;1&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;,&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;1&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;) NOT NULL,
 &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;CONSTRAINT &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;[PK_TransTest] &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;PRIMARY KEY CLUSTERED 
&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(
   &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;[id] &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;ASC
&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;)
&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;GO
&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;I can simulate runtime errors by attempting to insert into the&amp;nbsp;identity column. If XACT_ABORT is off, then a failed insert will be skipped, but&amp;nbsp;the code following will still execute:&lt;/P&gt;&lt;PRE&gt;&lt;CODE&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:green;"&gt;-- XACT_ABORT is off by default:
&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;BEGIN TRAN
   INSERT INTO &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;TransTest &lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;id&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;) &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;VALUES &lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'wrong-o'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;)
   &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;INSERT INTO &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;TransTest &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;DEFAULT VALUES
   INSERT INTO &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;TransTest &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;DEFAULT VALUES
COMMIT
&lt;/SPAN&gt;&lt;SPAN style="COLOR:green;"&gt;-- At this point we have one error AND two successful inserts AND a committed transaction

-- To halt and roll back, use xact_abort:
&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;SET &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;XACT_ABORT &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;ON
BEGIN TRAN
   INSERT INTO &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;TransTest &lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;id&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;) &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;VALUES &lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'wrong-o'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;)
   &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;INSERT INTO &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;TransTest &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;DEFAULT VALUES
   INSERT INTO &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;TransTest &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;DEFAULT VALUES
COMMIT&lt;/SPAN&gt;
&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;There is some long-standing debate about which method, GOTO or RETURN in the midst of code, is uglier and/or harder to maintain. Both are hopefully rendered obsolete by Try/Catch – a topic for a future post. But style aside, any solution is better than missing this issue altogether!&lt;/P&gt;
&lt;P&gt;So, we can exit a batch in the event of an error by either issuing a RETURN or by using GOTO to hop to the end of the batch, or with XACT_ABORT. Importantly, both those are server-side constructs and work only in the context of one batch. That is, it’s not possible to direct the server to GOTO a line in another batch, in the same script, because at the server each batch is completely independent. One is not accessible from the other. Further, we typically can’t abort a batch by calling RAISERROR() – though the SQL Server itself can and does sometimes issue batch aborting errors.&lt;/P&gt;
&lt;H4&gt;On Second Thought, Maybe RAISERROR() isn’t so Bad&lt;/H4&gt;
&lt;P&gt;That brings me to control of multiple batches. RETURN will stop the server executing a batch, but since the server does not control multiple batches issued from the client, a script will then typically resume execution at the first statement in the next batch – that is, directly after the next GO. Often I don’t want any of the remaining script to run after an error, batches or no batches. Here’s a simple example of the problem:&lt;/P&gt;&lt;PRE&gt;&lt;CODE&gt;&lt;SPAN style="COLOR:green;"&gt;-- Batch 1
&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;DECLARE  &lt;/SPAN&gt;&lt;SPAN style="COLOR:#434343;"&gt;@pretendError &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;INT&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;;
&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;SET &lt;/SPAN&gt;&lt;SPAN style="COLOR:#434343;"&gt;@pretendError &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;= &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;1&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;;

&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;PRINT &lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'This is the first statement in the first batch'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;;

&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;IF &lt;/SPAN&gt;&lt;SPAN style="COLOR:#434343;"&gt;@pretendError &lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;!= &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;0
  &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;RETURN&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;; &lt;/SPAN&gt;&lt;SPAN style="COLOR:green;"&gt;-- This will end batch 1, but batch 2 will still run!

&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;PRINT &lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'This second statement in the first batch will not execute'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;;
&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;GO &lt;/SPAN&gt;&lt;SPAN style="COLOR:green;"&gt;-- End of Batch 1

-- Batch 2
&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;PRINT &lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'I don''t want this to run, but it will'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;;
&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;GO &lt;/SPAN&gt;&lt;SPAN style="COLOR:green;"&gt;-- End of Batch 2
&lt;/SPAN&gt;
&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;The trick is that control of more than one batch – that is, making an error in one batch prevent the following batches from running – is a client-side problem, not a server-side problem. For that, the best solution I know of is SQLCMD. In SQLCMD mode, it’s possible to have the client note that an error was raised in a batch and then stop running the script instead of continuing with the next batch. Here’s the same example, tweaked a little to stop the entire script on error:&lt;/P&gt;&lt;PRE&gt;&lt;CODE&gt;&lt;SPAN style="COLOR:gray;"&gt;:&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;ON &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;Error &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;EXIT

&lt;/SPAN&gt;&lt;SPAN style="COLOR:green;"&gt;-- Batch 1
&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;DECLARE  &lt;/SPAN&gt;&lt;SPAN style="COLOR:#434343;"&gt;@pretendError &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;INT&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;;
&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;SET &lt;/SPAN&gt;&lt;SPAN style="COLOR:#434343;"&gt;@pretendError &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;= &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;1&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;;

&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;PRINT &lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'This is the first statement in the first batch'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;;

&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;IF &lt;/SPAN&gt;&lt;SPAN style="COLOR:#434343;"&gt;@pretendError &lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;!= &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;0
  &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;BEGIN
      &lt;/SPAN&gt;&lt;SPAN style="COLOR:green;"&gt;-- This RAISERROR() now signals SQLCMD
      -- to stop the whole script:
    &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;RAISERROR &lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'Something Bad Happened'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;, &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;11&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;, &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;1&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;)
    &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;RETURN&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;; &lt;/SPAN&gt;&lt;SPAN style="COLOR:green;"&gt;-- This ends Batch 1
  &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;END

PRINT &lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'This second statement in the first batch will not execute'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;;

&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;GO &lt;/SPAN&gt;&lt;SPAN style="COLOR:green;"&gt;-- End of Batch 1

-- Batch 2
&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;PRINT &lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'This is the second batch, and we want to prevent it from running'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;;
&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;GO &lt;/SPAN&gt;&lt;SPAN style="COLOR:green;"&gt;-- End of Batch 2
&lt;/SPAN&gt;
&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;Output is:&lt;/P&gt;&lt;PRE&gt;&lt;CODE&gt;This is the first statement in the first batch
&lt;SPAN style="COLOR:red;"&gt;Msg 50000, Level 11, State 1, Line 9
Something Bad Happened&lt;/SPAN&gt;
** An error was encountered during execution of batch. Exiting.
&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;We need to do a total of four things to get this behavior: 
&lt;UL&gt;
&lt;LI&gt;Execute in SQLCMD mode in Management Studio (or use SQLCMD scripting in some other way)&lt;/LI&gt;
&lt;LI&gt;Add the statement :On Error exit to the top of the script, so that raised errors will direct the client to stop the whole script, not just move on to the next batch. Raise errors with severity 11 through 19, so that the error is not treated as purely informational. I generally just use 11. B.O.L. seems to be wrong about this, based on my testing. Note that there is also special treatment for Error State 127 in some environments.&lt;/LI&gt;
&lt;LI&gt;Still implement RETURN or GOTO (or Try/Catch) flow control inside each batch to stop the batch itself. If this is not present, then the server is NOT directed to stop the current batch, even though the client will not run the next batch. What happens if the batch flow control is missing is that the server will run all the remaining statements after the error, in the current batch, and then the client will stop the script.&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;All together, this will both direct the server to stop mid-batch in case of an error, and will direct the client to “notice” that an error was raised with RAISERROR() – severity above 10. SQLCMD will then cause the remainder of the script to halt. All this needs to happen irrespective of BEGIN TRANSACTION, ROLLBACK, and COMMIT, which are not flow-control structures.&lt;/P&gt;
&lt;H4&gt;All Together&lt;/H4&gt;
&lt;P&gt;Here’s a complete, if contrived, example:&lt;/P&gt;&lt;PRE&gt;&lt;CODE&gt;&lt;SPAN style="COLOR:gray;"&gt;:&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;ON &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;Error &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;EXIT

&lt;/SPAN&gt;&lt;SPAN style="COLOR:green;"&gt;-- Batch 1
&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;DECLARE  &lt;/SPAN&gt;&lt;SPAN style="COLOR:#434343;"&gt;@pretendError &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;INT&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;;

&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;SET &lt;/SPAN&gt;&lt;SPAN style="COLOR:#434343;"&gt;@pretendError &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;= &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;1&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;;

&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;BEGIN TRANSACTION

      INSERT INTO &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;test1 &lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;testcolumn&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;) &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;VALUES &lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'First Row'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;);

      &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;IF &lt;/SPAN&gt;&lt;SPAN style="COLOR:#434343;"&gt;@pretendError &lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;!= &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;0
        &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;BEGIN
            RAISERROR &lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'Something Bad Happened'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;, &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;11&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;, &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;1&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;);
            &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;ROLLBACK&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;;
            &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;RETURN&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;;
        &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;END

      INSERT INTO &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;test1 &lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;testcolumn&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;) &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;VALUES &lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'Second Row'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;);

      &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;IF &lt;/SPAN&gt;&lt;SPAN style="COLOR:#434343;"&gt;@@ERROR &lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;!= &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;0
        &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;BEGIN
            RAISERROR &lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'Something Bad Happened'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;, &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;11&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;, &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;1&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;);
            &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;ROLLBACK&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;;
            &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;RETURN&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;;
        &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;END

      INSERT INTO &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;test1 &lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;testcolumn&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;) &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;VALUES &lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'Third Row'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;);

      &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;IF &lt;/SPAN&gt;&lt;SPAN style="COLOR:#434343;"&gt;@@ERROR &lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;!= &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;0
        &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;BEGIN
            RAISERROR &lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'Something Bad Happened'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;, &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;11&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;, &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;1&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;);
            &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;ROLLBACK&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;;
            &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;RETURN&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;;
        &lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;END

COMMIT

&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;GO &lt;/SPAN&gt;&lt;SPAN style="COLOR:green;"&gt;-- End of Batch 1

-- Batch 2 (Should NOT execute in case of failure in Batch 1)
&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;PRINT &lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'This second batch should not run'
&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;GO &lt;/SPAN&gt;&lt;SPAN style="COLOR:green;"&gt;-- End of Batch 2
&lt;/SPAN&gt;
&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;Breaking this down: when the example runs, in SQLCMD mode, the first batch will not insert any rows – because of the combination of BEGIN TRANSACTION, ROLLBACK, and, importantly, RETURN. Without the RETURN statements, the first insert statement would be rolled back, but the next two would succeed as the batch continues to execute even after the error was detected. With the RETURN statements, the server is directed to stop immediately, with the effect that control seems to “skip down” to the next line after the GO statement. That’s an imperfect analogy, but that is roughly the effect from the client side.&lt;/P&gt;
&lt;P&gt;Next, the combination of setting :On Error exit AND Raiserror() statements with severity 11 will cause SQLCMD to also stop execution of the script, which would otherwise continue at the next batch. This means that Batch 2 will be prevented from executing after there is an error in Batch 1.&lt;/P&gt;
&lt;P&gt;This example is simplified to illustrate those main points, and obviously the error condition is faked, so real production code might not look exactly like this. You may want to add still more logic such as capturing the value of @@error in a local variable, or checking @@trancount, two additional techniques that are covered well elsewhere. The main take-aways are that transaction handling and flow control are separate problems, and both need to be managed explicitly. Flow control inside batches and flow control between batches are also separate problems, each of which has a slightly different solution.&lt;/P&gt;
&lt;P&gt;[Shout out to &lt;A href="http://www.simple-talk.com/prettifier/"&gt;Simple Talk&lt;/A&gt; and to &lt;A href="http://thehobt.blogspot.com/2009/01/formatting-code-for-blogger.html"&gt;Aaron Alton&lt;/A&gt; for a code beautifier that works for a blog noob like me.]&lt;/P&gt;&lt;/SPAN&gt;&lt;img src="http://www2.sqlblog.com/aggbug.aspx?PostID=15471" width="1" height="1"&gt;</description><category domain="http://www2.sqlblog.com/blogs/merrill_aldrich/archive/tags/errors/default.aspx">errors</category><category domain="http://www2.sqlblog.com/blogs/merrill_aldrich/archive/tags/flow+control/default.aspx">flow control</category><category domain="http://www2.sqlblog.com/blogs/merrill_aldrich/archive/tags/transactions/default.aspx">transactions</category></item></channel></rss>