Stored Procedure Practices in SQL Server

A Stored Procedure is a set of PL/SQL statements with a block of name. This is usually being used to do CRUD operations.

Road map

This article explains the following topics that can be helpful when creating and using Stored Procedures.

  1. When to use Stored Procedures.
  2. Basic format, indentation rules and key points for Stored Procedures.
  3. Stored Procedure Template.
  4. Sample table with Stored Procedure for create and update operations.
  5. Advantages of Stored Procedures.
  6. Drawbacks.

When to use Stored Procedures

There is no certain limitation to the use of Stored Procedures, only specific scenarios. Stored Procedures can be used to do CRUD operations. Eventhough I listed some of the scenarios, you can use a Stored Procedure instead of C# code.

  1. To do a series of DML operations they are very suitable.

  2. They are very suitable for a maintenance standpoint type of applications since these are very easy to do the troubleshooting.

  3. Stored Procedures reduce SQL Injection attacks also. So this is also one of the options to use Stored Procedures.

  4. A Stored Procedure separates the data layer from the application. So, when implementating an application, at max one or two persons can manage the entire DB operations using Stored Procedures. Others can work on code or design related stuff.

  5. It helps for improved security for tables access and permissions based on user role.

  6. Bulk data of insertion from one table to another with a possible set of conditions.

  7. The operations that you need to do is easily fulfilled with SQL Server built-in functions or customized functions (for example, Split Custom Function, date related built-in functions and so on) when inserting or updating any data.

  8. The final note is, if you have a good command over database T-SQL Statements, then creating Stored Procedures for an application is very easy for implementation and maintenance process for an application.

Basic Format, Indentation rules, Key Points for Stored Procedures

When creating a Stored Procedure, the following procedure is very useful.

  1. All SQL Keywords must be in CAPITAL letters.

  2. Basic Indentation (TAB space) need to be followed when creating a Stored Procedure.

    1. BEGIN  
    2.         IF(--CONDITION)  
    3.        BEGIN  
    4.               --Some Statements  
    5.        END  
    6.        --Again Some Statements  
    7. END 
  3. As you observed the previous sample SQL statement contains the TAB indentation after the first BEGIN statement and the same for inside the IF statement of a BEGIN condition.

  4. Binding the entire Stored Procedure with a BEGIN and END block is a good practice even though it is optional.

  5. The first line of a Stored Procedure block should start with the “SET NOCOUNT ON”. It helps to reduce the unnecessary network round-trips.

  6. The user created Stored Procedure should not be begin with “sp_” since all system Stored Procedures are begun with “sp_” only.

  7. The name of the Stored Procedure should reflect the action performed through the Stored Procedure. For example, SaveEmployee, GetEmployeeByEmployeeId and so on.

  8. The Stored Procedure should contain try catch blocks and the catch block should throw the error using RAISEERROR.

  9. Usually to get the existing Stored Procedure text, you can use "SP_HELPTEXT [PROCEDURE_NAME]". It returns a set of text statements for that Stored Procedure and is like  "Result to Grid" format. But, the format of text for the Stored Procedure "Results to Grid" is not suitable. When getting the Stored Procedure text using "SP_HELPTEXT [PROCEDURE_NAME]", please change that options (Results to Text (Ctrl + T)). Then, the format of Stored Procedure text remains the same and looks good.

  10. Creating Stored Procedure if it contains some set of headers to identify, who has created or who has modified later and what he modified then it would help very much to the developers who will modify or understand the Stored Procedure in the future.

  11. I usually follow this set of headers for the Stored Procedures:

    1.  /*=============================================
    2. -- Author:Ramchand [Who has created] 
    3. -- Create date:9 June 2015 [When its created] 
    4. -- Description: [About the Stored Procedure] 
    5. -- Modify By: Ramchand [Who has last modified] 
    6. -- Last Modified Date: 1 July 2015 [When its last modified] 
    7. -- Update: [When and what are the updates done to the stored procedure] 
    8. --1). 1July2015- [Modified some thing by -[Developer]]
    9. --2). 2July2015 –[Modified another thing by -[Developer]]  
    10. -- Unite Test: EXEC [Stored-ProcedureName] [Parameters If any]
    11.  =============================================*/ 
  1. Adding headers and comments when it is required (logical conditions and other operations) are highly preferred since it would be easy to understand for co-developers and you as well.

  2. Use of table and temp variables are highly preferred if required and at the same time using CURSOR is not recommended in the Stored Procedure since it degrades the performance.

  3. In a usual manner, the following scenarios would happen:

  • You will modify some list of Stored Procedures in a day at your end. But when deploying all those to staging/production, you need to recollect all the Stored Procedures.
  • You need to get the list of Stored Procedures for any application.
  • You need to know when the Stored Procedure is modified.

    For all the previous scenarios, you can use one SQL statement, it would help. That statement is as follows.
    1. SELECT * FROM sys.procedures ORDER BY modify_date DESC    
    It would return the list of Stored Procedures from the selected database with the last modified one as the first row.
  1. When creating a Stored Procedure, it would be good if it contains the try catch blocks and transaction-level commits.

  2. To beautify or format the Stored Procedure text very many online tools exist. It would help to store the Stored Procedure text in a correct format. Here are some of the following online tools:

