|
|
|
Grasshopper
      
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
|
|
|
|
|
SSChampion
        
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
|
|
|
|
|
Grasshopper
      
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.
|
|
|
|
|
UDP 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
|
|
|
|
|
UDP 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
|
|
|
|
|
Grasshopper
      
Group: General Forum Members
Last Login: Saturday, April 20, 2013 4:22 PM
Points: 11,
Visits: 20
|
|
|
|
|
|
Grasshopper
      
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.
|
|
|
|
|
SSC 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
|
|
|
|
|
Grasshopper
      
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.
|
|
|
|
|
SSC 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.
|
|
|
|