Scott on Writing

Musings on technical writing...

Computed Columns and Divide by Zero Errors

Problem: With SQL server you have a computed column that has the following formula: SomeColumnA / SomeColumnB, where SomeColumnA and SomeColumnB are non-NULL numeric columns.  Clearly a problem can arise if there is a record in the database with SomeColumnB equal to 0.0, as that will result in a Divide by zero error.  Assume that the business requirements require that SomeColumnB might, indeed, be 0.0 for some records, and for such records, the computed column should result in a value of 0.0.  The problem - how do you do this, as computed columns don't allow conditional statements.

My Solution: Here's my solution (feel free to nitpick, suggest alternative approaches, lambast it as causing more detriment to the field of computer science than GOTOs, etc.).  For the computed column's formula I used NULLIF to see if SomeColumnB was 0.0.  If so, I have it return NULL, and the division will result in NULL.  I then wrapped the whole thing in an ISNULL, so if the division resulted in NULL, the result was 0.0:

ISNULL(SomeColumnA / NULLIF(SomeColumnB, 0.0), 0.0)

I'm hardly a SQL buff, so if there are any pitfalls to this approach, share them in the blog's comments, please.  On a closing note, let me quote from Sql-Server-Performance.com's comments on computed columns:

Generally, using computed columns in a table is not recommended because it does not follow the standard rules of normalization. But, it is sometimes more efficient overall if you use computed columns in a table than having to recompute the same data over and over in queries. [Empahsis their's.] This is especially true if you are running the same query over and over against your data that performs the same calculations over and over. By performing the calculations in the table, it can reduce the amount of work performed by a query each time it is run. You have to determine for yourself where the bottleneck in performance is, and act accordingly. If the bottleneck is in INSERTS and UPDATES, then using calculated columns may not be a good idea. But if your SELECT statements are the bottleneck, then using calculated columns may pay off.

UPDATE (Oct. 19th, 2004 - 1:05 PM PST): A helpful post from graz in the comments indicated that CASE statements can be used in a computed column, thereby providing conditional-like semantics for a computed column.  To learn more about CASE be sure to check out graz's article The case for CASE.

posted on Tuesday, October 19, 2004 10:17 AM

Feedback

# re: Computed Columns and Divide by Zero Errors 10/19/2004 10:55 AM Jay Nathan

Here's something else that'll work, but not sure if there are any advantages:

COALESCE(SomeColumnA/(SomeColumnB, 0.0), SomeColumnA/SomeColumnB)

The immediate disadvantage is that it's more verbose.

# re: Computed Columns and Divide by Zero Errors 10/19/2004 10:56 AM Jay Nathan

Doh!! That won't work afterall.

# re: Computed Columns and Divide by Zero Errors 10/19/2004 11:03 AM David Neal

If you are using stored procedures, then you can do the following:

SET ANSI_WARNINGS OFF
SET ARITHABORT OFF

SELECT Result1 = ColumnA/ColumnB,
Result2 = COALESCE(ColumnA/ColumnB, 0)

Result1 will be NULL and Result2 will be 0 if the value in ColumnB is 0.

# re: Computed Columns and Divide by Zero Errors 10/19/2004 11:10 AM Scott Mitchell

David, won't the Result1 = ColumnA/ColumnB result in a Divide by zero error when ColumnB = 0? I don't believe illegal division results in a NULL, but rather raises an error. (At least on my database box, maybe it's a SQL server setting somewhere...)

# re: Computed Columns and Divide by Zero Errors 10/19/2004 11:16 AM Mike Singer

> Problem: With SQL server you have a computed column

Perhaps the problem could be expressed wider, kind of: there are tables on SQL server and you should show to a user some corresponding grids with the computed columns? Then you could insert the column not only on Data Storage Level, but also on higher levels, right up to the level of client-side scripts.

# re: Computed Columns and Divide by Zero Errors 10/19/2004 11:32 AM David Neal

Scott, you won't get a divide by zero error if you have both ANSI_WARNINGS and ARITHABORT set to OFF. Again, this is only convenient when you're doing this within a stored procedure or batch statement.

BTW, ISNULL() and COALESCE() do the same thing. I'm just used to writing COALESCE.

# re: Computed Columns and Divide by Zero Errors 10/19/2004 11:34 AM David Neal

Here's an example you can run in Query Analyzer.

SET ANSI_WARNINGS OFF
SET ARITHABORT OFF

DECLARE @tblTable TABLE ( c1 int, c2 int )

INSERT INTO @tblTable
SELECT 235, 0
UNION SELECT 244, 0
UNION SELECT 50, 10

SELECT Result1 = c1/c2, Result2 = ISNULL(c1/c2, 0)
FROM @tblTable

# re: Computed Columns and Divide by Zero Errors 10/19/2004 12:50 PM graz

I'm a little confused. Why can't you use a CASE statement in a computer column. Am I missing something simple here.

use tempdb
GO
if exists (select *
from dbo.sysobjects
where id = object_id(N'[dbo].[T1]')
and OBJECTPROPERTY(id, N'IsUserTable') = 1)
drop table [dbo].[T1]
GO

CREATE TABLE [dbo].[T1] (
[Col1] [decimal](10, 5) NULL ,
[Col2] [decimal](10, 5) NULL ,
[CompColumn] AS (CASE
WHEN Col2 = 0 THEN 0
WHEN Col2 IS NULL THEN 0
ELSE Col1 / Col2
END)
) ON [PRIMARY]
GO

INSERT T1 (Col1, Col2)
VALUES (1, 2)

INSERT T1 (Col1, Col2)
VALUES (10, 5)

INSERT T1 (Col1, Col2)
VALUES (10, 0)


INSERT T1 (Col1, Col2)
VALUES (10, NULL)

GO
SELECT *
FROM T1

# re: Computed Columns and Divide by Zero Errors 10/19/2004 1:04 PM Scott Mitchell

Didn't realize you could have CASE statements in a computed column, that sure is helpful to know. (I had needed this in an earlier project, tried IFs in the computed column formula region, but those aren't allowed obviously, so ended up using a UDF... will have to "fix" that.) Thanks for the info! :-)

