SQL Server How can I use a column's values for DATEADD()'s datepart parameter? [duplicate]

41ik7eoe  于 11个月前  发布在  其他
关注(0)|答案(2)|浏览(66)

This question already has answers here:

send datepart as parameter from a table to DATEADD function in sql server (2 answers)
Closed 6 days ago.

I have a data set like this:

CREATE TABLE #Dummy 
(
    Latest_Appointment_Date date, 
    Interval varchar(255), 
    Increment int
); 

INSERT INTO #Dummy (Latest_Appointment_Date, Interval, Increment) 
VALUES ('2023-11-10', 'week', 2), 
       ('2023-11-23', 'month', 1);

Where the interval and increment columns denote how much I want to increment the date by (using DATEADD , for example). I can't figure out how to use the column values as the parameters of my DATEADD .

When I do

SELECT 
    *, DATEADD(Interval, Increment, Latest_Appointment_Date) 
FROM #Dummy

I get the error

'Interval' is not a recognized dateadd option

Any insight would be great. Thank you. I'm using SQL Server.

tjjdgumg

tjjdgumg1#

T-SQL's DATEADD is not a "real" function , it's actually a language-feature (like a statement or control-structure) and the first parameter ( datepart ) accepts keyword arguments, not value arguments, so you cannot parameterize it using a @variable nor column expression...

...instead, you'll need to use a CASE expression:

SELECT
    t.*,

    CASE t.Interval
        WHEN 'year'  THEN DATEADD( year , t.Increment, t.Latest_Appointment_Date )
        WHEN 'month' THEN DATEADD( month, t.Increment, t.Latest_Appointment_Date )
        WHEN 'day'   THEN DATEADD( day  , t.Increment, t.Latest_Appointment_Date )
        WHEN 'week'  THEN DATEADD( week , t.Increment, t.Latest_Appointment_Date )
        WHEN 'hour'  THEN DATEADD( hour , t.Increment, t.Latest_Appointment_Date )
        /* etc for the other defined keywords, tedious, huh? */
    END AS NextDate
FROM
    #Dummy AS t
aiazj4mn

aiazj4mn2#

My answer is basically what Dai said. Here's an inline table valued function you can use to abstract away that logic so you can reuse it elsewhere if you need (I copied all the various possible inputs to the proc from the DATEADD documentation)

create or alter function dbo.DynamicDateAdd
(
    @Interval varchar(30),
    @Increment int,
    @Date date
)
returns table
as
return
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', 'y') 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)
        else null
    end

go

Example Usage

declare @Now date = getdate()

;with inputs (Interval, Increment) as
(
    select 'day', checksum(newid()) % 3 union all
    select 'week', checksum(newid()) % 3 union all
    select 'month', checksum(newid()) % 3 union all
    select 'year', checksum(newid()) % 3 union all
    select 'not-an-input', checksum(newid()) % 3 
)
select
    Now = @Now,
    a.Increment,
    a.Interval,
    b.NewDate
from inputs a
cross apply dbo.DynamicDateAdd(interval, Increment, @Now) b

相关问题