Beginning Microsoft SQL Server 2008 ... - S3 Tech Training

Beginning Microsoft SQL Server 2008 ... - S3 Tech Training Beginning Microsoft SQL Server 2008 ... - S3 Tech Training

cdn.s3techtraining.com
from cdn.s3techtraining.com More from this publisher
17.06.2013 Views

Chapter 12: Stored Procedures 386 returning numbers and, instead, return a variable name that will make my code more readable by indicating the nature of the error I’m returning. … … SET NOCOUNT ON; -- Set up “constants” for error codes DECLARE @BUSINESS_ENTITY_ID_NOT_FOUND int, @DUPLICATE_RATE_CHANGE int SET @BUSINESS_ENTITY_ID_NOT_FOUND = -1000 SET @DUPLICATE_RATE_CHANGE = -2000 BEGIN TRY … … You may be curious as to why I’m using negative values here for my errors. While there is no real standard on such things, I tend to use positive values for return codes that are informational in nature (perhaps there are multiple possible successful outcomes and I want to indicate which successful outcome occurred) and negative values for errors. You can find your own path on such things; just make sure you follow the cardinal rule — be consistent! Also, I am deliberately not using the initialization syntax that became available in SQL Server 2008 (I would change the declare to DECLARE @BUSINESS_ENTITY_ ID_NOT_FOUND int = -1000). This is purely for backward compatibility reasons, so adjust accordingly. Next, we can test how many rows were affected by the UPDATE to HumanResources.Employee and utilize that to detect a BusinessEntityID Not Found error: … … UPDATE HumanResources.Employee SET JobTitle = @JobTitle, HireDate = @HireDate, CurrentFlag = @CurrentFlag WHERE BusinessEntityID = @BusinessEntityID; IF @@ROWCOUNT > 0 -- things happened as expected INSERT INTO HumanResources.EmployeePayHistory (BusinessEntityID, RateChangeDate, Rate, PayFrequency) VALUES (@BusinessEntityID, @RateChangeDate, @Rate, @PayFrequency); ELSE -- ruh roh, the update didn’t happen, so skip the insert, -- set the return value and exit BEGIN PRINT ‘BusinessEntityID Not Found’; ROLLBACK TRAN; RETURN @BUSINESS_ENTITY_ID_NOT_FOUND; END … …

Note the removal of the HireDate column from the UPDATE. As we discussed earlier, the RETURN will immediately exit the sproc supplying the return value provided (in this case, –1000 — the amount matching our variable). Our client application can now test the return value and match it against a known list of possible errors. That moves us on to our second potential error. We have a couple of ways we can handle this. We could pre-query the EmployeePayHistory table to see if it already has a matching row, and then avoid the INSERT entirely. Alternatively, we can just allow SQL Server to detect the error and just beef up the error handler to address that known possibility. In this case, I’m going to opt for the latter. It is almost always better to treat the rule and handle the exception. We would like to think that this particular error is going to be very infrequent, so we’ll largely assume it isn’t going to happen and address it when it does. With this in mind, we only need to make some alterations to our error handler: … … BEGIN CATCH -- Rollback any active or uncommittable transactions before -- inserting information in the ErrorLog IF @@TRANCOUNT > 0 BEGIN ROLLBACK TRANSACTION; END EXECUTE dbo.uspLogError; IF ERROR_NUMBER() = 2627 -- Primary Key violation BEGIN PRINT ‘Duplicate Rate Change Found’; RETURN @DUPLICATE_RATE_CHANGE; END END CATCH; … … Chapter 12: Stored Procedures OK, so with all these changes in place, let’s take a look at our new overall sproc. While this is a new sproc, I’m highlighting only those lines that change versus the original we cloned it from: CREATE PROCEDURE HumanResources.uspEmployeeHireInfo2 @BusinessEntityID [int], @JobTitle [nvarchar](50), @HireDate [datetime], @RateChangeDate [datetime], @Rate [money], @PayFrequency [tinyint], @CurrentFlag [dbo].[Flag] WITH EXECUTE AS CALLER AS BEGIN SET NOCOUNT ON; 387

Chapter 12: Stored Procedures<br />

386<br />

returning numbers and, instead, return a variable name that will make my code more readable by indicating<br />

the nature of the error I’m returning.<br />

…<br />

…<br />

SET NOCOUNT ON;<br />

-- Set up “constants” for error codes<br />

DECLARE @BUSINESS_ENTITY_ID_NOT_FOUND int,<br />

@DUPLICATE_RATE_CHANGE int<br />

SET @BUSINESS_ENTITY_ID_NOT_FOUND = -1000<br />

SET @DUPLICATE_RATE_CHANGE = -2000<br />

BEGIN TRY<br />

…<br />

…<br />

You may be curious as to why I’m using negative values here for my errors. While there is no real<br />

standard on such things, I tend to use positive values for return codes that are informational in nature<br />

(perhaps there are multiple possible successful outcomes and I want to indicate which successful outcome<br />

occurred) and negative values for errors. You can find your own path on such things; just make sure you<br />

follow the cardinal rule — be consistent! Also, I am deliberately not using the initialization syntax that<br />

became available in <strong>SQL</strong> <strong>Server</strong> <strong>2008</strong> (I would change the declare to DECLARE @BUSINESS_ENTITY_<br />

ID_NOT_FOUND int = -1000). This is purely for backward compatibility reasons, so adjust accordingly.<br />

Next, we can test how many rows were affected by the UPDATE to HumanResources.Employee and utilize<br />

that to detect a BusinessEntityID Not Found error:<br />

…<br />

…<br />

UPDATE HumanResources.Employee<br />

SET JobTitle = @JobTitle,<br />

HireDate = @HireDate,<br />

CurrentFlag = @CurrentFlag<br />

WHERE BusinessEntityID = @BusinessEntityID;<br />

IF @@ROWCOUNT > 0<br />

-- things happened as expected<br />

INSERT INTO HumanResources.EmployeePayHistory<br />

(BusinessEntityID,<br />

RateChangeDate,<br />

Rate,<br />

PayFrequency)<br />

VALUES (@BusinessEntityID, @RateChangeDate, @Rate, @PayFrequency);<br />

ELSE<br />

-- ruh roh, the update didn’t happen, so skip the insert,<br />

-- set the return value and exit<br />

BEGIN<br />

PRINT ‘BusinessEntityID Not Found’;<br />

ROLLBACK TRAN;<br />

RETURN @BUSINESS_ENTITY_ID_NOT_FOUND;<br />

END<br />

…<br />

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!