# re: Computed Columns and Divide by Zero Errors 10/20/2004 2:44 PM Stuart Radcliffe

If you have more complex requirements, you can also use a UDF in a computed column

# re: Computed Columns and Divide by Zero Errors 10/26/2004 8:14 AM Scott Mitchell

I've whipped up an article extolling the benefits of CASE, one of the benefits including graz's comment, about using CASE statements in computed columns:

The Power of SQL CASE Statements
http://www.4guysfromrolla.com/webtech/102704-1.shtml

# re: Computed Columns and Divide by Zero Errors 12/2/2004 11:19 AM Jim

I've always used something like this...

SELECT
CASE WHEN ColumnB = 0 THEN 0 ELSE ColumnA/ColumnB END as 'Value'


Good article, Scott.

# re: Computed Columns and Divide by Zero Errors 12/6/2004 9:39 AM jon s

Dont forget, you cant use CASE in a view.

# re: Computed Columns and Divide by Zero Errors 2/7/2005 3:00 PM Johnny

What if I need do SUM(ColumnA/ColumnB)?

# re: Computed Columns and Divide by Zero Errors 2/7/2005 3:16 PM Johnny

Nevermind, the following seems to work:

ISNULL(SUM(CASE WHEN ColumnB = 0 Then 0 Else ColumnA/ColumnB),0)

Any logical issues with the above statement?

# re: Computed Columns and Divide by Zero Errors 3/11/2005 7:58 AM Don

Do not use

SET ANSI_WARNINGS OFF
SET ARITHABORT OFF

in a stored procedure that you expect to call frequently or under load. This will cause the sproc to recompile each time it is executed, crippling your server.

# re: Computed Columns and Divide by Zero Errors 8/26/2005 6:24 PM Billy

Thanks very much, this helped me heaps!

# re: Computed Columns and Divide by Zero Errors 8/31/2005 9:56 PM Khadar khan

Thak You very much Mr.Scott and Mr.Jim
I got nice solution from both of u.

# re: Computed Columns and Divide by Zero Errors 9/25/2005 4:14 PM movedata

Thank you for the suggestion, fixed my issue.

# The Power of SQL CASE Statements 4/10/2007 10:58 PM baikangwang

By Scott Mitchell

Title:  
Name:  
Url:
Protected by Clearscreen.SharpHIPEnter the code you see:
Comments   

Add To Your Reader

My Links

Archives

Post Categories

 

I am a Microsoft MVP for ASP.NET.
I am an ASPInsider.
<May 2008>
SMTWTFS
27282930123
45678910
11121314151617
18192021222324
25262728293031
1234567

Comment Stats

DayTotal% of Total
Sunday 1866.8%
Monday 37913.9%
Tuesday 45316.7%
Wednesday 50418.5%
Thursday 53519.7%
Friday 49418.2%
Saturday 1666.1%
Total 2717100.0%

Hour1Total% of Total
12:00 AM 652.4%
1:00 AM 682.5%
2:00 AM 622.3%
3:00 AM 742.7%
4:00 AM 572.1%
5:00 AM 1033.8%
6:00 AM 1084.0%
7:00 AM 1585.8%
8:00 AM 1716.3%
9:00 AM 1475.4%
10:00 AM 1716.3%
11:00 AM 1816.7%
12:00 PM 1886.9%
1:00 PM 1696.2%
2:00 PM 1605.9%
3:00 PM 1324.9%
4:00 PM 1073.9%
5:00 PM 923.4%
6:00 PM 913.3%
7:00 PM 963.5%
8:00 PM 833.1%
9:00 PM 782.9%
10:00 PM 792.9%
11:00 PM 772.8%
Total 2717100.0%

Comments by Blog Entry Date/Time

Day Entry MadeAvg.Total
Sunday 5.54144
Monday 5.22339
Tuesday 4.28419
Wednesday 7.67637
Thursday 6.90607
Friday 5.48411
Saturday 5.33160
Total 5.842717

Hour1 Entry MadeAvg.Total
12:00 AM 5.0035
1:00 AM 1.002
5:00 AM 0.000
7:00 AM 7.0035
8:00 AM 5.35107
9:00 AM 6.32278
10:00 AM 6.47246
11:00 AM 4.41181
12:00 PM 6.88330
1:00 PM 3.00111
2:00 PM 5.41222
3:00 PM 8.64285
4:00 PM 4.0589
5:00 PM 5.92154
6:00 PM 4.52113
7:00 PM 9.67174
8:00 PM 9.80147
9:00 PM 5.05111
10:00 PM 5.4265
11:00 PM 4.5732
Total 5.842717

Learn More About Comment Stats
1 - All times GMT -8...


Blog Stats

Favorite Web Sites

My Books

My MSDN Articles