Click here to monitor SSC
SQLServerCentral is supported by Red Gate Software Ltd.
 
Log in  ::  Register  ::  Not logged in
 
 
 
        
Home       Members    Calendar    Who's On


Add to briefcase

Divide by zero from implicate conversion Expand / Collapse
Author
Message
Posted Monday, December 10, 2012 11:51 AM
Grasshopper

GrasshopperGrasshopperGrasshopperGrasshopperGrasshopperGrasshopperGrasshopperGrasshopper

Group: General Forum Members
Last Login: Saturday, April 20, 2013 4:22 PM
Points: 11, Visits: 20
I have a select statement where I am doing some basic math with a datediff function. I have looked at the raw data and no where do I get a zero value when I subtract the two dates. But as soon as I do the division, I get the error. Originally I thought it had to do with the column I was dividing into, so I changed the numerator to 1.0 and I still get the same results. I think some where along the line SQL server is doing a conversion or rounding of my value which is where I am getting the zero in the denominator. I have tried both convert and cast to see if that was an issue. I have tried rounding my values before any division and I still get the same result. Any insight would be greatly appreciated.

This is my original statement.
ISNULL(round((hs.fractionalPart*(dr.LostGeneration/ ( DATEDIFF(SECOND,dr.startTime,dr.endTime) / 3600.0))),1),0.0)

I have broken down the above statement to cast the dateDiff to a float and the dr.LostGeneration column to a float and I still get an error.

Here is sample of the data used to perform the above statement. I think my issue is with the last 3 rows getting rounded.

select convert(float,DATEDIFF(SECOND,dr.startTime,dr.endTime))/3600.0, dr.startTime, dr.endTime

Calculated Col StartTime EndTime
0.111111111111111 2012-12-10 10:42:45.000 2012-12-10 10:49:25.000
0.120277777777778 2012-12-10 12:17:06.000 2012-12-10 12:24:19.000
0.11 2012-12-10 08:28:12.000 2012-12-10 08:34:48.000
0.111388888888889 2012-12-10 15:13:20.000 2012-12-10 15:20:01.000
0.0352777777777778 2012-12-10 13:11:24.000 2012-12-10 13:13:31.000
0.0341666666666667 2012-12-10 13:02:49.000 2012-12-10 13:04:52.000
0.0655555555555556 2012-12-10 13:04:11.000 2012-12-10 13:08:07.000
Post #1394729
Posted Monday, December 10, 2012 12:07 PM


SSChampion

SSChampionSSChampionSSChampionSSChampionSSChampionSSChampionSSChampionSSChampionSSChampionSSChampion

Group: General Forum Members
Last Login: Today @ 3:55 AM
Points: 11,605, Visits: 27,643
try using a CASE statement to filter out the rows that have a zero denominator
something like this is my first guess:
CASE
WHEN DATEDIFF(SECOND,dr.startTime,dr.endTime) = 0
THEN 0
ELSE ISNULL(round((hs.fractionalPart*(dr.LostGeneration/ ( DATEDIFF(SECOND,dr.startTime,dr.endTime) / 3600.0))),1),0.0)
END



Lowell

--There is no spoon, and there's no default ORDER BY in sql server either.
Actually, Common Sense is so rare, it should be considered a Superpower. --my son
Post #1394741
Posted Monday, December 10, 2012 12:17 PM
Grasshopper

GrasshopperGrasshopperGrasshopperGrasshopperGrasshopperGrasshopperGrasshopperGrasshopper

Group: General Forum Members
Last Login: Saturday, April 20, 2013 4:22 PM
Points: 11, Visits: 20
That did work. Thanks.

What I don't fully understand is if I look at the raw data, I don't see any values of zero after the dateDiff and if I also do a select * where DateDiff = 0 I get no rows returned.
Post #1394745
Posted Monday, December 10, 2012 12:52 PM
UDP Broadcaster

UDP BroadcasterUDP BroadcasterUDP BroadcasterUDP BroadcasterUDP BroadcasterUDP BroadcasterUDP BroadcasterUDP Broadcaster

Group: General Forum Members
Last Login: Wednesday, May 15, 2013 8:20 AM
Points: 1,446, Visits: 1,883
I can make a guess as to why you have a zero in the denominator. You are dividing an INT by 3600.0, and then this number is the denominator for a division using dr.LostGeneration, whose data type is the one that determines the data type for the implicit conversion. I tried the following query to see what happens if that data type is INT:

DECLARE @LG AS INT
SET @LG = 1

