我被要求进行T-SQL挑战,我需要根据这样的日期位置获得下个月的同等日期:
今天是2011年7月18日,换句话说就是本月的第三个星期一......
现在我需要在SQL Server查询中获得下个月的第三个星期一(15/08/2011)。
这就像谷歌日历的重复规则。
我一直在尝试很多公式,但它变得非常复杂,任何帮助都会非常感激。
答案 0 :(得分:3)
此合成语将在下周的同一天计算,如果不存在则输入null
declare @t datetime
set @t = '2008-01-29'
select case (datepart(day, @t)+ 6) / 7
when (datepart(day, @t + 28)+ 6) / 7 then @t + 28
when (datepart(day, @t + 35)+ 6) / 7 then @t + 35
else null end
答案 1 :(得分:2)
CREATE FUNCTION fnSameDayOfWeekNextMonth (@Date datetime)
RETURNS datetime
AS BEGIN
RETURN (
SELECT
DATEADD(WEEK,
CASE (MONTH(ApproxDate) - MONTH(@Date) + 12) % 12
WHEN 2 THEN -1
ELSE ThisDayNum - (DAY(ApproxDate) - 1) / 7
END,
ApproxDate)
FROM (
SELECT
ThisDayNum = (DAY(@Date) - 1) / 7,
ApproxDate = DATEADD(WEEK, 5, @Date)
) s
)
END
此函数实现以下逻辑:
获取给定日期的大致日期加上恰好5周。
获取指定日期月份的星期几。
如果近似日期的月份是给定日期月份后的2个月,则从近似日期减去一周并返回结果。
否则与#2相同,但是对于近似日期(而不是给定日期)。
获得#2和#4之间的区别。
从近似日期减去#5,作为周数,并返回结果。
步骤#3意味着如果当前日期是第五个,那么结果日期将是下个月的第四个相同的工作日,因为第五个将是不可能的。在我看来,更新: @t-clausen.dk提供了在这种情况下返回NULL的更好主意。可以轻松修改上述函数以遵循相同的约定:…WHEN 2 THEN -1…
部分应简单地更改为…WHEN 2 THEN NULL…
。
答案 2 :(得分:1)
幸运的是,我必须这样做一次:http://blog.prokrams.com/2007/06/18/determining-the-ordinal-of-a-weekday/
Create Function fn_ReturnOrdinalDay( @TestDate datetime) returns int
begin
declare@ordinal int,@loopdate datetime
set @loopdate = @TestDateset
set @ordinal = 0
while datepart(m, @TestDate) = datepart(m, @loopdate)
begin
set @ordinal = @ordinal + 1
set @testdate = dateadd(d, -7, @testdate)
end
return @ordinal
end
ETA:要找到相同序数的第二天,你只需要在今天的日期添加+7,直到fn_ReturnOrdinalDay返回与今天相同的结果。
答案 3 :(得分:1)
我会使用日历表来执行此操作:您可以每天填充一行,然后您只需编写一个简单的查询来回答您的问题。您仍然可以使用其他海报建议的功能和逻辑来填充表格,但这将是一次性任务。如果您使用重复日期进行大量工作,则可以使用字符串值为“first Monday”,“third Wednesday”等的列,以便于查询。
您的查询可能如下所示:
select
min(BaseDate)
from
dbo.Calendar
where
DayDescription = (select DayDescription from dbo.Calendar where BaseDate = @Today) and
BaseDate > @Today
换句话说,给我今天之后的第一个日期,其中DayDescription(即“第三个星期一”或其他)与今天相同。该日期必须是下个月的第三个星期一。确切的查询将取决于您的数据类型以及搜索参数值。
作为一般观察,许多(大多数?)与日期相关的查询使用预先填充的表比使用函数更容易回答。
答案 4 :(得分:0)
如果您只需要进行上述挑战,那么这相对容易。
使用日期格式功能找出当天的名字(我记不起确切的名字)。
从月初开始循环,并保持数字的计数,例如在你到达输入日期之前,你会遇到星期二。
然后在下个月(或任何一个月)循环x次,一旦达到所需数量,请在下周二进行
答案 5 :(得分:0)
这可能对某人有所帮助,如果你想从现在起几个月内获得序数日期,我已经将这个功能创建为你所有建议的组合:
CREATE FUNCTION [dbo].[fncSameDayOfWeekAnotherMonth] (@Date datetime, @Months int)
RETURNS datetime
AS BEGIN
declare @FONM datetime, @day TinyInt, @ordinal tinyint, @FDM datetime, @result datetime
Set @FONM = DATEADD(dd,-(DAY(DATEADD(mm,@Months,@Date))-1),DATEADD(mm,@Months,@Date))--first day of month
Set @day = datepart(weekday,@Date)+7
set @ordinal=ceiling( cast(datepart(day,@Date)as float)/7 )--ordinal day
set @FDM = DateAdd(day, ((@day -DatePart(weekday, @FONM))%7), @FONM)--first day of week (monday, friday, etc) on month
set @result = DateAdd(day, (@ordinal-1)*7, @FDM)
RETURN case when DATEDIFF(month, @Date, @result) > @Months then DateAdd(day, (@ordinal-2)*7, @FDM) else @result end --if result exceeds number of months just subtract one week from ordinal
END
它接收日期和月数,获取当天的序数和您想要的月份的第一天。使用此最后一个查找该月中第一次出现的工作日,然后它会根据您的日期计算相应的有序日期。
我知道它有很多代码,可能会有所改进,但至少它的效果非常好。
答案 6 :(得分:0)
- 第三个星期三
DATEPART(dw,PromptDate)+ DATEPART(dw,PromptDate - 7)+ DATEPART(dw,PromptDate - 14)= 12
- 不应该是周三的第4或第5周,因为我们只对第3个星期三感兴趣。
AND DATEDIFF(MONTH,PromptDate - 14,PromptDate - 21)<> 0