[英]Get date for nth day of week in nth week of month
I have a column with values like '3rd-Wednesday', '2nd-Tuesday', 'Every-Thursday'. 我有一列的值,例如“ 3rd-Wednesday”,“ 2nd-Tuesday”,“ Every-Thursday”。
I'd like to create a column that reads those strings, and determines if that date has already come this month, and if it has, then return that date of next month. 我想创建一个读取这些字符串的列,并确定该日期是否已到本月,如果已经到,则返回下个月的日期。 If it has not passed yet for this month, then it would return the date for this month.
如果这个月还没有过去,那么它将返回这个月的日期。
Expected results (on 4/22/16) from the above would be: '05-18-2016', '05-10-2016', '04-28-2016'. 上述的预期结果(2016年4月22日)将为:'05 -18-2016','05-10-2016','04-28-2016'。
I'd prefer to do it mathematically and avoid creating a calendar table if possible. 我更喜欢数学上的方法,并且尽可能避免创建日历表。
Thanks. 谢谢。
This doesn't cater for 'Every-' entries, but hopefully will give you some inspiration. 这并不适合“每个”条目,但希望能给您一些启发。 I'm sure there are plenty of test cases this will fail on, and you might be better off writing a stored proc.
我确信有很多测试用例会失败,并且最好写一个存储的proc。
I did try to do this by calculating the day name and day number of the first day of the month, then calculating the next wanted day and applying an offset, but it got messy. 我确实尝试过通过计算月份的第一天的日期名称和天数,然后计算下一个想要的日期并应用偏移量来做到这一点,但这很麻烦。 I know you said no date table but the CTE simplifies things.
我知道您说没有日期表,但CTE可以简化事情。
A CTE creates a calendar for the current month of date and dayname. CTE为日期和日期的当前月份创建日历。 Some rather suspect parsing code pulls the day name from the test data and joins to the CTE.
一些相当可疑的解析代码从测试数据中提取了日期名称,并加入了CTE。 The where clause filters to dates greater than the Nth occurrence, and the select adds 4 weeks if the date has passed.
where子句过滤的日期大于第N个出现的日期,如果日期已过,则select加4周。 Or at least that's the theory :)
或至少这是理论:)
I'm using DATEFROMPARTS
to simplify the code, which is a SQL 2012 function - there are alternatives on SO for 2008. 我正在使用
DATEFROMPARTS
来简化代码,这是SQL 2012的功能-SO的替代品是2008。
SELECT * INTO #TEST FROM (VALUES ('3rd-Wednesday'), ('2nd-Tuesday'), ('4th-Monday')) A(Value)
SET DATEFIRST 1
;WITH DAYS AS (
SELECT
CAST(DATEADD(MONTH,DATEDIFF(MONTH,0,GETDATE()),N.Number) AS DATE) Date,
DATENAME(WEEKDAY, DATEADD(MONTH,DATEDIFF(MONTH,0,GETDATE()),N.Number)) DayName
FROM master..spt_values N WHERE N.type = 'P' AND N.number BETWEEN 0 AND 31
)
SELECT
T.Value,
CASE WHEN MIN(D.Date) < GETDATE() THEN DATEADD(WEEK, 4, MIN(D.DATE)) ELSE MIN(D.DATE) END Date
FROM #TEST T
JOIN DAYS D ON REVERSE(SUBSTRING(REVERSE(T.VALUE), 1, CHARINDEX('-', REVERSE(T.VALUE)) -1)) = D.DayName
WHERE D.Date >=
DATEFROMPARTS(
YEAR(GETDATE()),
MONTH(GETDATE()),
1+ 7*(CAST(SUBSTRING(T.Value, 1,1) AS INT) -1)
)
GROUP BY T.Value
Value Date
------------- ----------
2nd-Tuesday 2016-05-10
3rd-Wednesday 2016-05-18
4th-Monday 2016-04-25
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.