{"id":1941,"date":"2015-01-26T00:00:00","date_gmt":"2015-01-26T00:00:00","guid":{"rendered":"https:\/\/test.simple-talk.com\/uncategorized\/questions-about-t-sql-control-of-flow-language-you-were-too-shy-to-ask\/"},"modified":"2021-09-29T16:21:31","modified_gmt":"2021-09-29T16:21:31","slug":"questions-about-t-sql-control-of-flow-language-you-were-too-shy-to-ask","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/databases\/sql-server\/t-sql-programming-sql-server\/questions-about-t-sql-control-of-flow-language-you-were-too-shy-to-ask\/","title":{"rendered":"Questions About T-SQL Control-of-Flow Language You Were Too Shy to Ask"},"content":{"rendered":"<div id=\"pretty\">\n<ol>\n<li><a href=\"#first\">&#8220;Do I always need to use a BEGIN&#8230;END statement block within an IF statement?&#8221;<\/a><\/li>\n<li><a href=\"#second\">&#8220;When should I include an ELSE clause within an IF statement?&#8221;<\/a><\/li>\n<li><a href=\"#third\">How do I nest IF and IF&#8230;ELSE statements, if it&#8217;s even possible?&#8221;<\/a><\/li>\n<li><a href=\"#fourth\">&#8220;Is it possible to terminate a procedures execution from within an IF statement?&#8221;<\/a><\/li>\n<li><a href=\"#fifth\">&#8220;Which is better to use, a CASE expression or an IF (or IF&#8230;ELSE) statement?&#8221;<\/a><\/li>\n<li><a href=\"#sixth\">&#8220;Can I use control-of-flow language to do an upsert in SQL Server?&#8221;<\/a><\/li>\n<li><a href=\"#seventh\">&#8220;I don&#8217;t get how a WHILE loop works. Can you help make sense of what&#8217;s going on here?&#8221;<\/a><\/li>\n<li><a href=\"#eighth\">&#8220;How do I add a pause or wait time to my T-SQL in order to delay execution?&#8221;<\/a><\/li>\n<li><a href=\"#ninth\">&#8220;Is it possible to skip from one section of your T-SQL code to another?&#8221;<\/a><\/li>\n<li><a href=\"#tenth\">&#8220;What&#8217;s the simplest way to incorporate error handling into my stored procedures?&#8221;<\/a><\/li>\n<\/ol>\n<h3 id=\"first\">&#8220;Do I always need to use a  <code>BEGIN...END<\/code>  statement block within an IF statement?&#8221;<\/h3>\n<p>You need to include the <b><code>BEGIN...END<\/code><\/b> block only if you want to  associate more than one T-SQL statement with the <b> <code>IF<\/code><\/b> condition. The condition is a Boolean  expression within the <b><code>IF<\/code><\/b> clause that directs statement  execution control flow. The query engine evaluates the condition and, if it evaluates to  <b><code>TRUE<\/code><\/b>,  runs the statement immediately following the <b> <code>IF<\/code><\/b> clause. Otherwise, the query engine  skips ahead to the appropriate next statement.<\/p>\n<p>If you want that condition to apply to multiple statements, you must treat them as a  statement block by enclosing them within the <b> <code>BEGIN<\/code><\/b> and  <b><code>END<\/code><\/b>  keywords. Let&#8217;s look at a few <b><code>IF<\/code><\/b> statements in action to better  understand how the execution flow works. The following stored procedure includes the logic necessary to check whether  the <b><code>@CustID<\/code><\/b>  variable is <b><code>NULL<\/code><\/b>:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">IF OBJECT_ID('dbo.GetCustomerInfo', 'p') IS NOT NULL\nDROP PROCEDURE dbo.GetCustomerInfo;\nGO\n\nCREATE PROCEDURE dbo.GetCustomerInfo\n&#160; (@CustID INT = NULL)\nAS\nIF @CustID IS NULL\n&#160; PRINT 'You must provide a customer ID.';\nSELECT FirstName, LastName, City, StateProvinceName\nFROM Sales.vIndividualCustomer\nWHERE BusinessEntityID = @CustID;\nGO\n\n<\/pre>\n<p>The <b> <code>IF<\/code><\/b> expression verifies whether the variable  value is <b><code>NULL<\/code><\/b>. If it is, the expression  evaluates to <b><code>TRUE<\/code><\/b>, and the query processor  executes the <b><code>PRINT<\/code><\/b> statement. Otherwise, the  processor skips the <b><code>PRINT<\/code><\/b>  statement and jumps to the <b><code>SELECT<\/code><\/b> statement. We can verify  this by calling the procedure and passing in a valid <b> <code>BusinessEntityID<\/code><\/b> value:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">EXEC GetCustomerInfo 1700;<\/pre>\n<p>In this case, the <b><code>EXECUTE<\/code><\/b> statement (and subsequently  the procedure) returns the results shown in the following table:<\/p>\n<table class=\"MsoTableGrid\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>FirstName<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>LastName<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>City<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>StateProvinceName<\/b><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Rebecca<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Robinson<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Seaford<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Victoria<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Next let&#8217;s call the procedure without specifying a  <b><code>BusinessEntityID<\/code><\/b>  value:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">EXEC GetCustomerInfo;<\/pre>\n<p>Because the <b><code>@CustID<\/code><\/b> value is  <b><code>NULL<\/code><\/b>,  the query engine executes the <b> <code>PRINT<\/code><\/b> statement and returns the following  message, along with an empty result set for the customer data:<\/p>\n<pre>You must provide a customer ID.<\/pre>\n<p>So far, this is all fairly straightforward, but now suppose our procedure includes additional  statements that should run if the <b> <code>IF<\/code><\/b> expression evaluates to  <b><code>TRUE<\/code><\/b>:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">IF OBJECT_ID('dbo.GetCustomerInfo', 'p') IS NOT NULL\nDROP PROCEDURE dbo.GetCustomerInfo;\nGO\n\nCREATE PROCEDURE dbo.GetCustomerInfo\n&#160; (@CustID INT = NULL)\nAS\nIF @CustID IS NULL\n&#160; PRINT 'You must provide a customer ID.';\n&#160; PRINT 'Contact the sales rep for your region:';\n&#160; SELECT FirstName, LastName, TerritoryName, EmailAddress\n&#160; FROM Sales.vSalesPerson\n&#160; WHERE JobTitle = 'Sales Representative';\nSELECT FirstName, LastName, City, StateProvinceName\nFROM Sales.vIndividualCustomer\nWHERE BusinessEntityID = @CustID;\nGO\n<\/pre>\n<p>This time around, we want to run two <b> <code>PRINT<\/code><\/b> statements as well as a  <b><code>SELECT<\/code><\/b>  statement that returns a list of sales representations. When we call the stored procedure without specifying a  <a id=\"OLE_LINK2\"><\/a><a id=\"OLE_LINK1\"> <b><code>BusinessEntityID<\/code><\/b> value<\/a>,  we receive the two messages, as expected:<\/p>\n<pre>You must provide a customer ID.\nContact the sales rep for your region:\n\n<\/pre>\n<p>In addition, we receive the following information about the sales reps:<\/p>\n<table class=\"MsoTableGrid\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>FirstName<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>LastName<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>TerritoryName<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>EmailAddress<\/b><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Michael<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Blythe<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Northeast<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">michael9@adventure-works.com<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Linda<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Mitchell<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Southwest<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">linda3@adventure-works.com<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Jillian<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Carson<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Central<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">jillian0@adventure-works.com<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Garrett<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Vargas<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Canada<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">garrett1@adventure-works.com<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Tsvi<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Reiter<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Southeast<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">tsvi0@adventure-works.com<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Pamela<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Ansman-Wolfe<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Northwest<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">pamela0@adventure-works.com<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Shu<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Ito<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Southwest<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">shu0@adventure-works.com<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Jos&#233;<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Saraiva<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Canada<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">jos&#233;1@adventure-works.com<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">David<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Campbell<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Northwest<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">david8@adventure-works.com<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Tete<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Mensa-Annan<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Northwest<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">tete0@adventure-works.com<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Lynn<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Tsoflias<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Australia<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">lynn0@adventure-works.com<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Rachel<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Valdez<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Germany<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">rachel0@adventure-works.com<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Jae<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Pak<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">United Kingdom<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">jae0@adventure-works.com<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Ranjit<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Varkey Chudukatil<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">France<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">ranjit0@adventure-works.com<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Plus, we receive an empty result set for the customer information. Now let&#8217;s look what  happens when we call the procedure and pass in a correct <b> <code>BusinessEntityID<\/code><\/b> value:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">EXEC GetCustomerInfo 1700;<\/pre>\n<p>As expected, we won&#8217;t receive the message about providing a customer ID, but we&#8217;ll still  receive the message about contacting a sales rep as well as the result set that contains the sales rep information. Only  then will we receive the result set that contains the customer information, which is the only data we really wanted.<\/p>\n<p>The problem, of course, is that the query engine associates only the first  <b><code>PRINT<\/code><\/b>  statement with the <b><code>IF<\/code><\/b>  condition. If we want to associate additional statements, we must enclose all the statements within a  <b><code>BEGIN...END<\/code><\/b>  block:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">IF OBJECT_ID('dbo.GetCustomerInfo', 'p') IS NOT NULL\nDROP PROCEDURE dbo.GetCustomerInfo;\nGO\n\nCREATE PROCEDURE dbo.GetCustomerInfo\n&#160; (@CustID INT = NULL)\nAS\nIF @CustID IS NULL\n&#160; BEGIN\n&#160;&#160;&#160; PRINT 'You must provide a customer ID.';\n&#160;&#160;&#160; PRINT 'Contact the sales rep for your region:';\n&#160;&#160;&#160; SELECT FirstName, LastName, TerritoryName, EmailAddress\n&#160;&#160;&#160; FROM Sales.vSalesPerson\n&#160;&#160;&#160; WHERE JobTitle = 'Sales Representative';\n&#160; END\nSELECT FirstName, LastName, City, StateProvinceName\nFROM Sales.vIndividualCustomer\nWHERE BusinessEntityID = @CustID;\nGO\n<\/pre>\n<p>If we now call the stored procedure without specifying a customer ID, we&#8217;ll receive both  messages, a result set that contains the sales rep information, and an empty result set for the customer information.  However, if we do provide a valid customer ID, the query will return only the customer information.<\/p>\n<p>One other note about using <b><code>BEGIN...END<\/code><\/b>. Many developers will  enclose even a single statement in <b> <code>BEGIN...END<\/code><\/b> because it makes the code more  readable and makes it less likely that another developer will introduce an error by adding a statement without the  block. In general, it doesn&#8217;t hurt to include the <b> <code>BEGIN...END<\/code><\/b> block even if you don&#8217;t need it  in a particular case. In the long run it could save everyone a lot of trouble.<\/p>\n<h3 id=\"second\">&#8220;When should I include an  <code>ELSE<\/code>  clause within an  IF statement?&#8221;<\/h3>\n<p>You can add an <b><code>ELSE<\/code><\/b> clause to any  <b><code>IF<\/code><\/b>  construction when you want to run specific statements in the event the Boolean expression (the  <b><code>IF<\/code><\/b>  condition) evaluates to <b>FALSE<\/b>. You specify the  <b><code>ELSE<\/code><\/b>  clause after the <b><code>IF<\/code><\/b>  statement block. An <b><code>ELSE<\/code><\/b>  clause let&#8217;s you better control your code&#8217;s logic and provides a mechanism for running statements outside of the  <b><code>IF...ELSE<\/code><\/b>  structure.<\/p>\n<p>Let&#8217;s again rewrite our stored procedure. This time, we&#8217;ll put the logic for retrieving the  customer information in an <b><code> ELSE<\/code><\/b> clause and then add a final <b><code>PRINT<\/code><\/b> statement after the  <b><code>IF...ELSE<\/code><\/b>  block:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">IF OBJECT_ID('dbo.GetCustomerInfo', 'p') IS NOT NULL\nDROP PROCEDURE dbo.GetCustomerInfo;\nGO\n\nCREATE PROCEDURE dbo.GetCustomerInfo\n&#160; (@CustID INT = NULL)\nAS\nIF @CustID IS NULL\n&#160; BEGIN\n&#160;&#160;&#160; PRINT 'You must provide a customer ID.';\n&#160;&#160;&#160; PRINT 'Contact the sales rep for your region:';\n&#160;&#160;&#160; SELECT FirstName, LastName, TerritoryName, EmailAddress\n&#160;&#160;&#160; FROM Sales.vSalesPerson\n&#160;&#160;&#160; WHERE JobTitle = 'Sales Representative';\n&#160; END\nELSE\n&#160; SELECT FirstName, LastName, City, StateProvinceName\n&#160; FROM Sales.vIndividualCustomer\n&#160; WHERE BusinessEntityID = @CustID;\nPRINT 'AdventureWorks Bicycles;&#160; ' \n&#160; + CONVERT(VARCHAR(30), GETDATE(), 109);\nGO\n<\/pre>\n<p>As in the previous example, if the <b> <code>IF<\/code><\/b> expression evaluates to  <b><code>TRUE<\/code><\/b>,  the statements within the <b><code> BEGIN...END<\/code><\/b> block will run. However, this time around, if the expression evaluates to  <b><code>FALSE<\/code><\/b>,  the <b><code>SELECT<\/code><\/b>  statement in the <b><code>ELSE<\/code><\/b>  clause will run. This approach let&#8217;s us be more precise with our logic while at the same time add other statements that  are unrelated to the <b><code> IF...ELSE<\/code><\/b> statements.<\/p>\n<p>In this case, we&#8217;ve added a final <b> <code>PRINT<\/code><\/b> statement, which will run regardless  of what statements run within the <b> <code>IF...ELSE<\/code><\/b> blocks. That means, when we call  the function and pass in a valid customer ID, the procedure will return only the customer data along with the following  information:<\/p>\n<pre>AdventureWorks Bicycles; &#160;Jan 18 2015&#160; 9:54:16:237AM<\/pre>\n<p>However, if we call the procedure without specifying a customer ID, it will return the  original two statements about providing a customer ID and contacting the sales rep as well as return the result set  containing the sales rep information. The results will also include the statement about AdventureWorks Bicycles, but  will not include the empty result set for the customer information. Because we&#8217;ve added the  <b><code>ELSE<\/code><\/b> clause, the clause&#8217;s  <b><code>SELECT<\/code><\/b>  statement is no longer executed when the <b> <code>IF<\/code><\/b> expression evaluates to  <b><code>TRUE<\/code><\/b>.  The query engine executes the <b> <code>ELSE<\/code><\/b> clause <i>only<\/i> if the related <b> <code>IF<\/code><\/b> expression evaluates to  <b><code>FALSE<\/code><\/b>.<\/p>\n<h3 id=\"third\">&#8220;How do I nest  <code>IF<\/code>  and  IF&#8230;ELSE statements,  if it&#8217;s even possible?&#8221;<\/h3>\n<p>Yes, it is possible to nest your <b> <code>IF<\/code><\/b> and  <b><code>IF...ELSE<\/code><\/b>  statements, and you can do so to whatever degree necessary and practical. The primary limitation on nesting is available  memory. <\/p>\n<p>To demonstrate how nesting works, let&#8217;s return to the  <b><code>GetCustomerInfo<\/code><\/b>  stored procedure. As you&#8217;ll recall from the last couples examples, we used the  <b><code>IF<\/code><\/b>  conditions to determine which statements to run based on the value of the <b> <code>@CustID<\/code><\/b> variable. If the value was  <b><code>NULL<\/code><\/b>, we ran one set of statements.  If the value was an integer, we ran a different statement. However, what if the value is a valid integer but not a valid  customer ID?<\/p>\n<p>To address this situation, we can add logic to our T-SQL code that handles the additional  scenario. One way to do this is to nest an <b> <code>IF...ELSE<\/code><\/b> statement within the outer  <b><code>ELSE<\/code><\/b>  clause, as shown in the following example:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">IF OBJECT_ID('dbo.GetCustomerInfo', 'p') IS NOT NULL\nDROP PROCEDURE dbo.GetCustomerInfo;\nGO\n\nCREATE PROCEDURE dbo.GetCustomerInfo\n&#160; (@CustID INT = NULL)\nAS\nIF @CustID IS NULL\n&#160; BEGIN\n&#160;&#160;&#160; PRINT 'You must provide a customer ID.';\n&#160;&#160;&#160; PRINT 'Contact the sales rep for your region:';\n&#160;&#160;&#160; SELECT FirstName, LastName, TerritoryName, EmailAddress\n&#160;&#160;&#160; FROM Sales.vSalesPerson\n&#160;&#160;&#160; WHERE JobTitle = 'Sales Representative';\n&#160; END\nELSE\n&#160; BEGIN\n&#160;&#160;&#160; IF EXISTS(SELECT * FROM Sales.vIndividualCustomer\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; WHERE BusinessEntityID = @CustID)\n&#160;&#160;&#160;&#160;&#160; SELECT FirstName, LastName, City, StateProvinceName\n&#160;&#160;&#160;&#160;&#160; FROM Sales.vIndividualCustomer\n&#160;&#160;&#160;&#160;&#160; WHERE BusinessEntityID = @CustID;\n&#160;&#160;&#160; ELSE\n&#160;&#160;&#160;&#160;&#160; PRINT 'No record matches the customer ID ' + \n&#160;&#160;&#160;&#160;&#160;&#160;&#160; CAST(@CustID AS VARCHAR(10)) + '.'\n&#160; END\nGO\n<\/pre>\n<p>Notice we use the <b><code>EXISTS<\/code><\/b> function to check whether  the ID exists. As a result, the <b> <code>SELECT<\/code><\/b> statement in the original  <b><code>ELSE<\/code><\/b> clause will run only if the <b><code>@CustID<\/code><\/b> value matches a value in  underlying table. For example, suppose we pass in the value <b> <code>101<\/code><\/b> when we call the stored procedure. If  there is no match, it will return only the following message:<\/p>\n<pre>No record matches the customer ID 101.<\/pre>\n<p>Because the first <b><code>IF<\/code><\/b> expression evaluated to  <b><code>FALSE<\/code><\/b>,  the <b><code>ELSE<\/code><\/b>  clause kicked in. However, the nested <b><code>IF<\/code><\/b> expression in the outer  <b><code>ELSE<\/code><\/b>  clause also evaluated to <b><code> FALSE<\/code><\/b>, so the query engine jumped to the nested  <b><code>ELSE<\/code><\/b>  clause and executed that <b><code> PRINT<\/code><\/b> statement.<\/p>\n<p>Clearly, the ability to nest <b> <code>IF...ELSE<\/code><\/b> statements provides a powerful  mechanism for adding complex logic to our stored procedures and batches. Be wary of overdoing it, however. Memory is not  the only issue to keep in mind. Too much conditional logic can result in the query optimizer having to continuously  re-cache the plan, which can severely impact performance. Complex logic is often better suited to the application layer,  letting each stored procedure focus on a single task.<\/p>\n<h3 id=\"fourth\">&#8220;Is it possible to terminate a procedure&#8217;s execution  from within an  IF  statement?&#8221;<\/h3>\n<p>Yes, it is possible, and often it&#8217;s a good strategy to do so. Why cause the query engine to  do any more work than necessary? The sooner you can pull out, the better. And T-SQL supports a great tool for  unconditionally exiting a batch, statement block, or stored procedure: the  <b><code>RETURN<\/code><\/b>  statement.<\/p>\n<p>You can add a <b><code>RETURN<\/code><\/b> statement to whatever part  of the T-SQL logic that you want to end when and if you reach that part of the code. Let&#8217;s return to a basic version of  our <b><code>GetCustomerInfo<\/code><\/b>  stored procedure:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">IF OBJECT_ID('dbo.GetCustomerInfo', 'p') IS NOT NULL\nDROP PROCEDURE dbo.GetCustomerInfo;\nGO\n\nCREATE PROCEDURE dbo.GetCustomerInfo\n&#160; (@CustID INT = NULL)\nAS\nIF @CustID IS NULL\n&#160; BEGIN\n&#160;&#160;&#160; PRINT 'You must provide a customer ID.';\n&#160;&#160;&#160; PRINT 'Contact the sales rep for your region:';\n&#160;&#160;&#160; SELECT FirstName, LastName, TerritoryName, EmailAddress\n&#160;&#160;&#160; FROM Sales.vSalesPerson\n&#160;&#160;&#160; WHERE JobTitle = 'Sales Representative';\n&#160; END\nSELECT FirstName, LastName, City, StateProvinceName\nFROM Sales.vIndividualCustomer\nWHERE BusinessEntityID = @CustID;\nGO\n<\/pre>\n<p>Even if the <b><code>IF<\/code><\/b> expression evaluates to  <b><code>TRUE<\/code><\/b>,  the final <b><code>SELECT<\/code><\/b>  statement runs and with it comes an empty result set. One way to avoid this, as we saw earlier, is to add an  <b><code>ELSE<\/code><\/b>  clause. However, we can also terminate the stored procedure after the <b> <code>IF<\/code><\/b> statement block runs by adding the <b><code>RETURN<\/code><\/b> statement:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">IF OBJECT_ID('dbo.GetCustomerInfo', 'p') IS NOT NULL\nDROP PROCEDURE dbo.GetCustomerInfo;\nGO\n\nCREATE PROCEDURE dbo.GetCustomerInfo\n&#160; (@CustID INT = NULL)\nAS\nIF @CustID IS NULL\n&#160; BEGIN\n&#160;&#160;&#160; PRINT 'You must provide a customer ID.';\n&#160;&#160;&#160; PRINT 'Contact the sales rep for your region:';\n&#160;&#160;&#160; SELECT FirstName, LastName, TerritoryName, EmailAddress\n&#160;&#160;&#160; FROM Sales.vSalesPerson\n&#160;&#160;&#160; WHERE JobTitle = 'Sales Representative';\n&#160;&#160;&#160; RETURN;\n&#160; END\nSELECT FirstName, LastName, City, StateProvinceName\nFROM Sales.vIndividualCustomer\nWHERE BusinessEntityID = @CustID;\nGO\n<\/pre>\n<p>If the <b> <code>IF<\/code><\/b> expression evaluates to  <b><code>TRUE<\/code><\/b>  all the statements within the <b> <code>BEGIN...END<\/code><\/b> block will run, just like before;  however, when the query engine hits <b> <code>RETURN<\/code><\/b>, it will immediately stop processing  the stored procedure and exit. No other statements will be executed. <\/p>\n<p>Although this might not always be the strategy you want to employ for controlling your code&#8217;s  logical flow, when it is, the <b> <code>RETURN<\/code><\/b> statement is easy to implement and  can be used anywhere in your code that makes sense. For example, the following procedure definition also includes  <b><code>RETURN<\/code><\/b>  in the nested <b><code>IF<\/code><\/b>  statement:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">IF OBJECT_ID('dbo.GetCustomerInfo', 'p') IS NOT NULL\nDROP PROCEDURE dbo.GetCustomerInfo;\nGO\n\nCREATE PROCEDURE dbo.GetCustomerInfo\n&#160; (@CustID INT = NULL)\nAS\nIF @CustID IS NULL\n&#160; BEGIN\n&#160;&#160;&#160; PRINT 'You must provide a customer ID.';\n&#160;&#160;&#160; PRINT 'Contact the sales rep for your region:';\n&#160;&#160;&#160; SELECT FirstName, LastName, TerritoryName, EmailAddress\n&#160;&#160;&#160; FROM Sales.vSalesPerson\n&#160;&#160;&#160; WHERE JobTitle = 'Sales Representative';\n&#160;&#160;&#160; RETURN;\n&#160; END\nELSE\n&#160; BEGIN\n&#160;&#160;&#160; IF EXISTS(SELECT * FROM Sales.vIndividualCustomer\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; WHERE BusinessEntityID = @CustID)\n&#160;&#160;&#160;&#160;&#160; BEGIN\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; SELECT FirstName, LastName, City, StateProvinceName\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; FROM Sales.vIndividualCustomer\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; WHERE BusinessEntityID = @CustID;\n&#160;&#160;&#160; &#160;&#160;&#160;&#160;RETURN;\n&#160;&#160;&#160;&#160;&#160; END\n&#160;&#160;&#160; ELSE\n&#160;&#160;&#160;&#160;&#160; PRINT 'No record matches the customer ID ' + \n&#160;&#160;&#160;&#160;&#160;&#160;&#160; CAST(@CustID AS VARCHAR(10)) + '.'\n&#160; END\nGO\n<\/pre>\n<p>As before, the query engine terminates the procedure whenever it encounters  <b><code>RETURN<\/code><\/b>  and does not run any more statements. <\/p>\n<h3 id=\"fifth\">&#8220;Which is better to use, a  CASE expression or an  IF (or  IF&#8230;ELSE)  statement?&#8221;<\/h3>\n<p>This question comes up often, in part because Microsoft documentation used to group  <b><code>CASE<\/code><\/b> in with its control-of-flow  language elements. But that has changed because <b> <code>CASE<\/code><\/b> is not a control-of-flow language  element, but rather a method for evaluating individual expressions. <\/p>\n<p>So it&#8217;s not quite fair to compare <b> <code>IF<\/code><\/b> and  <b><code>CASE<\/code><\/b>.  They serve different purposes and perform different types of operations. The  <b><code>IF<\/code><\/b>  statement controls the flow of your code&#8217;s logic; whereas, <b> <code>CASE<\/code><\/b> is used as part of an expression to  evaluate a particular value. One way to think of this is it that <b> <code>IF<\/code><\/b> works at the statement level and  <b><code>CASE<\/code><\/b>  works at the value level, usually within a <b><code>SELECT<\/code><\/b> clause or  <b><code>WHERE<\/code><\/b>  clause. The <b><code>CASE<\/code><\/b>  expression evaluates a set of conditions sequentially and stops when one of the conditions evaluates to  <b><code>TRUE<\/code><\/b>.  With an <b><code>IF<\/code><\/b>  or <b><code>IF...ELSE<\/code><\/b>  statement, you can better control which elements get executed and in what order that execution occurs.<\/p>\n<p>That said, the two can sometimes be used to achieve the same results. For example, the  following T-SQL code declares a variable and uses an <b> <code>IF<\/code><\/b> statement to verify it&#8217;s value:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">DECLARE @a VARCHAR(30) = 'one'\n\nIF @a = 'one'\n&#160; BEGIN\n&#160;&#160;&#160; PRINT 'The variable value is 1.';\n&#160;&#160;&#160; RETURN;\n&#160; END\nIF @a = 'two'\n&#160; BEGIN\n&#160;&#160;&#160; PRINT 'The variable value is 2.';\n&#160;&#160;&#160; RETURN;\n&#160; END\nIF @a = 'three'\n&#160; BEGIN\n&#160;&#160;&#160; PRINT 'The variable value is 3.';\n&#160;&#160;&#160; RETURN;\n&#160; END\nIF @a = 'four'\n&#160; BEGIN\n&#160;&#160;&#160; PRINT 'The variable value is 4.';\n&#160;&#160;&#160; RETURN;\n&#160; END\nIF @a NOT IN ('one', 'two', 'three', 'four')\n&#160; BEGIN\n&#160;&#160;&#160; PRINT 'The variable value is not 1-4.';\n&#160;&#160;&#160; RETURN;\n&#160; END\n<\/pre>\n<p> Each <b> <code>IF<\/code><\/b> condition is evaluated until one  evaluates to <b><code>TRUE<\/code><\/b>.  The query engine will run the associated <b><code>PRINT<\/code><\/b> statement and  <b><code>RETURN<\/code><\/b>  statement, thus ending execution. But we can achieve the same results by creating a  <b><code>CASE<\/code><\/b>  expression within a <b><code>SELECT<\/code><\/b>  clause:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">DECLARE @b VARCHAR(30) = 'two'\n\nSELECT @b = \n&#160; CASE \n&#160;&#160;&#160; WHEN @b = 'one' THEN 'The variable value is 1.'\n&#160;&#160;&#160; WHEN @b = 'two' THEN 'The variable value is 2.'\n&#160;&#160;&#160; WHEN @b = 'three' THEN 'The variable value is 3.'\n&#160;&#160;&#160; WHEN @b = 'four' THEN 'The variable value is 4.'\n&#160; ELSE 'The variable value is not 1-4.'\n&#160; END;\nPRINT @b;\n\n<\/pre>\n<p>Once again, the query engine starts by evaluating each condition, but stops when it reaches  the condition that evaluates to <b> <code>TRUE<\/code><\/b>. Even with this simple example, you  can see how much easier it is to create a <b> <code>CASE<\/code><\/b> expression. If you can use  <b><code>CASE<\/code><\/b>,  that&#8217;s a good way to go. But if you need to control the flow of the statement logic, you should use  <b><code>IF<\/code><\/b>  or another control-of-flow language construct. A <b><code>CASE<\/code><\/b> expression is great for doing  the job it was meant for, but it&#8217;s not meant to control statement execution.<\/p>\n<p>Rather than comparing whether <b> <code>CASE<\/code><\/b> is better than  <b><code>IF<\/code><\/b>,  or vice versa, think in terms of picking the right tool for the right job. Usually, you&#8217;ll want to use  <b><code>CASE<\/code><\/b>  to evaluate and return individual values and use <b><code>IF<\/code><\/b> to control the flow of statement  execution.<\/p>\n<h3 id=\"sixth\">&#8220;Can I use control-of-flow language to do an <i>upsert<\/i> in SQL Server?&#8221;<\/h3>\n<p>For those not familiar with the term, <i>upsert<\/i> refers  to code that includes logic to either update a row or insert a row, depending on whether that row exists. As with other  data modification operations, you can use control-of-flow statement elements to do an upsert.<\/p>\n<p>One of the most common ways to do this is to use an  <b><code>IF<\/code><\/b>  expression to check for the row&#8217;s existence and then execute your statements accordingly. Let&#8217;s start with a simple  temporary table to demonstrate how this works:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">CREATE TABLE #products\n(ProdID INT, ListPrice MONEY);\n\nINSERT INTO #products VALUES\n(101, 199.99),\n(102, 299.99),\n(103, 399.99);\n\nNow let's create our data modification statements, based on an IF...ELSE construction to control the execution flow:\nDECLARE @ProdID INT = 103;\nDECLARE @ListPrice MONEY = 388.88\n\nIF EXISTS(SELECT * FROM #products \n&#160;&#160;&#160; WHERE ProdID = @ProdID)\n&#160; BEGIN\n&#160;&#160;&#160; UPDATE #products\n&#160;&#160;&#160; SET ListPrice = @ListPrice\n&#160;&#160;&#160; WHERE ProdID = @ProdID\n&#160; END\nELSE\n&#160; BEGIN\n&#160;&#160;&#160; INSERT INTO #products\n&#160;&#160;&#160;&#160;&#160; VALUES(@ProdID, @ListPrice)\n&#160; END;\n\nSELECT * FROM #products WHERE ProdID = @ProdID;\n\n<\/pre>\n<p>The <b> <code>IF<\/code><\/b> expression uses the  <b><code>EXISTS<\/code><\/b>  function to determine whether the row exists (based on the product ID). If it does exist, the  <b><code>UPDATE<\/code><\/b>  statement is executed. Otherwise, the database engine performs the <b> <code>INSERT<\/code><\/b> statement defined in the  <b><code>ELSE<\/code><\/b> clause. <\/p>\n<p>In this case, the value does exist so the <b> <code>ListPrice<\/code><\/b> value is updated and the  <b><code>SELECT<\/code><\/b> statement returns a value of <b><code>388.88<\/code><\/b>, as expected. Had we set the  value of the <b><code>@ProdID<\/code><\/b>  variable to one that doesn&#8217;t exist, a new row would have instead been inserted into the table.<\/p>\n<p>This, of course, is a very simple example, but it demonstrates what is a common approach to  using an <b><code>IF...ELSE<\/code><\/b> statement to perform an  upsert. And you can just as easily use control-of-flow language for other types of data modifications.<\/p>\n<p>But you need to be careful when you start to mix-and-match in this way. For example, the  solution above could result in concurrency issues, either in the form of deadlocks or multiple insertions of the same  data. In addition, this approach might not perform as well as other options because of unnecessary table or index scans.  Workarounds to this approach might include using the <b> <code>@@rowcount<\/code><\/b> system variable to test whether  the update has worked or using a <b> <code>MERGE<\/code><\/b> statement to join the table to  itself. The point is, you must be especially diligent when using control-of-flow language to modify data.<\/p>\n<h3 id=\"seventh\">&#8220;I don&#8217;t get how a  <code>WHILE<\/code>  loop works. Can you help make sense of what&#8217;s going on here?&#8221;<\/h3>\n<p>The <b> <code>WHILE<\/code><\/b> loop provides a structure for  repeatedly executing a set of statements as long as the loop&#8217;s condition evaluates to  <b><code>TRUE<\/code><\/b>.  The <b><code>WHILE<\/code><\/b>  loop lets you add the logic necessary to limit the number of executions when you don&#8217;t know that number in advance.  Let&#8217;s look at a few examples to get a sense of how these loops work.<\/p>\n<p>We&#8217;ll start simply by first demonstrating the logic behind the execution flow when using a <b><code>WHILE<\/code><\/b> loop. The following T-SQL  declares a variable and then executes a loop based on the variable&#8217;s value:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">DECLARE @c INT = 100;\n\nWHILE @c &lt;= 104\n&#160; BEGIN\n&#160;&#160;&#160; PRINT @c;\n&#160;&#160;&#160; SET @c = @c + 1; \n&#160; END;\n\n<\/pre>\n<p>The loop begins with the <b><code>WHILE<\/code><\/b> keyword, followed by the  condition that is evaluated each time the loop runs. If the condition evaluates to  <b><code>TRUE<\/code><\/b>, the query engine executes the  T-SQL in the statement block that follows the condition. If the condition evaluates to  <b><code>FALSE<\/code><\/b>,  the query engine exits the loop and continues on to any code after the statement block. <\/p>\n<p>In this case, the condition will evaluate to <b> <code>TRUE<\/code><\/b> five times, which means the loop will  run five times. When the variable value exceeds <b> <code>104<\/code><\/b>, the loop ends. The following statement  shows the results that the statements return:<\/p>\n<pre>\t\t100\n101\n102\n103\n104\n\t<\/pre>\n<p>You can further control the logic within your loop by adding a  <b><code>BREAK<\/code><\/b>  statement in any place where the query engine should exit the loop:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">DECLARE @d INT = 100;\n\nWHILE @d &lt;= 104\n&#160; BEGIN\n&#160;&#160;&#160; PRINT @d;\n&#160;&#160;&#160; SET @d = @d + 1;\n&#160;&#160; &#160;IF @d = 103\n&#160; &#160;&#160;&#160;&#160;BREAK;\n&#160; END;\n\n<\/pre>\n<p>This time around, we&#8217;ve added an <b> <code>IF<\/code><\/b> statement that specifies that the query  engine should break out of the loop if the variable value equals <b><code>103<\/code><\/b>. Because we&#8217;ve added the  <b><code>IF<\/code><\/b> and  <b><code>BREAK<\/code><\/b>  conditions, our loop now returns only the following results;<\/p>\n<pre>100\n101\n102\n\t<\/pre>\n<p>As you can see, query execution stopped when the variable value hit  <b><code>103<\/code><\/b>.  <\/p>\n<p>You can also add a <b><code>CONTINUE<\/code><\/b> statement to your  <b><code>WHILE<\/code><\/b>  loop to further control the execution. The <b><code>CONTINUE<\/code><\/b> statement causes the query  engine to restart the loop from wherever you&#8217;ve added <b> <code>CONTINUE<\/code><\/b>:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">DECLARE @e INT = 100;\n\nWHILE @e &lt;= 104\n&#160; BEGIN\n&#160;&#160;&#160; PRINT @e;\n&#160;&#160;&#160; SET @e = @e + 1; \n&#160;&#160;&#160; CONTINUE;\n&#160; IF @e = 103\n&#160;&#160;&#160; BREAK;\n&#160; END;\n\n<\/pre>\n<p>Because I&#8217;ve included the <b><code>CONTINUE<\/code><\/b> statement where I did, the  statement will never reach the final <b> <code>IF<\/code><\/b> block. Instead, each time the  <b><code>WHILE<\/code><\/b> condition evaluates to  <b><code>TRUE<\/code><\/b>,  the statement block will be executed up to <b><code>CONTINUE<\/code><\/b> and then start over,  giving us the following results:<\/p>\n<pre>100\n101\n102\n103\n104\n\t<\/pre>\n<p>Of course, all we&#8217;ve done is go full circle, receiving the same results we received without  using <b><code>CONTINUE<\/code><\/b> and  <b><code>BREAK<\/code><\/b>,  but these simple examples should help demonstrate the basic concepts of a <b> <code>WHILE<\/code><\/b> loop. <\/p>\n<p>But now suppose we want to do something a little more involved. Let&#8217;s start by creating a  small temporary table based on data from the <b> <code>Product<\/code><\/b> table in the  <b><code>AdventureWorks2014<\/code><\/b>  database: <\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">SELECT ProductID, \n&#160; Name AS ProductName,\n&#160; StandardCost AS Wholesale,\n&#160; ListPrice As Retail\nINTO #PriceyProducts\nFROM Production.Product\nWHERE ListPrice &gt; 2999.99;\n\nSELECT * FROM #PriceyProducts \n<\/pre>\n<p>The <b> <code>SELECT<\/code><\/b> statement returns the results shown  in the following table:<\/p>\n<table class=\"MsoTableGrid\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>ProductID<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>ProductName<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>Wholesale<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>Retail<\/b><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">749<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Road-150 Red, 62<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2171.2942<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">3578.27<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">750<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Road-150 Red, 44<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2171.2942<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">3578.27<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">751<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Road-150 Red, 48<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2171.2942<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">3578.27<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">752<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Road-150 Red, 52<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2171.2942<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">3578.27<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">753<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Road-150 Red, 56<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2171.2942<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">3578.27<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">771<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Mountain-100 Silver, 38<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">1912.1544<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">3399.99<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">772<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Mountain-100 Silver, 42<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">1912.1544<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">3399.99<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">773<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Mountain-100 Silver, 44<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">1912.1544<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">3399.99<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">774<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Mountain-100 Silver, 48<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">1912.1544<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">3399.99<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">775<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Mountain-100 Black, 38<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">1898.0944<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">3374.99<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">776<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Mountain-100 Black, 42<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">1898.0944<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">3374.99<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">777<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Mountain-100 Black, 44<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">1898.0944<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">3374.99<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">778<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Mountain-100 Black, 48<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">1898.0944<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">3374.99<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Now suppose we want to increase the retail prices in 10% percent increments, but only as long  as the average net price remains under $2500. At the same time, the retail price must always remain under $4999.99. We  can create a <b><code>WHILE<\/code><\/b>  loop that increments the price while ensuring we stay within our parameters:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">DECLARE @count INT = 0\n\nWHILE (SELECT AVG(Retail - Wholesale) FROM #PriceyProducts) &lt; 2500\n&#160; BEGIN\n&#160;&#160;&#160; UPDATE #PriceyProducts SET Retail = Retail * 1.1\n&#160;&#160;&#160; SET @count = @count + 1;\n&#160;&#160;&#160; IF (SELECT MAX(Retail) FROM #PriceyProducts) &lt; 4999.99\n&#160;&#160;&#160;&#160;&#160; CONTINUE;\n&#160;&#160;&#160; ELSE\n&#160;&#160;&#160;&#160;&#160; BREAK;\n&#160; END;\nPRINT 'The WHILE loop ran ' + CAST(@count AS VARCHAR(10)) + ' times.'\n\n<\/pre>\n<p>The <b> <code>WHILE<\/code><\/b> condition checks whether the average  net price is under $2500. If the condition evaluates to <b> <code>TRUE<\/code><\/b>, the statement block runs and  increases the retail prices by 10%. The statement block also includes an <b> <code>IF<\/code><\/b> statement, which checks whether the  highest retail price is under $4999.00. If it is, the loop starts over. Should the  <b><code>IF<\/code><\/b>  condition evaluate to <b><code>FALSE<\/code><\/b>,  the query engine breaks out of the loop and jumps to the final <b><code>PRINT<\/code><\/b> statement.  <\/p>\n<p>I included the <b><code>@count<\/code><\/b> variable only to count the  number of times the <b><code>WHILE<\/code><\/b>  loop runs, which in this case, is three times, as the following results show:<\/p>\n<pre>The WHILE loop ran 3 times.<\/pre>\n<p>If we were now to view the data in the <b> <code>#PriceyProducts<\/code><\/b> table, we would see the  following results:<\/p>\n<table class=\"MsoTableGrid\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>ProductID<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>ProductName<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>Wholesale<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>Retail<\/b><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">749<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Road-150 Red, 62<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2171.2942<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">4762.6774<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">750<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Road-150 Red, 44<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2171.2942<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">4762.6774<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">751<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Road-150 Red, 48<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2171.2942<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">4762.6774<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">752<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Road-150 Red, 52<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2171.2942<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">4762.6774<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">753<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Road-150 Red, 56<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">2171.2942<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">4762.6774<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">771<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Mountain-100 Silver, 38<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">1912.1544<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">4525.3867<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">772<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Mountain-100 Silver, 42<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">1912.1544<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">4525.3867<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">773<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Mountain-100 Silver, 44<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">1912.1544<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">4525.3867<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">774<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Mountain-100 Silver, 48<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">1912.1544<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">4525.3867<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">775<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Mountain-100 Black, 38<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">1898.0944<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">4492.1117<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">776<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Mountain-100 Black, 42<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">1898.0944<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">4492.1117<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">777<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Mountain-100 Black, 44<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">1898.0944<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">4492.1117<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">778<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">Mountain-100 Black, 48<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">1898.0944<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">4492.1117<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>We can verify our results by running the following  <b><code>SELECT<\/code><\/b>  statement to determine the current average net price:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">SELECTAVG(Retail - Wholesale) FROM #PriceyProducts<\/pre>\n<p>The statement returns the value <b> <code>2598.9164<\/code><\/b>, which exceeds the $2500. It was  at this point that the query engine exited the <b> <code>WHILE<\/code><\/b> loop. In addition, as we can see in  the results, the maximum <b><code>Retail<\/code><\/b> value is  <b><code>4762.6774<\/code><\/b>,  which is below the <b><code>4999.99<\/code><\/b>  limit.<\/p>\n<h3 id=\"eighth\">&#8220;How do I add a pause or wait time to my T-SQL in  order to delay execution?&#8221;<\/h3>\n<p>SQL Server supports a handy control-of-flow statement called  <b><code>WAITFOR<\/code><\/b>,  which stops code execution until a specified time or for a specified amount of time. A  <b><code>WAITFOR<\/code><\/b>  statement can be handy to deal with those unusual circumstances when you need to work around legacy systems or network  limitations. For example, one of your SQL Server jobs might trigger a second job that can run only at specific time  because of network constrains. <\/p>\n<p class=\"MsoNormal\"><code>WAITFOR<\/code>  can also be used in development and testing environments to help generate specific responses. For example, suppose we&#8217;ve  created the following temporary table:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">SELECT ProductID AS ProdID, \n&#160; Name AS ProductName,\n&#160; StandardCost AS Wholesale,\n&#160; ListPrice As Retail\nINTO ##awproducts\nFROM Production.Product\nWHERE FinishedGoodsFlag = 1;\n<\/pre>\n<p>Now suppose we want to test concurrency by running two separate operations, each in its own  session, to verify whether we&#8217;ll get a dirty read. We can start the first session, but include a  <b><code>WAITFOR<\/code><\/b>  statement to delay the transaction by five seconds:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">BEGIN TRANSACTION; \n&#160;\nUPDATE ##awproducts\nSET Retail = Retail * 1.2\nWHERE ProdID = 680;\n\nWAITFOR DELAY '00:00:05'&#160; \n\nROLLBACK TRANSACTION;\n<\/pre>\n<p>The <b> <code>WAITFOR<\/code><\/b> statement includes the  <b><code>DELAY<\/code><\/b>  keyword to indicate that we want to delay the execution, rather than use the  <b><code>TIME<\/code><\/b>  option to specify a specific time. During these five seconds, we run a <b> <code>SELECT<\/code><\/b> statement from our second session,  but first set the isolation level to <b> <code>READ<\/code><\/b>  <b><code>UNCOMMITTED<\/code><\/b>:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;\n\nSELECT Retail FROM ##awproducts\nWHERE ProdID = 680;\n\t<\/pre>\n<p>Because the first transaction is still active, the  <b><code>SELECT<\/code><\/b>  statement returns a value of <b><code>1717.80<\/code><\/b>, the value that has been  updated in the first session. However, if we run the <b> <code>SELECT<\/code><\/b> statement again, after the first  transaction completes (and rolls back), the statement returns the value <b> <code>1431.50<\/code><\/b>. In other words, the first time we  ran our <b><code>SELECT<\/code><\/b>  statement we received a dirty read.<\/p>\n<p>We can also specify the exact time we want to end our delay by using the  <b><code>TIME<\/code><\/b>  option:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">DECLARE @time DATETIME = DATEADD(S, 5, GETDATE());\nWAITFOR TIME @time;\nPRINT 'The waiting is over.'; \n\t<\/pre>\n<p>Once again, we&#8217;re waiting only five seconds, but you get the point. You can provide a time  rather than a range, giving you another way to control execution.<\/p>\n<h3 id=\"ninth\">&#8220;Is it possible to skip from one section of your  T-SQL code to another?&#8221;<\/h3>\n<p>In T-SQL you can use a <b><code>GOTO<\/code><\/b> statement to jump to another  part of the code, as long as you&#8217;ve assigned a label to the destination. A label is merely an identifier that provides a  heading for the targeted section of code. For example, the following T-SQL includes several labeled blocks of code with  several references to them:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">DECLARE @count INT = 1;\n\nIF @count = 1\n&#160; GOTO goto_one;\nELSE IF @count = 2\n&#160; GOTO goto_two;\nELSE IF @count = 3\n&#160; GOTO goto_three;\nELSE\n&#160; GOTO goto_four;\n\ngoto_one:\nPRINT 'This is goto_one.'\nGOTO goto_four;\n\ngoto_two:\nPRINT 'This is goto_two.'\nGOTO goto_four;\n\ngoto_three:\nPRINT 'This is goto_three.'\nGOTO goto_four;\n\ngoto_four:\nRETURN\n\n<\/pre>\n<p>When you reference a label, you provide only the label name along with the  <b><code>GOTO<\/code><\/b>  keyword. However, when you assign a label to a bock of code, you must also include a colon. When the query engine  encounters a <b><code>GOTO<\/code><\/b> statement, it jumps to the  label identified in the statement. For example, the initial <b> <code>IF<\/code><\/b> statement includes a  <b><code>GOTO<\/code><\/b>  statement that points to the <b> <code>goto_one<\/code><\/b> label. As a result, if the  <b><code>@count<\/code><\/b>  variable has a value of <b><code>1<\/code><\/b>,  the query engine will jump to the <b> <code>goto_one<\/code><\/b> label, execute the  <b><code>PRINT<\/code><\/b>  statement associated with that label, and return the following results.<\/p>\n<pre>This is goto_one.<\/pre>\n<p>Of course, you&#8217;re likely to want to use the <b> <code>GOTO<\/code><\/b> statement for more practical purposes  than in the example above. For example, suppose your T-SQL includes a number of  <b><code>IF<\/code><\/b>  statements that take different steps. Regardless of which condition evaluates to  <b><code>TRUE<\/code><\/b>,  you want to run a final <b><code> INSERT<\/code><\/b> statement that logs the event. You can do something similar to the following:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">CREATE TABLE #UsageLog\n(LogID INT IDENTITY, Usage VARCHAR(20), \n&#160; LogTime DATETIME DEFAULT GETDATE());\n\nDECLARE @CustID INT = 170, @usage VARCHAR(20) = '';\n\nIF @CustID IS NULL\n&#160; BEGIN\n&#160;&#160;&#160; PRINT 'You must provide a customer ID.';\n&#160;&#160;&#160; PRINT 'Contact the sales rep for your region:';\n&#160;&#160;&#160; SELECT FirstName, LastName, TerritoryName, EmailAddress\n&#160;&#160;&#160; FROM Sales.vSalesPerson\n&#160;&#160;&#160; WHERE JobTitle = 'Sales Representative';\n&#160;&#160;&#160; SET @usage = 'ID null';\n&#160;&#160;&#160; GOTO log_usage;\n&#160; END\nELSE IF EXISTS(SELECT * FROM Sales.vIndividualCustomer\n&#160;&#160;&#160; WHERE BusinessEntityID = @CustID)\n&#160; BEGIN\n&#160;&#160;&#160; SELECT FirstName, LastName, City, StateProvinceName\n&#160;&#160;&#160; FROM Sales.vIndividualCustomer\n&#160;&#160;&#160; WHERE BusinessEntityID = @CustID;\n&#160;&#160;&#160; SET @usage = 'ID valid';\n&#160;&#160;&#160; GOTO log_usage;\n&#160; END\nELSE\n&#160; BEGIN\n&#160;&#160;&#160; PRINT 'No record matches the customer ID ' + \n&#160;&#160;&#160;&#160;&#160; CAST(@CustID AS VARCHAR(10)) + '.'\n&#160;&#160;&#160; SET @usage = 'ID invalid';\n&#160;&#160;&#160; GOTO log_usage;\n&#160; END\n\nlog_usage:\nINSERT INTO #UsageLog (Usage) VALUES(@usage);\n<\/pre>\n<p>For each possible condition, the statement block ends with a  <b><code>GOTO<\/code><\/b>  statement that points to the <b> <code>log_usage<\/code><\/b> label, so no matter what happens  elsewhere, the last statement here will run. Although we&#8217;ve included only a simple  <b><code>INSERT<\/code><\/b>  statement with out label, you can use this strategy to avoid having to recode more complex logic in multiple places.<\/p>\n<h3 id=\"tenth\">&#8220;What&#8217;s the simplest way to incorporate error  handling into my stored procedures?&#8221;<\/h3>\n<p>Since the release SQL Server 2005, error handling has been fairly easy to incorporate in your  T-SQL code through the use of <b> <code>TRY...CATCH<\/code><\/b> blocks. The idea behind this is  that you put the main body of your code in the <b> <code>TRY<\/code><\/b> block and put the error handling in the <b><code>CATCH<\/code><\/b>  block. The statements in the <b> <code>CATCH<\/code><\/b> block will run only if the query  engine encounters an error in the <b> <code>TRY<\/code><\/b> block.<\/p>\n<p>When Microsoft first added support for <b> <code>TRY...CATCH<\/code><\/b> error handling, you had to use a <b><code>RAISERROR<\/code><\/b> statement to catch and  throw the error, should one occur. But that changed in SQL Server 2012. You can now use a  <b><code>THROW<\/code><\/b> statement, which is simpler  to use and more accurate.<\/p>\n<p>To demonstrate how all this works, let&#8217;s start with a simple temporary table and add a few  rows of data:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">CREATE TABLE #products\n(ProdID INT PRIMARY KEY, ListPrice MONEY);\n\nINSERT INTO #products VALUES\n(101, 199.99),\n(102, 299.99),\n(103, 399.99);\n<\/pre>\n<p>Now let&#8217;s create a stored procedure that adds a row to the table, with the values coming from  two input parameters:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">IF OBJECT_ID('dbo.AddProduct', 'p') IS NOT NULL\nDROP PROCEDURE dbo.AddProduct;\nGO\n\nCREATE PROCEDURE dbo.AddProduct\n&#160; (@ProdID INT, @ListPrice MONEY)\nAS\nBEGIN TRY\n&#160; BEGIN TRANSACTION;\n&#160;&#160;&#160; INSERT INTO #products VALUES (@ProdID, @ListPrice);\n&#160; COMMIT TRANSACTION;\nEND TRY\nBEGIN CATCH\n&#160; IF @@TRANCOUNT &gt; 0\n&#160;&#160;&#160; ROLLBACK TRANSACTION;\n&#160; PRINT 'The stored procedure generated the following error:';\n&#160; THROW;\nEND CATCH;\nGO\n<\/pre>\n<p>First, notice that the procedure definition includes the  <b><code>TRY...CATCH<\/code><\/b>  blocks. In the <b><code>TRY<\/code><\/b>  block, we include the primary T-SQL needed to begin the transaction, insert the vales into the table, and commit the  transaction. If the statements in the <b> <code>TRY<\/code><\/b> block run with no problem, the  operation completes and the database engine exists the <b> <code>TRY...CATCH<\/code><\/b> blocks. However, if the  <b><code>TRY<\/code><\/b>  block generates an error, the database engine skips to the <b><code>CATCH<\/code><\/b> block where the error can be  handled.<\/p>\n<p>In this example, the <b><code>CATCH<\/code><\/b> block includes three  statements. The first is an <b> <code>IF<\/code><\/b> statement that rolls back the  transaction if the <b><code> @@TRANCOUNT<\/code><\/b> system variable value is greater than  <b><code>0<\/code><\/b>, which means a transaction is  active in the current session. Next, it includes a <b> <code>PRINT<\/code><\/b> statement, which I&#8217;ve included  primarily to verify that the <b><code>CATCH<\/code><\/b> block statements are being  executed should an error occur in the <b> <code>TRY<\/code><\/b> block. Finally, I add a  <b><code>THROW<\/code><\/b>  statement to catch and return the error.<\/p>\n<p>Let&#8217;s look at the stored procedure in action to demonstrate how everything works. First,  we&#8217;ll use the procedure to add a row to our temporary table and then run a  <b><code>SELECT<\/code><\/b> statement:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">EXEC AddProduct 104, 499.99;\n\nSELECT * FROM #products;\n\t<\/pre>\n<p>Not surprisingly, the query returns four rows, including a row for product 104, as shown in  the following results:<\/p>\n<table class=\"MsoTableGrid\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>ProdID<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\"><b>ListPrice<\/b><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">101<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">199.99<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">102<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">299.99<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">103<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">399.99<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"MsoNormal\">104<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"MsoNormal\">499.99<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Now let&#8217;s try to run the same <b> <code>EXECUTE<\/code><\/b> command again:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">EXEC AddProduct 104, 499.99;<\/pre>\n<p>Because we&#8217;d be violating the primary key by adding this row, the query engine baulks and  returns the following results:<\/p>\n<p>The  stored procedure generated the following error:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">Msg 2627, Level 14, State 1, Procedure AddProduct, Line 1058\nViolation of PRIMARY KEY constraint 'PK__#product__042785C5164AE135'. Cannot insert duplicate key in object 'dbo.#products'. The duplicate key value is (104).\n\n<\/pre>\n<p>Notice that the results include the message from the  <b><code>PRINT<\/code><\/b>  command, along with the error details provided by the <b> <code>THROW<\/code><\/b> statement. <\/p>\n<p>The <b> <code>THROW<\/code><\/b> statement also let&#8217;s you define your  own error number, message, and state, as shown in the following example:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">IF OBJECT_ID('dbo.AddProduct', 'p') IS NOT NULL\nDROP PROCEDURE dbo.AddProduct;\nGO\n\nCREATE PROCEDURE dbo.AddProduct\n&#160; (@ProdID INT, @ListPrice MONEY)\nAS\nBEGIN TRY\n&#160; BEGIN TRANSACTION;\n&#160;&#160;&#160; INSERT INTO #products VALUES (@ProdID, @ListPrice);\n&#160; COMMIT TRANSACTION;\nEND TRY\nBEGIN CATCH\n&#160; IF @@TRANCOUNT &gt; 0\n&#160;&#160;&#160; ROLLBACK TRANSACTION;\n&#160; PRINT 'The stored procedure generated the following error:';\n&#160; THROW 55555, 'SQL Server threw an exception because of the way you called your stored procedure.', 1;\nEND CATCH;\nGO\n\n<\/pre>\n<p>If we were to once again try to add product 104, out results would now look like the  following:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">The stored procedure generated the following error:\nMsg 55555, Level 16, State 1, Procedure AddProduct, Line 1111\nSQL Server threw an exception because of the way you called your stored procedure.\n\n<\/pre>\n<p>It&#8217;s up to you whether to go with the generic message or create your own. The  <b><code>THROW<\/code><\/b>  statement on its own is a powerful tool, and that might be all you need. There is more to error handling, though, so you  might benefit from an article I wrote a while back on the subject: &#8220;<a href=\"https:\/\/www.simple-talk.com\/sql\/database-administration\/handling-errors-in-sql-server-2012\/\">Handling  Errors in SQL Server 2012<\/a>.&#8221;<\/p>\n<\/p><\/div>\n","protected":false},"excerpt":{"rendered":"<p>Surely, we all know how T-SQL Control-of-flow language works? In fact it is surprisingly easy to get caught out. What, for example,  do the BREAK, RETURN and CONTINUE  keywords do, precisely,  in their various contexts? the answers to this  and other questions aren&#8217;t all entirely obvious, but we&#8217;re too shy to ask them in public, and risk displaying our ignorance.&hellip;<\/p>\n","protected":false},"author":221841,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[143531],"tags":[4179,4150,4183,4252,5771],"coauthors":[],"class_list":["post-1941","post","type-post","status-publish","format-standard","hentry","category-t-sql-programming-sql-server","tag-source-control","tag-sql","tag-t-sql","tag-t-sql-programming","tag-too-shy"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/1941","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/users\/221841"}],"replies":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/comments?post=1941"}],"version-history":[{"count":6,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/1941\/revisions"}],"predecessor-version":[{"id":54525,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/1941\/revisions\/54525"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=1941"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=1941"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=1941"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=1941"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}