Stored Procedure Template

The following format is one of the formats I usually follow when creating Stored Procedures that include create/update/delete operations.

  1. /*=============================================  
  2. Author:Ramchand [Who has created]         
  3. Create date:9 June 2015 [When its created]  
  4. Description: Create/Save the employee details   [About the Stored Procedure]  
  5. Modify By: [Who has last modified]  
  6. Last Modified Date: [When its last modified]  
  7. Update: [When and what are the updates done to the stored procedure]  
  8. Unit Test: EXEC [PROCEDURE_Name] [Parameters-If-any]  
  9. -- =============================================*/  
  10. CREATE PROCEDURE [PROCEDURE_NAME]  
  11. AS  
  12. BEGIN  
  13.     SET NOCOUNT ON  
  14.     BEGIN TRANSACTION  
  15.     BEGIN TRY  
  16.           
  17.         --Insert/update code here  
  18.         --If everything goes fine, it commit the transaction otherwise it goes to the catch block  
  19.   
  20.         --Commit the transaction at the end of stored procedure if no error occurs  
  21.         COMMIT TRANSACTION  
  22.   
  23.     END TRY  
  24.     BEGIN CATCH  
  25.         --rollback the transaction as it comes to catch block  
  26.         ROLLBACK TRANSACTION  
  27.   
  28.         DECLARE @ErrorNum INT = ERROR_NUMBER();  
  29.         DECLARE @ErrorLine INT = ERROR_LINE();  
  30.         DECLARE @ErrorMsg NVARCHAR(4000) = ERROR_MESSAGE();  
  31.         DECLARE @ErrorSeverity INT = ERROR_SEVERITY();  
  32.         DECLARE @ErrorState INT = ERROR_STATE();  
  33.   
  34.         PRINT 'Error Number ' + CAST(@ErrorNum AS VARCHAR(10));  
  35.         PRINT 'Error Line ' + CAST(@ErrorLine AS VARCHAR(10));  
  36.         RAISERROR(@ErrorMsg, @ErrorSeverity, @ErrorState);  
  37.   
  38.     END CATCH  
  39. END 

Sample Table with Stored Procedure for create and update operations 

