我需要的是今天下一天(周一,周二,周三......)的日期。
允许用户选择他们想要的日期,并将其作为int存储在表格中。 "下周二打电话给我(3)"
Sunday = 1
Monday = 2
Tuesday = 3
...
所以我的表看起来像这样。
UserID, NextDayID
我想出的是:
select dateadd(dd,(7 - datepart(dw,GETDATE()) + NextDayID ) % 7, getdate())
如果您今天要求下一天我可以在需要的时候添加一周,这似乎有效并且将在今天返回。
我想知道的是,这是一个很好的解决方案还是我缺少的东西?
答案 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';
实际上,您可能希望日历表中有更多列,因为您会发现它有很多用途。
此外,通常可以看到使用日历表的代码显然正确。阅读上面的代码很简单:选择今天之后的最小日历日期和星期一。很难看到依赖于日期函数和日期算术的代码显然是正确的。
答案 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