This topic describes SQL coding standards you may follow when working with databases and scripts.
SQL coding standards provide a consistent approach to writing clean code and scripts across SQL databases. These standards make your code readable, understandable, and organized. When working in teams, coding standards help reduce the risk of misinterpretation and ensure long-term maintainability in SQL environments.
These are rules for naming database objects, such as tables, columns, stored procedures, indexes, or views. Proper naming improves code readability, reduces confusion, and supports ongoing development.
CustomerOrder.FirstName, OrderDate.Note
Prefixes may include underscores.
Follow a consistent prefix pattern.
| Object type | Prefix | Naming convention | Example |
|---|---|---|---|
| Table | Contains a table name. | Customer |
|
| View | vw_ |
Followed by the table and view names. | vw_CustomerOrders |
| Stored procedure | usp_ |
Followed by a verb (Get, Delete, Update, Archive, Insert) and table name. |
usp_GetCustomer |
| Function | ufn_ |
Followed by a key attribute that describes what the function returns or calculates. | ufn_CalcOrderTotal |
| Trigger | trg_ |
Followed by a verb (action) and table name. | trg_UpdateTimestamp |
| Primary key column | Contains a primary key name. | ID |
|
| Primary key constraint | PK_ |
Followed by a table name. | PK_Customer |
| Foreign key constraint | FK_ |
Followed by the child and parent table names. | FK_Order_CustomerId |
| Unique constraint | UQ_ |
Followed by the table and column names. | UQ_Customer_Email |
| Check constraint | CK_ |
Followed by a table name and a description. | CK_Order_Amount |
| Clustered index | IXC_ |
Followed by the table and column names. | IXC_Customer_LastName |
| Nonclustered index | IX_ |
Followed by the table and column names or multiple column names if the index is composite. | IX_Order_CustomerId_OrderDate |
| Unique nonclustered index | UQ_ |
Followed by the table and column names. | UQ_Product_SKU |
Note
The prefixes
usp_,vw_,ufn_, andtrg_are still very common in legacy enterprise environments, but in modern greenfield projects - especially those using EF Core, Dapper, or microservices - they are increasingly being dropped because most teams now consider them visual noise.
tbl, or any other descriptive prefix.ID column for the primary key.PRIMARY KEY for each table unless there is a strong reason not to.ID as the primary key column name for identity columns.CreateCustomerTable.sql.#TempCustomer or ##GlobalTempCustomer.#Temp1 or #Data, that do not describe the purpose.Sales, Finance, or Audit, to separate them logically based on their purpose or business domain.Use nonclustered indexes to improve query performance for frequently filtered, sorted, or joined columns.
Clustered indexes define the physical ordering of data in a table and can be used for operations that require sequential data access.
BETWEEN, >, >=, <, or <=.ORDER BY or GROUP BY.Because the clustered index key is automatically included in every nonclustered index, larger clustered keys increase the size and storage cost of all related indexes. Therefore, select clustered index columns that have one or more of the following characteristics:
IDENTITY.RECOMPILE option unless there are specific requirements.DECLARE statement followed by a SET statement at the beginning of the code before its execution.SET NOCOUNT ON option at the beginning of SQL batches to improve the performance of stored procedures.INSERT or UPDATE, inside views.Note
Creating a view based on other views may slow down query performance.
If the structure of the underlying tables changes, the view must be updated accordingly.
Proper aliasing improves readability and makes complex queries easier to follow.
AS keyword for clarity.Consistent spacing improves readability and helps developers quickly understand code structure.
SELECT, FROM, WHERE, JOIN, GROUP BY, and ORDER BY, on their own lines.SELECT keyword.=, >, <, +.AND/OR conditions vertically in WHERE or JOIN clauses.( or before the closing character ).Using correct data types improves performance, ensures data accuracy, and reduces storage requirements.
TEXT, NTEXT, and IMAGE. Instead, use VARCHAR(MAX), NVARCHAR(MAX), and VARBINARY, respectively.The table provides a list of data types and their usage in SQL code.
| Data type | Usage |
|---|---|
INT |
Integer. |
BIGINT |
Integer requiring a very large range. |
SMALLINT |
Integer requiring a small numeric range. |
DATETIME2 |
Date and time values with higher precision. |
VARCHAR |
Variable-length character data. |
CHAR |
Fixed-length character data. |
MONEY |
Monetary values; use only when fixed precision is acceptable. |
DECIMAL |
Exact numeric values with fixed precision. |
REAL or FLOAT |
Approximate numeric values for scientific, statistical, or floating-point calculations. |
NUMERIC |
Fixed-point decimal numbers. |
TIME |
Time-only values (no date). |
NCHAR or NVARCHAR |
Unicode text for multilingual or international character sets. |
Specify default values for parameters or columns to ensure predictable behavior when inputs are missing.
NOT NULL statement.GETDATE(), for date and time defaults.NULL and NOT NULL values for each column; avoid relying on implicit defaults.NULL values impact performance, complicate the schema, and reduce index efficiency. Additionally, arithmetic expressions that involve NULL values, for example, NULL + 5 returns NULL, which can lead to unexpected results and errors in calculations.NULL values.ISNULL() or COALESCE() to process NULL values in calculations.IS NULL / IS NOT NULL instead of = NULL or <> NULL.NOT NULL + DEFAULT instead of NULL for date values whenever possible.NULL for numeric or text fields only when the absence of a value has a distinct semantic meaning. For example, Discount IS NULL indicates that a discount is not applicable or unknown, or Phone IS NULL indicates that no phone number is provided.NOT NULL + DEFAULT for numeric and string columns only when the default value has a clear and valid business meaning.NULL behaves in queries: In GROUP BY and DISTINCT clauses, all NULL values are considered equal, even though logical comparison (WHERE and ON) treats NULL = NULL as UNKNOWN.COUNT(column) ignores NULL values, while COUNT(*) counts all rows regardless of NULL values.WHERE Active = 1 excludes rows where Active IS NULL. Use ISNULL(), COALESCE(), or explicit conditions, such as Active = 1 OR Active IS NULL, when appropriate.NULL values in key columns, especially in foreign keys and columns involved in JOIN conditions.Coding standards ensure queries, such as SELECT, INSERT, UPDATE, and DELETE, are written clearly, correctly, and securely.
SELECT, FROM, and WHERE.SELECT, FROM, WHERE, GROUP BY, and ORDER BY, on a new line.AND, OR) on new lines.;) in SQL code as a statement terminator.SELECT * and list the required columns explicitly.GROUP BY to avoid extra processing.SELECT or WHERE clauses when alternative logic exists.WHERE clauses.WHERE clause before a HAVING clause.ORDER BY with multiple columns, arrange them in a logical order of importance (for example, from the most to the least significant grouping).UNION ALL instead of UNION.INNER, LEFT, RIGHT, and FULL).WITH clauses to improve readability over nested subqueries.;) in a batch.LIKE searches to prevent index scans.<> or NOT), as they often cause table or index scans.IF EXISTS instead of SELECT COUNT(*) to check record existence.EXISTS instead of IN to check for specific values.CAST over CONVERT for simple type conversions.CREATE TABLE instead of SELECT INTO whenever possible, since SELECT INTO can lock system objects in tempdb and is slower as it copies the table structure along with data.NOLOCK unless the specific use case and risks are understood.SET NOCOUNT ON at the beginning of SQL batches, stored procedures, and triggers.INSERT statements.Note
To verify compliance with best practices, design guidelines and naming conventions, use T-SQL Analyzer.
SQL coding standards help define when to use a type of the temporary object, how to name them, and how to manage their lifecycle for clarity and performance.
The table describes temporary objects used in SQL queries.
| Temporary object type | Visibility | Lifetime | Example |
|---|---|---|---|
| Table variables | Visible only within the session that creates the table variable. | Deleted when the batch ends. | DECLARE @t TABLE (...) |
| Local temporary tables | Visible only within the session that creates the local temporary table. | Deleted when the object created the local temporary table ends. Used commonly for stored procedures. |
CREATE TABLE #t (...) |
| Global temporary tables | Visible to all connections. | Deleted after all referencing connections are closed. | CREATE TABLE ##t (...) |
| Permanent tempdb tables | Visible to all users. | Exists until SQL Server restarts. | USE tempdb; CREATE TABLE t (...) |
| Common table expressions (CTEs) | Visible only within the statement. | Exists only within a single statement. | WITH cte AS (...) SELECT * FROM cte |
General rules
DROP TABLE when they are no longer required.CTEs vs. TempTable
| Aspect | Common Table Expressions (CTEs) | Temporary tables |
|---|---|---|
| Purpose | Improve readability and support recursion. | Re-use data or perform multiple processing passes. |
| Execution | Re-executed each time they are referenced. | Data is stored once; faster and more reliable re-use. |
| Performance | Used for small datasets or recursive queries. | Preferred for large datasets and repeated processing. |
| Indexes | Do not support indexes. However, indexes may be created on the underlying base tables. | Support indexes, improving query performance. |
| Lifetime and cleanup | Exist only during query execution and are automatically cleaned up. | Must be explicitly dropped after use. |
Note
When working with stored procedures, use table variables instead of temporary tables, since the latter ones can cause stored procedures to recompile.
Here are techniques and patterns to manage runtime errors:
BEGIN TRY and BEGIN CATCH blocks.TRY...CATCH with explicit transactions (BEGIN TRANSACTION, COMMIT, and ROLLBACK) to ensure data consistency on failure.Error severity
TRY-CATCH blocks handle errors with severity levels between 11 and 19 that do not close the database connection.TRY-CATCH blocks.TRY-CATCH blocks.View a list of reserved keywords that shouldn’t be used as names for tables, columns, or other database objects unless you enclose them in quoted identifiers or delimited identifiers.