Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SQL Dynamic DatePart when using DateDiff

Is there a way to pass the DatePart parameter of DateDiff as a variable? So that I can write code that is similar to this?

DECLARE @datePart VARCHAR(2)
DECLARE @dateParameter INT

SELECT @datePart = 'dd'
SELECT @dateParameter = 28

SELECT
    *
FROM
    MyTable
WHERE
    DATEDIFF(@datePart, MyTable.MyDate, GETDATE()) < @dateParameter

The only ways I can think of doing it are with a CASE statement checking the value of the parameter or by building the SQL as a string and running it in an EXEC.

Does anyone have any "better" suggestions? The platform is MS SQL Server 2005

like image 329
Robin Day Avatar asked May 07 '09 14:05

Robin Day


People also ask

Does datediff include start and end?

DATEDIFF returns the total number of the specified unit between startDate and endDate.

How can I get the difference between two dates in SQL?

To find the difference between dates, use the DATEDIFF(datepart, startdate, enddate) function. The datepart argument defines the part of the date/datetime in which you'd like to express the difference. Its value can be year , quarter , month , day , minute , etc.

How do I count the number of days between two dates in SQL?

The statement DATEDIFF(dd,@fromdate,@todate) + 1 gives the number of dates between the two dates. The statement DATEDIFF(wk,@fromdate,@todate) gives the number of weeks between dates and * 2 gives us the weekend (Saturday and Sunday) count. The next two statements excludes the day if it's a Saturday or Sunday.

Can we use datediff in where clause?

The DATEDIFF function can also be used in a WHERE clause as well as ORDER BY and HAVING clauses. The units of time available for the DATEDIFF are the same as those for the DATEADD function.


4 Answers

According to BOL entry on DATEDIFF (arguments section) for SQL Server 2005,

These dateparts and abbreviations cannot be supplied as a user-declared variable.

So you are probably stuck with Dynamic SQL or using a CASE statement. But I would opt for a CASE version instead of dynamic SQL.

like image 75
dance2die Avatar answered Oct 19 '22 05:10

dance2die


Old but still valid unfortunately.

I did it the case way and just want to share the code so you don't have to do all the annoying typing I had to do. Covers all possible date parts. Just replace the name of the function and the date function to implement for other T-SQL date functions.

Copy and paste section

-- SELECT dbo.fn_DateAddFromStringPart('year', 1, GETDATE())
CREATE FUNCTION fn_DateAddFromStringPart
(
    @Interval VARCHAR(11),
    @Increment INT,
    @Date SMALLDATETIME
)
RETURNS DATETIME
AS
BEGIN
    -- Declare the return variable here
    DECLARE @NewDate DATETIME

    -- Add the T-SQL statements to compute the return value here
    SELECT @NewDate = CASE
        WHEN @Interval IN ('year', 'yy', 'yyyy') THEN DATEADD(YEAR, @Increment, @Date)
        WHEN @Interval IN ('quarter', 'qq', 'q') THEN DATEADD(QUARTER, @Increment, @Date)
        WHEN @Interval IN ('month', 'mm', 'm') THEN DATEADD(MONTH, @Increment, @Date)
        WHEN @Interval IN ('dayofyear', 'dy', '') THEN DATEADD(DAYOFYEAR, @Increment, @Date)
        WHEN @Interval IN ('day', 'dd', 'd') THEN DATEADD(DAY, @Increment, @Date)
        WHEN @Interval IN ('week', 'wk', 'ww') THEN DATEADD(WEEK, @Increment, @Date)
        WHEN @Interval IN ('weekday', 'dw', 'w') THEN DATEADD(WEEKDAY, @Increment, @Date)
        WHEN @Interval IN ('hour', 'hh') THEN DATEADD(HOUR, @Increment, @Date)
        WHEN @Interval IN ('minute', 'mi', 'n') THEN DATEADD(MINUTE, @Increment, @Date)
        WHEN @Interval IN ('second', 'ss', 's') THEN DATEADD(SECOND, @Increment, @Date)
        WHEN @Interval IN ('millisecond', 'ms') THEN DATEADD(MILLISECOND, @Increment, @Date)
        WHEN @Interval IN ('microsecond', 'mcs') THEN DATEADD(MICROSECOND, @Increment, @Date)
        WHEN @Interval IN ('nanosecond', 'ns') THEN DATEADD(NANOSECOND, @Increment, @Date)
    END

    -- Return the result of the function
    RETURN @NewDate

END
GO
like image 28
Asken Avatar answered Oct 19 '22 07:10

Asken


The only thing you can really do aside from the suggested dynamic sql or case statement is to always do the datediff at a granular DatePart and then upconvert. This isn't fool proof though, you will get an overflow in the function if you try to datediff to granular a part over too large a span e.g. datediff(second, 0, getdate()). But if you just need something like minute parts you should be fine (double check with max date values you care about).

So for example

select datediff(minute, 0, getdate())

If I want to convert this to hours, days, etc, I can just divide the result by the appropriate amount. It won't take into account leap years etc.

like image 2
ahains Avatar answered Oct 19 '22 06:10

ahains


Definitely using the dynamic query such as this below works very well, I assume you plan on using only abbreviation for @datePart. I would recommend using a minimum of VARCHAR(4) for datepart this will handle such abbreviations as yyyy and mcs. Happy coding:

DECLARE @datePart VARCHAR(2)
DECLARE @dateParameter INT
DECLARE @SQLTemp varchar(MAX)


SELECT @datePart = 'dd'
SELECT @dateParameter = 28

set  @SQLTemp ='SELECT * FROM MyTable
    WHERE DATEDIFF('+@datePart+', '+MyTable.MyDate+', GETDATE()) < '+@dateParameter

exec (@SQLTemp)
like image 2
PapaPanthers Avatar answered Oct 19 '22 07:10

PapaPanthers