Overcoming SQL Server 'The datediff function resulted in an overflow'

by Ross Buggins 27. January 2011 14:31

The built in SQL dateDiff function has issues when trying to calculate the difference between dates that are far apart when you request a high precision. There are solutions available which request a difference with a lower precision and multiply that by a constant, however I was looking for a more absolute answer, so I turned to the .Net runtime.

The built in function:

 

dateDiff(MILLISECOND, '01/01/2010', '01/01/2011')

Returns with the error:

Msg 535, Level 16, State 0, Line 4
The datediff function resulted in an overflow. The number of dateparts separating two date/time instances is too large. Try to use datediff with a less precise datepart.

However my new function:

 [dbo].[DateDiffMs]('01/01/2010', '01/01/2011')

Returns:

31536000000

Success!

This is possible by creating a User Defined Function in C# which is then deployed to the database.

In visual studio, create a new Sql Database CLR project and create the very simple function:

public partial class UserDefinedFunctions
{

    [Microsoft.SqlServer.Server.SqlFunction]
    public static SqlInt64 DateDiffMs(DateTime from, DateTime to)
    {
        var span = to.Subtract(from);
        return new SqlInt64((long)span.TotalMilliseconds);
    }
};

Deploy this to your database and you then have the ability to get the number of milliseconds between any date.

 

Testing

To test the speed implications I created two quick recursive CTE's which record how long it takes to run 100000 operations.

The first tests the standard Date Diff:

declare @loopSize int = 1000000;

declare @start datetime = null;

declare @end datetime = null;

 

SELECT @start = GETDATE();

 

with cte_1(result, myCounter)

AS

(

select DATEDIFF(SECOND, '01/01/2010', '01/01/2011'), 1

union all

select result, myCounter + 1 FROM cte_1

 

where myCounter < @loopSize

)

 

 

 

select * from cte_1 OPTION (MAXRECURSION 0);

SELECT @end= GETDATE();

 

SELECT [dbo].[TicksDiff](@start, @end)

GO

 

 

GO

 

 

 

The second tests the .Net Function:

 

 

 

 declare @loopSize int = 1000000;

declare @start datetime = null;

declare @end datetime = null;

 

SELECT @start = GETDATE();

 

with cte_1(result, myCounter)

AS

(

select [dbo].[DateDiffSecs]('01/01/2010', '01/01/2011'), 1

union all

select result, myCounter + 1 FROM cte_1

 

where myCounter < @loopSize

)

 

 

 

select * from cte_1 OPTION (MAXRECURSION 0);

SELECT @end= GETDATE();

 

SELECT [dbo].[TicksDiff](@start, @end)

GO

 

 

 

--select DATEDIFF(SECOND, '01/01/2010', '01/01/2011');

GO

 

Results

DateDiff - 184100000 ticks

DateDiffSecs - 190300000 ticks

The .NET CLR method only takes 3.3% longer to run than the built in function. I think this is tolerable!

Tags: , ,

.net | sql

Add comment




  Country flag
biuquote
  • Comment
  • Preview
Loading


Month List

Widget Most comments not found.

Object reference not set to an instance of an object.X