Professional Documents
Culture Documents
Number:
STD-DMS009
Domain:
Category:
Data
Date Issued:
Date Revised:
James Weaver, Dir of Div of Tech Engineering
Abstract:
The purpose of this document is to detail and give examples of Microsoft Structured Query
Language (MS SQL) development standards followed at Department of Public Welfare (DPW).
General:
Coding standards are conventions and methods developers follow when developing, editing or
maintaining program code. Better programming style, developer understanding, readability and
reduced application development time are the results of following coding standards.
Database Modeling Environment
CA AllFusion ERwin Data Modeler is the standard tool for designing and modeling SQL Server
2008 databases.
All models will be reviewed by Database Management Section.
All completed models will be stored in the model repository.
Database Data Definition Environment
Microsoft SQL Server Management Studio is the standard tool to use for the execution and
modification of Data Definition Language (DDL) for the development of SQL Server 2008
databases. The general process is:
1. Initially generate a DDL from ERwin using forward engineering, or if required, create
DDL statements manually within Management Studio
Page 1 of 37
2. Execute the DDL within Management Studio and, if necessary, edit and/or tune the
statements using the Management Studio environment
3. Reverse engineer the database back into ERwin to keep the two synchronized
Store revised data models and all DDL scripts within Visual Source Safe or Team Foundation
Server. The DDL scripts will be stored in a consistent manner under the project folder within
Visual Source Safe or Team Foundation Server.
Database Programming Environment
Use SQL Server 2008 Management Studio to code and test stored procedures and triggers.
Prototype every process using t-sql within SQL Server Management Studio prior to creating a
new stored procedure, view, function or trigger. This will result in ease of debugging.
Use Execution Plans
Estimated Execution plans should be used while developing T-SQL
Actual Execution plans need to be included in the migration packet
Use Database Engine Tuning Advisor
SQL Server DBAs and analysts will use this tool to determine if additional keys or
indexes may be required. Creation of the additional objects will be determined and
executed by database administrators and analysts.
General Import/Export File Rules
All files imported to and exported from SQL Server 2008 must be delimited. Although commas,
hyphens, semicolons and other characters can be used to delimit files, only a vertical bar (|
or pipe) will be allowed, no exceptions. Using other characters introduces the possibility of
that character being embedded as valid data within a text or large variable character column. A
vertical bar is less likely to be valid data.
Commenting Guidelines
These rules apply in general to all source files.
Object Header Usage
Include object headers in every source code file.
Object Maintenance Documentation
Include object maintenance documentation in every source code file. Keep this
documentation current on all revisions after moving any given source file into production.
Before initial migration into production, revision information is not required.
Comment Quality
Page 2 of 37
Comments must contain a description of the process the SQL module (source file),
procedure, or trigger accomplishes. Write the description in clear, concise, non-colloquial
English, using business terms to describe the processes.
Every object contains an object header. An object header contains the database name, object
name, creation date, author, a brief description of the object, parameters passed, returns,
calling mechanism, tables and aliases used in code, other procedures called, DPSR #, notes,
and any special comments and warnings. Module headers remain open on the right-hand side.
Documentation for Object Maintenance
This section describes how to document changes in the Transact-SQL source code. The
method involves using a maintenance documentation heading and comments within the
source code. A common developer signature provides these together.
Object Maintenance Documentation
Immediately following the object header there is a skeletal maintenance block. Use this
skeletal block as a template for maintenance done to the object code. Copy, paste, and fill
in this block when you alter the object code. The block copy marks are on the lines with the
equal signs. Include the lines with the block copy marks.
Make the insertion of the copied block directly after the skeleton block. Thus, the history is
recorded from earliest to latest.
Developer Modification Signature
MS SQL Server 2008 Naming and Coding Standard.doc
Page 3 of 37
Include the developer modification signature in the comment block or function header within
the module that you (the developer) have altered. This gives future developers an easy trail
to follow on what changes have been made and by whom. The signature must contain the
developers three initials followed by the version id, and the number corresponding to the
change of request number, all encompassed within a pair of braces. An example developer
signature follows:
{RHP: 07.01:01}.
------ --------- --|
|
|
|
|
Change ID
|
Version/Release
Developer Initials
Example of OBJECT HEADER AND MAINTENANCE DOCUMENTATION
/*****************************************************************
*
Database:
LIHEAP2000
*
Procedure Name: USP_VENDOR_FILE_DATA
*
Date:
10/02/2002
*
Author:
Steve Jones
*
Procedure Desc:
This proc. returns data required for electronic vendor
*
payment files, currently being sent to vendors in
*
tape format to the top 10 vendors.
*
Parameters:
@idn_vendorAS VARCHAR(10) Vendor ID
*
@nbr_vt_recent AS VARCHAR(15)
Recent VT#
*
@cde_hdr_ftr
AS VARCHAR(10)
*
HEADER/DETAIL/FOOTER
*
Returns:
A recordset with detailed listing of clients with
*
each vendor
*
Calling Mechanism: DTS Package
*
Tables and Alias
T_VOU_TRNSMTL TVT
*
Definitions:
T_VENDOR TV
*
T_APPLN_PMT TAP
*
T_APPLN TA
*
T_VENDOR_EFT_INFO
*
T_STATUS_EFT_MODE
*
Procedures Used: USP_SAVE_ERROR
*
DPSR #:
017480
*
Notes:
*
1. Copyright (c) 2001 Pa Department of Welfare
*
Special Comments/Warnings:
*
None
*
******************************************************************
*
Version:
01.01
Page 4 of 37
*
Author:
Sumit Dua
*
Date:
12/24/2002
*
DPSR #:
******************************************************************
*
Description of Requests:
*
1. SSN is missing leading 0s
*
Description of Modifications:
*
1. See {SDU:01.01:01} for Coding Changes
*
Special Comments:
*
None
*
Other modules changed with this request:
*
*****************************************************************/
Source Modification Tags
As the developer, after creating a object Maintenance Documentation block, use the
developer modification signature(s) to identify changes to the source code that were made
as per that object maintenance documentation block. Additionally, include a note describing
the change. Together, the signature and note constitute a source modification tag. Use
these tags to record minor level comments. The example segment of source that follows
shows the use of the developer modification signature shown in the above section object
maintenance documentation to record the changes that the developer has applied.
:
:
:
-- {SDU:01.01:01} Make SSN 15 characters
app.NBR_SSN AS VARCHAR(15)
-- {SDU:01.01:01} Put leading zeros back on SSN
RIGHT('000000000' + LTRIM(RTRIM(CAST(
app.NBR_SSN AS VARCHAR(9)))), 9) AS VARCHAR(15)
:
:
:
Major Line-Level Commenting
Line-level code commenting is any other type of commenting that does not fall under object
headers. Major line-level commenting helps clarify where the logic of a certain procedure starts
and ends. Typical instances where major line-level commenting can be used are with
initialization routines, blocks of code which server a logical grouping, validation routines, errorhandling routines, exit routines, and so forth.
Page 5 of 37
Create major line-level comments in semi-boxes (open on the right) with a multi-line
commenting style. Write a very brief description of the process about which you are
commenting. For detailed explanations, use the major line-level comment block with the minor
line-level comment block (described in the subsequent section).
The routine described in major line-level commenting continues until encountering another
major line-level comment. An example of major line-level commenting follows:
/**********************************************************************
* Initializations
**********************************************************************/
DECLARE @MyStatus AS Integer
SELECT @MyStatus = 0
:
:
:
/**********************************************************************
* Perform Validations
**********************************************************************/
An example of commenting where a logical break is identified and described follows:
/**********************************************************************
* Process Status Code
**********************************************************************/
--- The following code processes the StatusCode parameter by
-- extracting the StatusResolution from the tblSatatus table and
-- verifying that the status is valid with the action parameter.
-IF @StatusCode <> ""
Minor Line-level Commenting
Do not put comments on the same line as the code. Examples of this illegal style follow:
DECLARE @IsNew AS Integer
- Is New Flag
DECLARE @Firstname AS VARCHAR(32) -- First Name Field
Insert all comments for a particular section of code before the code block, with one
blank comment line before and after the comment. An example follows:
--- Declare the local working variables
-DECLARE @IsNew AS Integer
MS SQL Server 2008 Naming and Coding Standard.doc
Page 6 of 37
Page 7 of 37
Examples of the right way to write a Transact-SQL statement follows. Specify each field as
in the examples:
SELECT
@dte_vt_date = dte_record_crtd
FROM T_VOU_TRNSMTL
WHERE nbr_vt = @nbr_vt_recent
SELECT
pmt.IDN_APPLN_PMT,
pmt.AMT_BNFT
FROM
T_APPLN_PMT pmt
INNER JOIN
ON
T_VOU_TRNSMTL vt
vt.IDN_TRNSMTL_VOU =pmt.IDN_TRNSMTL_VOU
Compound Statements
Compound statements are those that are encased within a BEGINEND structure.
Formatting rules for this structure are as follows:
1. The BEGIN statement aligns directly under the statement above.
2. The END statement is aligned in the same position as its corresponding BEGIN
statement.
3. Within the BEGINEND structure, statements are indented one full tab stop.
IFELSE Statement Blocking
Treat all IF statements (and block ifs) as if they were compound statements using the
BEGINEND structure. No exceptions are permitted.
An example follows:
IF @@ROWCOUNT < 1
BEGIN
RETURN -1
END
ELSE
BEGIN
SELECT @RowReturned = @@ROWCOUNT
RETURN 0
MS SQL Server 2008 Naming and Coding Standard.doc
Page 8 of 37
END
usp_MyStoredProcedure
@MyParameter1,
@MyParameter2,
@MyParameter3 OUTPUT,
@MyParameter4 OUTPUT
Page 9 of 37
4. If the length of the keyword or keywords (ex: SELECT DISTINCT and ORDER
BY) equals or exceeds the tab stop setting (8), the parameter is placed on the
subsequent line at the proper indent position
5. Parentheses are used to distinguish logical blocks and are indented at the same level as
any other parameter.
Page 10 of 37
idn_user_crtd = @ModifiedUser
WHERE nbr_vendor = @VendorID
T_FIPS_CODE
Column Naming
All column names will follow the current DPW naming conventions.
View Naming
All view names will consist of the prefix VW_ followed by business function they perform
or business rule they enforce.
Example: VW_SEL_T_FIPS_CODE
Page 11 of 37
Variable Formats
All variable names should be defined in a consistent manner across all the programs.
To ensure consistency with the database, variables include the appropriate class word
in the name.
Local Variables: <Class Word>_<Variable Name>
e.g. NBR_INDIV
Parameters: <P>_<Class Word>_<Variable Name>
e.g. P_CNT_INDIV
Global Variables: <G>>_<Class Word>_<Variable Name>
e.g. G_NBR_SSN
Cursors: <Cursor Name>_cur
e.g. ACTIVE_INDIV_CUR
Stored Procedures
When coding enterprise applications, the use of stored procedures to separate application
logic from database code has been found beneficial. Stored procedures will be used for any
data access (SELECT) or manipulation (INSERT, DELETE, UPDATE).
The advantages include:
Stored procedures should be named according to the business function they perform or
business rule they enforce. The name should include a prefix of USP and a business
description of the action performed. The name should be appropriately abbreviated with items
found in the standard abbreviation list. An example of a procedure name would be
USP_ADD_NEW_T_INDIV. As the name implies, this procedure would add a new row to the
T_INDIV table.
Page 12 of 37
Triggers
Triggers and sequences should be used to populate artificial keys within a table. Triggers
should also be used to populate the auditing timestamp column on the table.
The naming standard of triggers in the database is defined with concatenation of a trigger
identity string of TR, a one-character trigger event code, a two-character trigger operation
code, a two-character trigger type code, and a descriptive string of table specific information
related to the trigger. The concatenation is undertaken by an underscore between these five
portions of the name. If a particular database does not support one of these descriptors (i.e.
Trigger Event Code), it may be omitted. Definition of the three codes is through following
conventions:
1. Trigger Event Code:
B for BEFORE trigger event, and
A for AFTER trigger event.
2. Trigger Operation Code:
IN for INSERT operation,
UP for UPDATE operation, and
DE for DELETE operation
NS for INSTEAD operation (redirect statement to effect other objects INSTEAD of the
object listed).
LO for Database level operations that occur upon logon
LF for Database level operations that occur upon logoff
ST for Database level operations that occur upon database startup
SD for Database level operations that occur upon database shutdown
ER for operations that occur upon detection of an error condition
SC for schema level operations (typically DDL execution)
3. Trigger Type Code:
RW for ROW LEVEL trigger type, (triggers that are executed for every row affected
during the transaction)
ST for STATEMENT LEVEL trigger types (triggers that execute only one for a
particular transaction no matter how many rows are affected).
For example, if you have a trigger with BEFORE event, for INSERT operation, of ROW LEVEL
type, and acting on a table of APPLN, the trigger will be named as TR_B_IN_RW_APPLN.
Database Rules
Rules are a backward-compatibility feature that perform some of the same functions as
CHECK constraints. Using CHECK constraints is the preferred, standard way to restrict the
values in a column. CHECK constraints are also more concise than rules. There can be only
one rule applied to a column, but multiple CHECK constraints can be applied. CHECK
Page 13 of 37
constraints are specified as part of the CREATE TABLE statement, while rules are created as
separate objects and then bound to the column.
Constraints
Planning and creating tables requires identifying how to enforce integrity of the data stored
within the columns of the tables. MS SQL Server 2008 has the following constraints to enforce
integrity:
Primary Key Constraints are columns or a column that uniquely identifies a row within
a table. All tables should have a primary key and composite primary keys should be
avoided. Primary keys should be named PK_tablename_columnname.
Example: PK_T_ADDRESS_IDN_ADDR.
Foreign Key Constraints are columns or a column that is used to enforce a relation
between information in two tables. A link is defined between the two tables when a
primary key is referenced by a column or columns in another table. The reference
becomes a foreign key in the second table. Foreign keys should be named
FK_foreignkeytable_primarykeytable_columnname.
Example: FK_T_NAME_T_ADDRESS_IDN_ADDR.
Unique Constraints are columns or a column defined on a table to ensure that no
duplicate values can exist. Unique constraints can be used to enforce uniqueness of
data on columns that are not a primary key. More than one unique constrain can be
defined on a table. Unique constraints should be named UCON_
tablename_columnname.
Example: UCON_T_ADDR_IDN_ADDR.
Check Constraints are created to limit values that can be entered in a column or
columns. Unlike foreign key constraints, a check constraint determines valid data from a
logical expression. Check constraints can be used to limit valid data entries to a range.
Check constraints should be named CKCON_ tablename_columnname.
Example: CKCON_T_ADDR_STATE.
Indexes
An index is an on-disk structure associated with a table or a view that speeds retrieval of rows
from the table or the view. An index contains keys built from one or more columns in the table
or the view. These keys are stored in a structure (B-tree) that enables SQL Server to find the
row or rows associated with the key values quickly and efficiently.
A table or view can contain the following types of indexes:
Page 14 of 37
Clustered
o
Clustered indexes sort and store the data rows in the table or view based on their
key values. These are the columns included in the index definition. There can be
only one clustered index per table, because the data rows themselves can be
sorted in only one order.
The only time the data rows in a table are stored in sorted order is when the table
contains a clustered index. When a table has a clustered index, the table is
called a clustered table. If a table has no clustered index, its data rows are stored
in an unordered structure called a heap.
Nonclustered
o
The pointer from an index row in a nonclustered index to a data row is called a
row locator. The structure of the row locator depends on whether the data pages
are stored in a heap or a clustered table. For a heap, a row locator is a pointer to
the row. For a clustered table, the row locator is the clustered index key.
IDX_T_ADDR_STATE_STATE
Default Definitions
Default Definitions are predefined values created on columns within a table. The default
value will be used when inserting a new row in a table and a particular column in the
insert statement does not have a value. For example you may have a default of all
99999999 that you may want to set up as a default end date. The default should have a
prefix of D_ followed by a description of what the default does. All words should be run
together and not be separated by underscores.
Example: D_OPENDATE
Allowing Null Values is used when a column in a row can contain a null value. NULL is a
value either unknown or undefined and typically means no entry has been made. Avoid
permitting null values within columns.
User Defined Data Types
User defined Data Types are predefined variable lengths. For example instead of having to
always specify that SSN is a numeric field of 10 positions, you could create a user defined data
type entitled udt_ssn. Therefore, when you need to use SSN, you would just specify udt_ssn
Page 15 of 37
as the data type and all the relevant information would not have to be reentered. The user
defined data type should have a prefix of UDT_ followed by a description of what the data type
is supposed to standardize. All words should run together and not be separated by
underscores.
Example: UDT_CITY
Page 16 of 37
A TRY block starts with the BEGIN TRY statement and ends with the END TRY statement.
One or more Transact-SQL statements can be specified between the BEGIN TRY and END
TRY statements.
A TRY block must be followed immediately by a CATCH block. A CATCH block starts with the
BEGIN CATCH statement and ends with the END CATCH statement. In Transact-SQL, each
TRY block is associated with only one CATCH block.
It is highly recommended that the return variables from any error trapping be returned to the
application and processed at the application. Avoid processing an exception or error that
causes the application to abnormally end.
Working with TRYCATCH
When you use the TRYCATCH construct, consider the following guidelines and suggestions:
TRYCATCH constructs can be nested. This means that TRYCATCH constructs can
be placed inside other TRY and CATCH blocks. When an error occurs within a nested
TRY block, program control is transferred to the CATCH block that is associated with
the nested TRY block.
To handle an error that occurs within a given CATCH block, write a TRY...CATCH
block within the specified CATCH block.
Page 17 of 37
Errors that have a severity of 20 or higher that cause the Database Engine to close the
connection will not be handled by the TRYCATCH block. However, TRYCATCH will
handle errors with a severity of 20 or higher as long as the connection is not closed.
Attentions will terminate a batch even if the batch is within the scope of a TRYCATCH
construct. This includes an attention sent by the Microsoft Distributed Transaction
Coordinator (MS DTC) when a distributed transaction fails. MS DTC manages
distributed transactions.
Error Functions
TRYCATCH uses the following error functions to capture error information:
ERROR_MESSAGE() returns the complete text of the error message. The text includes
the values supplied for any substitutable parameters such as lengths, object names, or
times.
ERROR_LINE() returns the line number inside the routine that caused the error.
ERROR_PROCEDURE() returns the name of the stored procedure or trigger where the
error occurred.
Error information is retrieved by using these functions from anywhere in the scope of the
CATCH block of a TRYCATCH construct. The error functions will return NULL if called
outside the scope of a CATCH block. Error functions can be referenced inside a stored
procedure and can be used to retrieve error information when the stored procedure is
executed in the CATCH block. By doing this, you do not have to repeat the error handling code
in every CATCH block. In the follow code example, the SELECT statement in the TRY block
will generate a divide-by-zero error. The error will be handled by the CATCH block, which uses
a stored procedure to return error information.
USE AdventureWorks;
GO
-- Verify that the stored procedure does not exist.
IF OBJECT_ID ('usp_GetErrorInfo', 'P') IS NOT NULL
DROP PROCEDURE usp_GetErrorInfo;
Page 18 of 37
GO
-- Create a procedure to retrieve error information.
CREATE PROCEDURE usp_GetErrorInfo
AS
SELECT
ERROR_NUMBER() AS ErrorNumber,
ERROR_SEVERITY() AS ErrorSeverity,
ERROR_STATE() as ErrorState,
ERROR_PROCEDURE() as ErrorProcedure,
ERROR_LINE() as ErrorLine,
ERROR_MESSAGE() as ErrorMessage;
GO
BEGIN TRY
-- Generate divide-by-zero error.
SELECT 1/0;
END TRY
BEGIN CATCH
-- Execute the error retrieval routine.
EXECUTE usp_GetErrorInfo;
END CATCH;
GO
Compile and Statement-level Recompile Errors
There are two types of errors that will not be handled by TRYCATCH if the error occurs in
the same execution level as the TRYCATCH construct:
Compile errors, such as syntax errors that prevent a batch from executing.
Errors that occur during statement-level recompilation, such as object name resolution
errors that happen after compilation due to deferred name resolution.
When the batch, stored procedure, or trigger that contains the TRYCATCH construct
generates one of these errors, the TRYCATCH construct does not handle these errors.
These errors will return to the application or batch that called the error-generating routine. For
example, the following code example shows a SELECT statement that causes a syntax error.
If this code is executed in the SQL Server Management Studio Query Editor, execution will not
start because the batch fails to compile. The error will be returned to the Query Editor and will
not get caught by TRYCATCH.
USE AdventureWorks;
GO
BEGIN TRY
MS SQL Server 2008 Naming and Coding Standard.doc
Page 19 of 37
USE AdventureWorks;
GO
BEGIN TRY
-- This PRINT statement will run because the error
-- occurs at the SELECT statement.
PRINT N'Starting execution';
-- This SELECT statement will generate an object name
-- resolution error because the table does not exist.
SELECT * FROM NonExistentTable;
END TRY
BEGIN CATCH
SELECT
ERROR_NUMBER() AS ErrorNumber,
ERROR_MESSAGE() AS ErrorMessage;
END CATCH;
GO
Page 20 of 37
You can use TRYCATCH to handle errors that occur during compilation or statement-level
recompilation by executing the error-generating code in a separate batch within the TRY block.
For example, you do this by placing the code in a stored procedure or by executing a dynamic
Transact-SQL statement using sp_executesql. This allows TRYCATCH to catch the error at
a higher level of execution than the error occurrence. For example, the following code shows a
stored procedure that generates an object name resolution error. The batch that contains the
TRYCATCH construct is executing at a higher level than the stored procedure; and the error,
which occurs at a lower level, is caught.
USE AdventureWorks;
GO
-- Verify that the stored procedure does not already exist.
IF OBJECT_ID ('usp_MyError', 'P') IS NOT NULL
DROP PROCEDURE usp_MyError;
GO
CREATE PROCEDURE usp_MyError
AS
-- This SELECT statement will generate
-- an object name resolution error.
SELECT * FROM NonExistentTable;
GO
BEGIN TRY
-- Run the stored procedure.
EXECUTE usp_MyError;
END TRY
BEGIN CATCH
SELECT
ERROR_NUMBER() AS ErrorNumber,
ERROR_MESSAGE() AS ErrorMessage;
END CATCH;
GO
Here is the result set.
ErrorNumber ErrorMessage
----------- --------------------------------------208
Invalid object name 'NonExistentTable'.
Page 21 of 37
Handling Deadlocks
TRYCATCH can be used to handle deadlocks. The 1205 deadlock victim error can be
caught by the CATCH block and the transaction can be rolled back until the threads become
unlocked
The following example shows how TRYCATCH can be used to handle deadlocks. This first
section creates a table that will be used to demonstrate a deadlock state and a stored
procedure that will be used to print error information.
USE AdventureWorks;
GO
-- Verify that the table does not exist.
IF OBJECT_ID (N'my_sales',N'U') IS NOT NULL
DROP TABLE my_sales;
GO
-- Create and populate the table for deadlock simulation.
CREATE TABLE my_sales
(
Itemid
INT PRIMARY KEY,
Sales
INT not null
);
GO
INSERT my_sales (itemid, sales) VALUES (1, 1);
INSERT my_sales (itemid, sales) VALUES (2, 1);
GO
-- Verify that the stored procedure for error printing
-- does not exist.
IF OBJECT_ID (N'usp_MyErrorLog',N'P') IS NOT NULL
DROP PROCEDURE usp_MyErrorLog;
GO
-- Create a stored procedure for printing error information.
CREATE PROCEDURE usp_MyErrorLog
AS
PRINT
'Error ' + CONVERT(VARCHAR(50), ERROR_NUMBER()) +
', Severity ' + CONVERT(VARCHAR(5), ERROR_SEVERITY()) +
', State ' + CONVERT(VARCHAR(5), ERROR_STATE()) +
', Line ' + CONVERT(VARCHAR(5), ERROR_LINE());
PRINT
Page 22 of 37
ERROR_MESSAGE();
GO
The following code scripts for session 1 and session 2 run simultaneously in two separate SQL
Server Management Studio connections. Both sessions try to update the same rows in the
table. One of the sessions will succeed with the update operation during the first attempt, and
the other session will be selected as the deadlock victim. The deadlock victim error will cause
execution to jump to the CATCH block and the transaction will enter an uncommittable state.
Inside the CATCH block, the deadlock victim can roll back the transaction and retry updating
the table until the update succeeds or the retry limit is reached, whichever happens first.
Session 1
Session 2
USE AdventureWorks;
GO
USE AdventureWorks;
GO
UPDATE my_sales
SET sales = sales + 1
WHERE itemid = 1;
UPDATE my_sales
SET sales = sales + 1
WHERE itemid = 2;
UPDATE my_sales
SET sales = sales + 1
WHERE itemid = 2;
UPDATE my_sales
SET sales = sales + 1
WHERE itemid = 1;
SET @retry = 0;
SET @retry = 0;
Page 23 of 37
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
-- Check error number.
-- If deadlock victim error,
-- then reduce retry count
-- for next update retry.
-- If some other error
-- occurred, then exit
-- retry WHILE loop.
IF (ERROR_NUMBER() = 1205)
SET @retry = @retry - 1;
ELSE
SET @retry = -1;
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
-- Check error number.
-- If deadlock victim error,
-- then reduce retry count
-- for next update retry.
-- If some other error
-- occurred, then exit
-- retry WHILE loop.
IF (ERROR_NUMBER() = 1205)
SET @retry = @retry - 1;
ELSE
SET @retry = -1;
Page 24 of 37
Note:
RAISERROR can generate errors with state from 1 through 127 only. Because the Database
Engine might raise errors with state 0, we recommend that you check the error state returned
by ERROR_STATE before passing it as a value to the state parameter of RAISERROR.
USE AdventureWorks;
GO
-- Verify that stored procedure does not exist.
IF OBJECT_ID (N'usp_RethrowError',N'P') IS NOT NULL
DROP PROCEDURE usp_RethrowError;
GO
-- Create the stored procedure to generate an error using
-- RAISERROR. The original error information is used to
-- construct the msg_str for RAISERROR.
CREATE PROCEDURE usp_RethrowError AS
-- Return if there is no error information to retrieve.
IF ERROR_NUMBER() IS NULL
RETURN;
DECLARE
@ErrorMessage NVARCHAR(4000),
@ErrorNumber INT,
@ErrorSeverity INT,
@ErrorState
INT,
@ErrorLine
INT,
@ErrorProcedure NVARCHAR(200);
-- Assign variables to error-handling functions that
-- capture information for RAISERROR.
SELECT
@ErrorNumber = ERROR_NUMBER(),
@ErrorSeverity = ERROR_SEVERITY(),
@ErrorState = ERROR_STATE(),
@ErrorLine = ERROR_LINE(),
@ErrorProcedure = ISNULL(ERROR_PROCEDURE(), '-');
MS SQL Server 2008 Naming and Coding Standard.doc
Page 25 of 37
Page 26 of 37
BEGIN TRY
BEGIN TRY
SELECT CAST('invalid_date' AS datetime)
END TRY
BEGIN CATCH
PRINT 'Inner TRY error number: ' +
CONVERT(varchar,ERROR_NUMBER()) + ' on line: ' +
CONVERT(varchar, ERROR_LINE())
END CATCH
SELECT CAST('invalid_int' AS int)
END TRY
BEGIN CATCH
PRINT 'Outer TRY error mumber: ' + CONVERT(varchar,ERROR_NUMBER())+
' on line: ' + CONVERT(varchar, ERROR_LINE())
END CATCH
Custom Error Messages
Generation of custom error messages for use by procedures and triggers is optional but highly
recommended.
Page 27 of 37
Transact-SQL Restrictions
Following is SQL Server functionality that should not be used when developing procedures or
triggers.
Cursors
Do not use cursors without adequate justification and the consent of the Database
Administrators. Use alternatives to cursors wherever possible, including: temp tables, table
variables, redefinition of logic, and exterior 3GL coding (for example: a Visual Basic
program or process).
When a cursor is declared with a FOR UPDATE clause, it is recommended to specify a
column list. SQL Server can optimize operations based on column list information
available. A future release of SQL Server may have tighter requirements on specification of
updateable columns.
Please make sure to use FOR UPDATE clause when updates are done through the cursor.
When a cursor is declared with a FOR UPDATE clause and no updates occur through the
cursor do not use the FOR UPDATE statement.
Result Sets for Qualified Transactions
Develop procedures so that each procedure will return a maximum of one result set, if the
procedure will be used with qualified transactions.
Result Sets for Non-Qualified Transactions
It is recommended that, when developing procedures, create each procedure so that it
returns only one result set, when that procedure is for use with non-qualified transactions.
Page 28 of 37
ANSI_NULLS
ANSI_PADDING
ANSI_WARNINGS
ARITHABORT
CONCAT_NULL_YIELDS_NULL
QUOTED_IDENTIFIERS
Page 29 of 37
NUMERIC_ROUNDABOUT
Page 30 of 37
Database Administrators will check stored procedures, functions, views and triggers for
use of ORDER BY clause specifying ordinal column numbers as sort columns.
As an example, the following syntax is not allowed:
SELECT au_id FROM dbo.authors ORDER BY 2, 1
The use of ordinal column numbers will not be allowed.
Schema Usage
Database Administrators will check stored procedures, functions, views and triggers for
use of schema qualified names when referencing tables and views.
Unless specified otherwise, all Transact-SQL references to the name of a database object
can be a four-part name in the form:
[
server_name.[database_name].[schema_name].
| database_name.[schema_name].
| schema_name.
]
]
When referencing a specific object, you do not always have to specify the server,
database, and owner (schema) for SQL Server to identify the object. However, it is
recommended that at least the schema name be specified to identify a table or view inside
a stored procedure, function, view or trigger.
When SQL Server looks up a table/view without a schema qualification, it first looks in the
default schema and then looks in the 'dbo' schema. The default schema corresponds to
the current user for adhoc batches, and corresponds to the schema of a stored procedure
when inside one. In either case, SQL Server incurs an additional runtime cost to verify
schema binding of unqualified objects. Applications are more maintainable and may
experience a slight performance improvement if object references are schema qualified.
Top without Order By
Database Administrators will check stored procedures, functions, views and triggers for
usages of TOP in queries without an ORDER BY clause.
It is generally recommended to specify sort criteria when using TOP clause. Otherwise, the
results produced will be plan dependant and may lead to undesired behavior.
With Hint Specification
Database Administrators will check stored procedures, triggers, views and functions for
use of table hints without the WITH keyword.
Hints must be specified using the WITH keyword.
Avoid Stored Procedure Recompiles
See next section.
Page 31 of 37
Performance Recommendations
General Considerations
Connections to the SQL Server database should be brief. A connection should be made,
a process completed and the connection dropped. No persistent connections to SQL
Server are allowed.
Stored procedures should perform one process and not a series of process. It is better to
create a stored procedure that performs an insert rather than a stored procedure that
performs an insert, update and a delete. Executing multiple stored procedures is preferred
over executing one, unwieldy, multi-task stored procedure.
Stored Procedure Recompiles
No stored procedures should interleave Data Definition Language (DDL) and Data
Manipulation Language (DML) operations. In other words, do all CREATE/DROP
statements separate from SELECT and UPDATE statements. If data operations are mixed,
the SQL server must recompile procedures each time to determine the best plan to use for
each new or dropped object. Therefore, coding all creates and drops together will reduce
the amount of stored procedure compiles. Avoid creating a temporary table in a control-offlow statement such as an IFELSE or WHILE statement. Avoid using a DROP statement
for temporary tables in stored procedures, because tables are automatically dropped when
the procedure is completed. Specifying the owner of objects such as dbo.Tablename and
dbo.Stored procedure name will cut down on recompiles.
Temporary Tables
Often procedure throughput can be dramatically improved by the use of temporary tables.
Restructuring a Transact-SQL statement that involves lengthy and/or complicated joins to
perform the same functionally by multiple actions against a temp table will improve
performance. Please note: use a temporary table to manipulate small amounts of data,
Page 32 of 37
and if data exceeds 500 records add an index. Also if you have > 6 data changes in a
temporary table consider using the option (keep plan) to avoid unnecessary recompiles.
Table Variable Type
The table variable type functions exactly like the temporary table, with the exception that all
data is loaded directly in random access memory.
Temporary Tables vs. Table Variable
Database Administrators will check stored procedures and triggers for usages of temporary
tables that may be replaced by use of table variables.
When a procedure creates a temporary table and has no CREATE INDEX issued on it, and
it is dropped all in the same procedure, you will be asked to consider using table variables
instead to potentially observe fewer recompilations.
Note that if large data volumes will be inserted in the temporary table it may still be
preferred to use temporary tables over table variables due to parallel execution restrictions
and statistics maintenance.
Dynamic SQL Execution
Where possible use the stored procedure sp_executesql to execute dynamic code rather
then the straight exec command. The procedure sp_executesql should be used instead of
the exec command to execute a Transact-SQL statement a number of times when the
change in parameter values to the statement is the only variation. This is because the
Transact-SQL SQL Server query optimizer is likely to reuse the execution plan it generates
for the first execution.
Table Hints
Consider using Table Hints to optimize performance.
Join Hints
Consider using Join Hints to optimize performance.
Indexes
Examine the performance of the statements within the procedure and the entire application
to determine if an additional index will justify its overhead. Consider overall index usage all
along the development path. Indexes, or lack of indexes, are the direct cause of poor
performance 90% of the time. As per Microsofts suggestion, all tables that have more then
500 records should have a clustered index, even if a field is created just to hold the index.
Please note when setting an index, pay close attention to the fill factor for the given index.
The fill factor is the amount space consumed by the index and more importantly the amount
of space that will be kept free for expansion. For an example a 90% fill factor is 90% full
with 10% left for expansion. For tables that do a high volume of inserts, updates, deletes
you may want to consider a lower fill factor, or perhaps not having a clustered index at all.
A clustered index will slow down inserts but speed up selects. The developer should
determine what the best trade off is.
Page 33 of 37
Ultimately, it is the responsibility of the developer coding the stored procedures and the
SQL code to determine what the best indexes are and how they should be used.
Execution Plan
When debugging and tuning a stored procedure, examine the execution plan for clues as to
the performance of the procedure and how it may be improved.
In the example below, a table scan is being generated. From this, one should ask if another
index should be created to avoid the scan. If yes, create an index and rerun.
All table scans should be thoroughly documented. An example execution plan should be
checked into Source Safe or Team Foundation Server as well as the sql code checklist and
changed as the code changes. If there are various scenarios be sure to submit all of the
various paths, especially the worst case path. See the execution plan example doc below on
how to format the plan for submission to DBA.
SQL Profiler/Database Engine Tuning Advisor
Two valuable and necessary tools when tracking and or monitoring performance are SQL Profiler and
Database Engine Tuning Advisor. Only the DBA has permissions to run these two tools. The DBA can
analyze the output from these tools and give suggestions on what tables or objects have problems and
can benefit from index creation.
Programmatic Recommendations
This section provides recommendations to developers for improving the reliability of
procedures and triggers.
Use SET NOCOUNT
When developing procedures that return a result set and use intermediate processing, be
sure to set the SET NOCOUNT ON option to prevent the generation of unwanted result set
count information. Use the SET NOCOUNT OFF statement to restore result counting
before executing a SELECT statement to return results.
Stylistic Recommendations
Page 34 of 37
Naming Packages
The name of the SQL Server Integration Services package should indicate the database the
package belongs to as well as the purpose of the SSIS package. In a development
environment, the developer testing the package may own the package but in all other
environments SA (System Administrator) will own the package. The package may very well
have the same name as the job. The difference between a job and a package is that a job is a
scheduled package. A package on its own must be started manually. The package names can
be mixed case for ease of readability.
Example: CUSTOMERVendorExport
SQL Server 2008 Reporting Services
SQL Server 2008 Reporting Services (SSRS) is required when creating any reports for use at
the DPW.
Naming Reports
The name of the SQL Server 2008 Reporting Services object should indicate the database the
report belongs to as well as the purpose of the SSRS package. The report names can be
mixed case for ease of readability.
Example: CUSTOMERNameAndAddresses
Job Naming Standards
A job consists of a series of SQL Statements that are to be executed as a transaction (as one
complete unit). The name of a SQL SERVER job should indicate the database the job belongs
Page 35 of 37
to and the purpose of the job as well. In a development environment, the job may be owned by
the developer testing the job; but, in all other environments the SA will own the job. All jobs will
need to be approved by the DBA prior to being scheduled to run. The job names should be
mixed case for ease of readability.
Example: ACCOUNTINGImportDailyFiles
Page 36 of 37
2. Use the replace function to turn a single quote into two single quotes.
Ex. set @input = replace(@input,'''','''''')
By doing this we now insure that the developers intended code will run and the intruders code
will fail. If possible, the addition of an audit routine should be added to the procedure/
database to track when SQL Injection is attempted.
Version
Change Description
Author and
Organization
1.0
New document
Kiley Milakovic
12/11/2007
1.1
Matt Leitzel
01/13/2011
1.2
Matt Leitzel
06/20/2012
1.2
Rich Gill
Page 37 of 37