我的列中包含“第3周三”,“第2周二”,“每周四”等值。
我想创建一个读取这些字符串的列,并确定该月份是否已经到来,如果有,则返回下个月的日期。如果这个月没有通过,那么它将返回本月的日期。
上述预期结果(2016年4月22日)将是:'05 -18-2016','05 -10-2016','04 -28-2016'。
我希望以数学方式进行,并尽可能避免创建日历表。
感谢。
答案 0 :(得分:0)
这不符合'Every-'条目,但希望能给你一些灵感。我确信有很多测试用例会失败,你最好还是写一个存储过程。
我确实尝试通过计算当月第一天的日期名称和日期编号,然后计算下一个想要的日期并应用偏移量来做到这一点,但它变得很乱。我知道你说没有日期表,但CTE简化了事情。
CTE为当前日期和日期名创建日历。一些相当可疑的解析代码从测试数据中提取日期名称并加入CTE。 where子句过滤到大于第N次出现的日期,如果日期已过,则select会增加4周。或者至少那是理论:)
我正在使用DATEFROMPARTS
来简化代码,这是一个SQL 2012函数 - 2008年有SO的替代品。
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