SQL Server:获取下周的相对日期。 (下周一,周二,周三.....)

时间:2013-09-20 15:23:43

标签: sql sql-server date

我需要的是今天下一天(周一,周二,周三......)的日期。

允许用户选择他们想要的日期,并将其作为int存储在表格中。 "下周二打电话给我(3)"

Sunday = 1
Monday = 2
Tuesday = 3
...

所以我的表看起来像这样。

UserID, NextDayID

我想出的是:

select dateadd(dd,(7 - datepart(dw,GETDATE()) + NextDayID ) % 7, getdate())

如果您今天要求下一天我可以在需要的时候添加一周,这似乎有效并且将在今天返回。

我想知道的是,这是一个很好的解决方案还是我缺少的东西?

8 个答案:

答案 0 :(得分:21)

1)您的解决方案使用非确定性函数:datepart(dw...)。由于这方面的原因,更改DATEFIRST设置会产生不同的结果。例如,您应该尝试:

SET DATEFIRST 7;
your solution;

然后

SET DATEFIRST 1;
your solution;

2)以下解决方案独立于DATEFIRST / LANGUAGE设置:

DECLARE @NextDayID INT  = 0 -- 0=Mon, 1=Tue, 2 = Wed, ..., 5=Sat, 6=Sun
SELECT DATEADD(DAY, (DATEDIFF(DAY, @NextDayID, GETDATE()) / 7) * 7 + 7, @NextDayID) AS NextDay

结果:

NextDay
-----------------------
2013-09-23 00:00:00.000

此解决方案基于DATETIME类型的以下属性:

  • 第0天= 19000101 =星期一

  • 第1天= 19000102 =星期二

  • 第2天= 19000103 =星期三

...

  • 第5天= 19000106 =周六

  • 第6天= 19000107 =太阳

因此,将INT值0转换为DATETIME会得到19000101

如果您想查找下一个Wednesday,那么您应该从第2天开始(19000103 / Wed),计算第2天和当天之间的天数(20130921 ; 41534天),除以7(以获得完整周数; 5933周),乘以7(41531 fays;以获得天数 - 第一个Wednesday / {之间的整周{1}}和最后19000103)然后再添加7天(一周; 41538天;以便获得关注Wednesday)。将此号码(41538天)添加到开始日期:Wednesday

注意:我当前的日期是19000103

编辑#1:

20130921

结果:

DECLARE @NextDayID INT;
SET @NextDayID = 1; -- Next Sunday
SELECT DATEADD(DAY, (DATEDIFF(DAY, ((@NextDayID + 5) % 7), GETDATE()) / 7) * 7 + 7, ((@NextDayID + 5) % 7)) AS NextDay

注意:我当前的日期是NextDay ----------------------- 2013-09-29 00:00:00.000

答案 1 :(得分:1)

如果今天是需要找出的那一天,则找出包括今天在内的下一天。

只需稍作调整...设置变量@weekdayno 如下: 1 = 星期日,2 = 星期一,3 = 星期二,4 = 星期三,5 = 星期四,6 = 星期五,7 = 星期六

    DECLARE @weekdayno INT 
    DECLARE @todayno INT 

    SET @weekdayno = 2  ---For Monday----
    SET @todayno = DATEPART(dw,GETDATE()) 

    SELECT CASE 
    WHEN (@todayno = @weekdayno) 
        THEN CONVERT(varchar, GETDATE(), 101) 

    WHEN (@todayno < @weekdayno) 
        THEN CONVERT(varchar, (@weekdayno - @todayno + GETDATE()), 101) 

    WHEN (@todayno > @weekdayno) 
        then CONVERT(varchar,(GETDATE() - (@todayno - @weekdayno) + 7), 101) 

    END AS UpcomingOrToday

答案 2 :(得分:0)

日历表是使用一组日期函数和日期算法的替代方法。针对此特定问题的最小日历表可能如下所示。

2013-09-20  Fri
2012-09-21  Sat
2012-09-22  Sun
2012-09-23  Mon
2012-09-24  Tue
...

因此,获得下周一的查询可能如下所示。

select min(cal_date)
from calendar
where cal_date > current_date
  and day_of_week = 'Mon';

实际上,您可能希望日历表中有更多列,因为您会发现它有很多用途。

此外,通常可以看到使用日历表的代码显然正确。阅读上面的代码很简单:选择今天之后的最小日历日期和星期一。很难看到依赖于日期函数和日期算术的代码显然是正确的。

A calendar table in PostgreSQL

答案 3 :(得分:0)

以下功能可让您即时生成表格...这就是我通常的做法...我不喜欢烫发日期表的想法......似乎没必要,但每个人和情况都不同: - )

CREATE function [dbo].[fxDateTable]
(
    @begindate datetime = null
,   @enddate datetime = null
)
RETURNS @dates TABLE
(
            EventDate datetime primary key not null
)
as
begin
    select @enddate = isnull(@enddate, getdate())
    select @begindate = isnull(@begindate, dateadd(day, -3, @enddate))

    insert @dates
    select dateadd(day, number, @begindate)
    from 
        (select distinct number from master.dbo.spt_values
         where name is null
        ) n
    where dateadd(day, number, @begindate) < @enddate

    return
end

答案 4 :(得分:0)

这是一个老问题。但我确信发布更好的解决方案是值得的。

-- 0 = 1st Mon, 1 = 1st Tue, 2 = 1st Wed, ..., 5 = 1st Sat, 6 = 1st Sun
-- 7 = 2nd Mon, 8 = 2nd Tue, ...
declare @NextDayID int = 0, @Date date = getdate()