;WITH TALLY AS (

SELECT ROW_NUMBER() OVER(ORDER BY MSV.number) AS N
FROM master.dbo.spt_values AS MSV
CROSS APPLY master.dbo.spt_values AS SV2
WHERE MSV.number < 2250
AND MSV.number > 0
)
SELECT N
FROM TALLY
WHERE N < 3601
AND @LG / N / 3600.0 = 0

The results of this query include ALL the numbers from 1 to 3600. You might recognize the CTE as a TALLY table. I would suggest a slight re-ordering of how you compute this result, as follows:

ROUND((hs.fractionalPart * (CAST(dr.LostGeneration AS float)/
(ISNULL(NULLIF(DATEDIFF(SECOND,dr.startTime,dr.endTime),0),1.)/3600.))),1)

Let me know...


Steve
(aka sgmunson)

Weight Loss Tips
Post #1394759
Posted Monday, December 10, 2012 12:59 PM
UDP Broadcaster

UDP BroadcasterUDP BroadcasterUDP BroadcasterUDP BroadcasterUDP BroadcasterUDP BroadcasterUDP BroadcasterUDP Broadcaster

Group: General Forum Members
Last Login: Wednesday, May 15, 2013 8:20 AM
Points: 1,446, Visits: 1,883
FYI, had to edit my last post (before this one) twice - please be sure to check it again...



Steve
(aka sgmunson)

Weight Loss Tips
Post #1394764
Posted Monday, December 10, 2012 1:22 PM
Grasshopper

GrasshopperGrasshopperGrasshopperGrasshopperGrasshopperGrasshopperGrasshopperGrasshopper

Group: General Forum Members
Last Login: Saturday, April 20, 2013 4:22 PM
Points: 11, Visits: 20
Both posts work. Thanks.
Post #1394767
Posted Monday, December 10, 2012 11:08 PM
Grasshopper

GrasshopperGrasshopperGrasshopperGrasshopperGrasshopperGrasshopperGrasshopperGrasshopper

Group: General Forum Members
Last Login: Wednesday, May 01, 2013 4:43 PM
Points: 14, Visits: 59
What about Hs.FeactionalPart? Is it a float or did you cast it as a float when you cast the other parts? SQL Server doesn't always do implicit conversions the way we expect. You can dig into the execution plan to see where the implicit conversion is happening as well.
Post #1394896
Posted Tuesday, December 11, 2012 2:12 AM
SSC Rookie

SSC RookieSSC RookieSSC RookieSSC RookieSSC RookieSSC RookieSSC RookieSSC Rookie

Group: General Forum Members
Last Login: Yesterday @ 2:07 AM
Points: 48, Visits: 197
try rearranging this

jkury (12/10/2012)

ISNULL(round((hs.fractionalPart*(dr.LostGeneration/ ( DATEDIFF(SECOND,dr.startTime,dr.endTime) / 3600.0))),1),0.0)


to

ISNULL(round((hs.fractionalPart*dr.LostGeneration*3600/ ( DATEDIFF(SECOND,dr.startTime,dr.endTime))),1),0.0)

If something odd is going on with implicit type conversions in the division this would prevent the problem with time diffs of under an hour
Post #1394950
Posted Tuesday, December 11, 2012 7:35 AM
Grasshopper

GrasshopperGrasshopperGrasshopperGrasshopperGrasshopperGrasshopperGrasshopperGrasshopper

Group: General Forum Members
Last Login: Saturday, April 20, 2013 4:22 PM
Points: 11, Visits: 20
Grasshopper - I can't flip the order as you suggested because I get the difference in seconds and then convert that to minutes. We report to the minute, but want seconds for accuracy.

I also ensured that all values are of the same data type. I tested by manually converting all values to float.
Post #1395121
Posted Wednesday, December 12, 2012 4:39 AM
SSC Rookie

SSC RookieSSC RookieSSC RookieSSC RookieSSC RookieSSC RookieSSC RookieSSC Rookie

Group: General Forum Members
Last Login: Yesterday @ 2:07 AM
Points: 48, Visits: 197
You are dividing the denominator by 3600 - that is exactly the same mathematically as multiplying the numerator. However due to the computer handling floats using a fixed number of bits the division will result in a loss of precision (accuracy should not be affected at all unless there is a problem with your system's clock) compared to the multiplication. Assuming of course you aren't using large enough values to cause an overflow.
In practice for the example given I doubt you will notice the difference.

Note also by dividing by 3600 you convert from seconds to hours not minutes. My rearrangement does not change this.
Post #1395590
« Prev Topic | Next Topic »

Add to briefcase

Permissions Expand / Collapse