Free SQL Server Learning - Making the most out of SQL Server Agent
solving sql server problems for millions of dbas and developers since 2006



SQL Server DBA Tips SQL Server Developer Tips SQL Server Business Intelligence Tips SQL Server Career Tips SQL Server Tip Categories SQL Server Tutorials SQL Server Webcasts SQL Server Whitepapers SQL Server Tools SQL Server Questions and Answers MSSQLTips Authors About MSSQLTips SQL Server User Groups SQL Server Events I am MSSQLTips MSSQLTips Advertising Options

MSSQLTips Facebook Page MSSQLTips LinkedIn Page MSSQLTips RSS Feed MSSQLTips Pinterest Page MSSQLTips Twitter Page MSSQLTips Google+ Page




































SQL Product Highlight

Red Gate Software - SQL Server performance monitoring that makes prioritizing simple

SQL Monitor offers straightforward server monitoring through a web-based UI, to help you prioritize your workload:

  • Real-time SQL Server performance updates
  • Alerts within 15 seconds of a SQL Server problem
  • Embedded advice on how to solve performance problems
  • Web-based, so you can track server performance away from your desk
  • Quick to install
  • NEW: library of custom metric scripts written by SQL Server MVPs, for extra coverage

Start monitoring your servers today with a free trial.

Learn more!











Getting creative with Computed Columns in SQL Server

By:   |   Read Comments   |   Related Tips: More > T-SQL

Problem

I have used computed columns in simple scenarios and these are working fine. However in some cases we are facing limitations while implementing business logic through computed columns. For example we are required to have different values based on a separate expression to determine the computed values. Also, there maybe the chance of a divide by zero error which needs to be prevented. We are also required to access columns outside the computed column table for use in the computed column expression.  In this tip we look at how to make computed columns more flexible.

Solution

Computed columns can add great flexibility in database design. It is possible to conditionally apply the computational expression, handling divided by zero error and accessing any column outside the table of computed column. This would make the computed column more flexible and handy for your database design. Following is list of some scenarios that we are going to handle in this tip.

  • Conditional computation of values
  • Divided by zero error
  • Accessing a column outside the computed column table

We will use simple T-SQL techniques to solve the above mentioned issues. This will demonstrate the flexibility and ability of computed columns to handle any such issues.


Conditional Computation of Values

We have a simple table with some columns related to employees. There is also a computed column [DORetirement] which computes retirement at age 60.  We have a new requirement to set the age limit to 65 for managers, but keep it at 60 for all other employees.

We can accomplish this by using a conditional formula using a CASE statement as shown in the following code.  For the DORetirement column if the designation is "Manager" then the retirement will be 65 else it will be 60.

-- Script# 1: Computed column with conditional formula
-- Use sample database
USE [AdventureWorks]
GO 
 
-- Create Table with computed column
IF OBJECT_ID('CCtest', 'U') IS NOT NULL
  DROP TABLE [dbo].[CCtest]
GO
 
CREATE TABLE [dbo].[CCtest]
  (
  [EmpNumb] INT NOT NULL,
  [Designation] VARCHAR(50) NOT NULL,
  [DOBirth] DATETIME NOT NULL,
  [DORetirement] AS 
    CASE WHEN designation = 'Manager' 
      THEN (DATEADD(YEAR,(65),[DOBirth]))
      ELSE (DATEADD(YEAR,(60),[DOBirth]))
    END
)
GO
 
--Insert sample data 
INSERT INTO CCTest (empNumb, Designation, DOBirth) 
SELECT 84, 'DBA', '1985-12-13' UNION ALL
SELECT 85, 'DBA', '1980-11-18' UNION ALL
SELECT 86, 'Manager', '1978-01-19' UNION ALL
SELECT 88, 'Manager', '1985-12-13' UNION ALL
SELECT 90, 'Developer', '1975-07-23' 
GO
 
-- Check the required functionality in result
SELECT Designation, datediff(yy,dobirth,doretirement ) AgeLimit, DOBirth, DORetirement 
FROM CCTest
GO

If you run the above code you should get output like the following.  By using a CASE statement, we can define separate expressions depending on the provided criteria.

Conditional formula in computed column


Divided by Zero Error

In computational expression, if we are dividing then there may be a chance to have a zero in the denominator. In such cases we run the risk of having an error because of a divide by zero.

Consider a scenario where we have a computed column with formula [Result] AS (numerator/denominator) where numerator and denominator columns are used for the computed column [DivideResult].  In this case a divide by zero error would be encountered whenever the computed column expression is calculated with a zero in the denominator column.

We can avoid this error by replacing the zero in denominator with a NULL value using the NULLIF function as shown below.  The fourth record we insert into the table would cause a divide by zero issue, but the NULLIF function converts this to a NULL.  

-- Script# 2: Avoiding divided by zero error
-- Use sample database
USE [AdventureWorks]
GO 
-- Create Table with computed column
IF OBJECT_ID('CCtest', 'U') IS NOT NULL
  DROP TABLE CCtest