I have created one sample table named "Employee" and created a Stored Procedure "SaveEmployee". It would do the creation and update of employee details. The Stored Procedure header contains the unit test format for inserting/updating the employee details using the Stored Procedure. The following is the script for the both table and Stored Procedure. 
  1. SET ANSI_NULLS ON  
  2. GO  
  3. SET QUOTED_IDENTIFIER ON  
  4. GO  
  5. /*=============================================  
  6. Author:Ramchand [Who has created]         
  7. Create date:9 June 2015 [When its created]  
  8. Description: Create/Save the employee details   [About the Stored Procedure]  
  9. Modify By: [Who has last modified]  
  10. Last Modified Date: [When its last modified]  
  11. Update: [When and what are the updates done to the stored procedure]  
  12. Unit Test:   
  13.         For InsertEXEC SaveEmployee 0,'Ramchand','Repalle','Male',1 
  14.         For Update : EXEC SaveEmployee 1, 'Ram','Chand','Male',1  
  15. -- =============================================*/  
  16. CREATE PROCEDURE [dbo].[SaveEmployee]  
  17. (  
  18. @EmployeeID INT,  
  19. @FirstName NVARCHAR(100),  
  20. @LastName NVARCHAR(100),  
  21. @Gender NVARCHAR(10),  
  22. @LoggedInUserID INT  
  23. )  
  24. AS  
  25. BEGIN  
  26.     SET NOCOUNT ON;  
  27.     BEGIN TRANSACTION  
  28.     BEGIN TRY  
  29.     IF(@EmployeeID > 0)  
  30.     BEGIN  
  31.         --UPDATE THE Employee, If Employee matches with the EmployeeId  
  32.         IF EXISTS(SELECT EmployeeId FROM Employee WHERE EmployeeId = @EmployeeID)  
  33.         BEGIN  
  34.             UPDATE Employee SET FirstName = @FirstName,   
  35.                                 LastName = @LastName,  
  36.                                 Gender = @Gender,  
  37.                                 ModifiedBy = @LoggedInUserID,  
  38.                                 ModifiedDate = GETDATE() WHERE EmployeeId = @EmployeeID  
  39.         END  
  40.     END  
  41.     ELSE  
  42.     BEGIN  
  43.         -- insert the employee details  
  44.         INSERT INTO Employee(FirstName,LastName,Gender,CreatedBy,CreatedDate)   
  45.                     VALUES(@FirstName,@LastName,@Gender,@LoggedInUserID,GETDATE())  
  46.         SET @EmployeeID = SCOPE_IDENTITY();       
  47.   
  48.     END  
  49.   
  50.     --Commit the transaction at the end of stored procedure if no error occurs  
  51.     COMMIT TRANSACTION  
  52.   
  53.     END TRY  
  54.     BEGIN CATCH  
  55.         --rollback the transaction as it comes to catch block  
  56.         ROLLBACK TRANSACTION  
  57.   
  58.         DECLARE @ErrorNum INT = ERROR_NUMBER();  
  59.         DECLARE @ErrorLine INT = ERROR_LINE();  
  60.         DECLARE @ErrorMsg NVARCHAR(4000) = ERROR_MESSAGE();  
  61.         DECLARE @ErrorSeverity INT = ERROR_SEVERITY();  
  62.         DECLARE @ErrorState INT = ERROR_STATE();  
  63.   
  64.         PRINT 'Error Number ' + CAST(@ErrorNum AS VARCHAR(10));  
  65.         PRINT 'Error Line ' + CAST(@ErrorLine AS VARCHAR(10));  
  66.         RAISERROR(@ErrorMsg, @ErrorSeverity, @ErrorState);  
  67.   
  68.     END CATCH  
  69. END  
  70. GO  
  71. /****** Object:  Table [dbo].[Employee]    Script Date: 7/2/2015 7:09:34 PM ******/  
  72. SET ANSI_NULLS ON  
  73. GO  
  74. SET QUOTED_IDENTIFIER ON  
  75. GO  
  76. CREATE TABLE [dbo].[Employee](  
  77.     [EmployeeId] [int] IDENTITY(1,1) NOT NULL,  
  78.     [FirstName] [nvarchar](100) NOT NULL,  
  79.     [LastName] [nvarchar](100) NOT NULL,  
  80.     [Gender] [nvarchar](10) NOT NULL,  
  81.     [CreatedBy] [intNOT NULL,  
  82.     [CreatedDate] [datetime] NOT NULL,  
  83.     [ModifiedBy] [intNULL,  
  84.     [ModifiedDate] [datetime] NULL,  
  85.  CONSTRAINT [PK_Employee] PRIMARY KEY CLUSTERED   
  86. (  
  87.     [EmployeeId] ASC  
  88. )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ONON [PRIMARY]  
  89. ON [PRIMARY]  
  90.   
  91. GO  
  92. ALTER TABLE [dbo].[Employee] ADD  CONSTRAINT [DF_Employee_CreatedDate]  DEFAULT (getdate()) FOR [CreatedDate]  
  93. GO 
Advantages of Stored Procedures

The following are some of the advantages of using Stored Procedures.
  1. Stored Procedures are complied when created and stored in executable format. So Stored Procedures calls are quick and efficient.

  2. The maintenance of Stored Procedures are very easy and independent of the application since it's stored in the separate database server.

  3. These can be tested individually at the database server (no dependency on application).

  4. You can re-use the Stored Procedure among applications.

  5. You can see the execution plan for the Stored Procedures and if required you can add indexes and other changes for performance improvement.

  6. You can do the modifications and deployments to the Stored Procedure directly at the database server (independent of the application).

  7. Stored Procedures provide better security in terms of SQL Injection attacks and other user-based roles and so on.

Drawbacks

Using a Stored Procedures in a correct scenario as previously explained in a relevant manner doesn't cause any problems. Eventhough the Stored Procedure are not the following types:

  1. When you are going to do some operations, using loops (CURSOR) is not preferred since it causes performance effects.

  2. The other scenario is that you have defined your application core logic in a Stored Procedure of SQL Server. After some period of time or some other requirement, the client has decided to migrate the database from SQL Server to Oracle, then the migration of Stored Procedures is not such a straight forward job since some of the keywords in Oracle are not the same as in SQL Server.

Conclusion

This article explained when to choose Stored Procedures, what is to be considered when creating a Stored Procedure with a template and also the definition of a sample Stored Procedure.