select cast (cast (
    -- last Monday before [Date] inclusive, starting from 1900-01-01
    datediff (day, @NextDayID % 7, @Date) / 7 * 7
    -- shift on required number of days
    + @NextDayID + 7
    as datetime) as date)

这个解决方案是@Bogdan Sahlean的改进解决方案。 它可以运行大于6的@NextDayID。 例如,你可以从今天开始第二个星期一。

以下查询显示我的解决方案正常运行。

select [Date]
    , convert (char(5), [0], 10) as Mon1
    , convert (char(5), [1], 10) as Tue1
    , convert (char(5), [2], 10) as Wed1
    , convert (char(5), [3], 10) as Thu1
    , convert (char(5), [4], 10) as Fri1
    , convert (char(5), [5], 10) as Sat1
    , convert (char(5), [6], 10) as Sun1
    , convert (char(5), [7], 10) as Mon2
    , convert (char(5), [8], 10) as Tue2
from (
    select [Date], NextDayID
        , cast (cast (
          datediff (day, NextDayID % 7, [Date]) / 7 * 7 -- last Monday before [Date] inclusive, starting from 1900-01-01
        + NextDayID + 7 -- shift on required number of days
        as datetime) as date) as NextDay
    from (
        select datefromparts (2018, 5, dt) as [Date]
        from (values(14),(15),(16),(17),(18),(19),(20))t_(dt)
    ) d
    cross join (values(0),(1),(2),(3),(4),(5),(6),(7),(8))nd(NextDayID)
) t
pivot (
    min (NextDay) for NextDayID in ([0], [1], [2], [3], [4], [5], [6], [7], [8])
) pvt

结果:

Date       | Mon1  | Tue1  | Wed1  | Thu1  | Fri1  | Sat1  | Sun1  | Mon2  | Tue2
-----------+-------+-------+-------+-------+-------+-------+-------+-------+------
2018-05-14 | 05-21 | 05-15 | 05-16 | 05-17 | 05-18 | 05-19 | 05-20 | 05-28 | 05-22
2018-05-15 | 05-21 | 05-22 | 05-16 | 05-17 | 05-18 | 05-19 | 05-20 | 05-28 | 05-29
2018-05-16 | 05-21 | 05-22 | 05-23 | 05-17 | 05-18 | 05-19 | 05-20 | 05-28 | 05-29
2018-05-17 | 05-21 | 05-22 | 05-23 | 05-24 | 05-18 | 05-19 | 05-20 | 05-28 | 05-29
2018-05-18 | 05-21 | 05-22 | 05-23 | 05-24 | 05-25 | 05-19 | 05-20 | 05-28 | 05-29
2018-05-19 | 05-21 | 05-22 | 05-23 | 05-24 | 05-25 | 05-26 | 05-20 | 05-28 | 05-29
2018-05-20 | 05-21 | 05-22 | 05-23 | 05-24 | 05-25 | 05-26 | 05-27 | 05-28 | 05-29

此解决方案不依赖于@@datefirst

答案 5 :(得分:0)

我认为这是寻找下一个星期一的最佳方法

CONVERT(VARCHAR(11),DateAdd(DAY,case 
     when (DateName(WEEKDAY, NextVisitDate) ='Tuesday') Then 6 
     when (DateName(WEEKDAY, NextVisitDate) ='Wednesday') Then 5 
     when (DateName(WEEKDAY, NextVisitDate) ='Thursday') Then 4
     when (DateName(WEEKDAY, NextVisitDate) ='Friday') Then 3 
     when (DateName(WEEKDAY, NextVisitDate) ='Saturday') Then 2
     when (DateName(WEEKDAY, NextVisitDate) ='Sunday') Then 1
     else 0 end, DateAdd(DAY, DateDiff(DAY, 0,  NextVisitDate), 0)),106) AS Monday,}

答案 6 :(得分:0)

尝试一下:这将给出一个月中所需工作日的日期。

 declare @monthstartdate date='2020-01-01',@monthenddate date='2020-01-31',@weekday char(9)='thursday',@weeknum int=4

        ; with cte(N,WeekDayName_C,Date_C) as
        (select 1,datename(WEEKDAY,@monthstartdate),@monthstartdate
        union all
        select n+1,datename(WEEKDAY,dateadd(day,n,@monthstartdate)),dateadd(day,n,@monthstartdate) from cte where n<31 and Date_C<=@monthenddate )
        select * from (select *,ROW_NUMBER() over (partition by WeekDayName_C order by Date_C asc)Weeknum from cte)a
        where WeekDayName_C=@weekday and Weeknum=@weeknum

答案 7 :(得分:0)

我将其作为函数来使用,其中该过程使用了可用的简化知识,因此,我认为这是一个可靠的解决方案。

CREATE FUNCTION [nilnul.time_._dated.date].[NextWeekday]
(
    @nextWeekDay int  -- sunday as firstday is 1.
)
RETURNS datetime
AS
BEGIN


declare @time datetime;
set @time=getdate();

declare @weekday int;
set @weekday = datepart(weekday,  @time) ;

declare @diff int;
set @diff= @nextWeekDay-@weekday;

--modulo 7 bijectively
declare @moduloed int;
set @moduloed = case 
    when @diff <=0 then @diff+7 
    else @diff
end;

return dateadd(day, @moduloed,  @time);

END