GO
CREATE TABLE [dbo].[CCtest]
  (
  [Numerator] int NOT NULL,
  [Denominator] int NOT NULL,
  [Result] AS (Numerator/NULLIF(Denominator,0)) 
  )
GO
--Insert sample data
INSERT INTO CCTest (Numerator, Denominator) 
SELECT 840, 12 UNION ALL
SELECT 805, 6 UNION ALL
SELECT 846, 3 UNION ALL
SELECT 88, 0 UNION ALL
SELECT 90, 15
GO
-- Check the result
SELECT * from CCTest
GO

Since you can not divide by NULL the returned value is NULL for this column for this one record.

By default a computed column will allow NULL values. However you can explicitly specify NOT NULL with persisted computed columns only.


Accessing a column outside of the computed column table

A computed column can not directly access any column outside its table. This limitation may be overcome by using a User Defined Function. A UDF may be used in the expression to access any column outside the computed column table.

In the script below, a UDF is created to calculate the employee leave balance to show how many remaining days of leave an employee has beyond the maximum of 20 days.  This data comes from a secondary table named LeaveBalance.

--Script # 3: Use UDF to access column in other table
-- Use sample database
USE [AdventureWorks]
GO 
-- Create Table to reference in UDF
IF OBJECT_ID('LeaveBalance', 'U') IS NOT NULL
  DROP TABLE LeaveBalance
GO
CREATE TABLE [dbo].[LeaveBalance]
  (
  [EmpNumb] INT NOT NULL,
  [LeavesAvailed] TINYINT NOT NULL,
  )
GO
--Insert sample data
INSERT INTO LeaveBalance
SELECT 840, 12 UNION ALL
SELECT 805, 6 UNION ALL
SELECT 846, 13 UNION ALL
SELECT 88, 7 UNION ALL
SELECT 90, 15
GO
-- Create UDF to get leave balance
IF OBJECT_ID('UDF_GetLeaveBalance', 'FN') IS NOT NULL
  DROP FUNCTION UDF_GetLeaveBalance
GO
-- Create UDF to use in computed column
CREATE FUNCTION UDF_GetLeaveBalance (@EmpNumb int)
RETURNS TINYINT
AS
BEGIN
  DECLARE @LeaveBalance TINYINT
  SELECT @LeaveBalance = (20 - LeavesAvailed) 
  FROM LeaveBalance
  WHERE EmpNumb = @empnumb
  RETURN @LeaveBalance
END
GO
-- Create Table to use computed column
IF OBJECT_ID('CCTest', 'U') IS NOT NULL
  DROP TABLE CCtest
GO
CREATE TABLE [dbo].[CCtest]
  (
  [EmpNumb] INT NOT NULL,
  [Designation] VARCHAR(50) NOT NULL,
  [LeaveBalance] AS ([dbo].UDF_GetLeaveBalance(EmpNumb))
  )
GO
--Insert sample data
INSERT INTO CCTest (EmpNumb, Designation) 
SELECT 840, 'DBA' UNION ALL
SELECT 805, 'DBA' UNION ALL
SELECT 846, 'Manager' UNION ALL
SELECT 88, 'Manager' UNION ALL
SELECT 90, 'Developer' 
GO
-- Check the result
SELECT * from CCTest
GO

So below we can see the number of remaing days available for each employee.

There are some considerations related to UDFs when a computed column is to be used in an index.  You can read more about this in this tip: How to create indexes on computed columns in SQL Server.

Next Steps

The above mentioned problems and their solutions work in the same way for persisted or non persisted computed columns. Utilizing the available flexibility of computed columns may improve your database design. Computed columns are a good option to use to implement business logic through expressions.

  • Click here to read tip about basics of working with computed columns
  • Click here to read tip about creating indexes on computed columns


Last Update: 8/29/2011

About the author

Atif is a passionate SQL Server DBA, technical reviewer and article author.

View all my tips


Print  
Become a paid author


Comments and Feedback:


Post a Comment or Question

Keep it clean and stay on the subject or we may delete your comment.
Your email address is not published. Required fields are marked with an asterisk (*)

*Name   *Email Notify for updates

Signup for our newsletter


Comments
*Enter Code refresh code


 
Sponsor Information
SQL Server having some performance issues? Idera SQL check. FREE SQL Server enhancement.

SQL Developer Bundle: Cut out dull work with 12 tools for simpler, faster database development. Free trial

What grade do you think your SQL Servers get? Find out with a SQL Server Health Check consultant in the USA.

In two mouse clicks view SQL bottlenecks. With ZERO impact pinpoint all poor performing SQL with 100% accuracy.

Optimizing SQL Server performance can be a daunting task. Or is it?


Copyright (c) 2006-2013 Edgewood Solutions, LLC All rights reserved
privacy | disclaimer | copyright | advertise | about
authors | contribute | feedback | giveaways | user groups
Some names and products listed are the registered trademarks of their respective owners.


Edgewood Solutions LLC | MSSharePointTips.com | MSSQLTips.com