在SQL中查找一周中某一天的下一个匹配项

时间:2012-01-25 23:31:04

标签: sql-server-2005 tsql datetime

我正在尝试更新SQL报告sproc的WHERE子句,以检查给定日期是在下一次出现的类之前还是之前。课程有一个StartDate,每周在同一天发生一次。鉴于StartDate,我如何找到一周中那一天的下一次出现?

E.G。如果StartDate是2012年1月18日,星期三,我运行截至今天,2012年1月26日的报告,我需要找到2/1/2012,即1/26之后的下一个星期三。如果StartDate是1/19,周四,我今天运行报告,公式应该给我今天的周四1/26。

这是SQL中的一种想法:

SELECT *
FROM tbl_Class cs
INNER JOIN tbl_Enrollment sce ON cs.pk_ClassID = sce.fk_ClassID
WHERE ...
AND sce.StartDate < [Find date of next class after @AsOfDate using cs.StartDate]

3 个答案:

答案 0 :(得分:1)

这是我提出的一些示例SQL。 3次迭代,这样你就可以了解我的结果。第3次迭代应该是您可以通过将列名替换为变量而合并到WHERE子句中。

设定:

DECLARE @Startdate DATETIME,@currentdate datetime
SET @Startdate = '1-26-2012' 
SET @Currentdate = '1-23-2012'

--This section just normalizes it so you can use 7 as the interval
--The offset depends on your current setting for DATEFIRST, U.S. English default is 7, Sunday.
-- see http://msdn.microsoft.com/en-us/library/ms187766.aspx 
DECLARE @StartDateWorkingDayOfWeek int,@CurrentDateWorkingDayOfWeek int
SELECT @StartDateWorkingDayOfWeek =(DATEPART(weekday,@Startdate)-2)
SELECT @CurrentDateWorkingDayOfWeek=(DATEPART(weekday,@Currentdate)-2)

迭代#1

--Iteration 1 
IF @StartDateWorkingDayOfWeek < @CurrentDateWorkingDayOfWeek
SELECT DATEADD(DAY,DATEDIFF(DAY,0,@Currentdate)/7*7 + 7,@StartDateWorkingDayOfWeek)
else
SELECT DATEADD(DAY,DATEDIFF(DAY,0,@Currentdate)/7*7 + 0,@StartDateWorkingDayOfWeek)

迭代#2

--Iteration 2
SELECT DATEADD(DAY,DATEDIFF(DAY,0,@Currentdate)/7*7 + 

CASE WHEN @StartDateWorkingDayOfWeek < @CurrentDateWorkingDayOfWeek
    then 7
    ELSE 0
    end

    ,@StartDateWorkingDayOfWeek)

迭代#3

--iteration 3
SELECT DATEADD(DAY,DATEDIFF(DAY,0,@Currentdate)/7*7 + 

CASE WHEN (DATEPART(weekday,@Startdate)-2) < (DATEPART(weekday,@Currentdate)-2)
    then 7
    ELSE 0
    end

    ,(DATEPART(weekday,@Startdate)-2))

给本文提示: http://www.sqlmag.com/article/tsql3/datetime-calculations-part-3

答案 1 :(得分:0)

感谢TetonSig及其对此链接的引用,我想出了这些内容:http://www.sqlmag.com/article/tsql3/datetime-calculations-part-3

我们可以将上一个星期一的日期排除在当前日期之前(@AsOfDate),如下所示:

SELECT DATEADD(day, DATEDIFF(day,0, @AsOfDate-1) /7*7, 0);

这将获得1/1/1900和@AsOfDate之间的天数天数。 / 7 * 7将其转换为整周,然后将其添加回到1/1/1900(星期一)以获得@AsOfDate之前的星期一。 -1使其不包含@AsOfDate。没有减1,如果@AsOfDate在星期一,它将被计为“前一个”星期一。

接下来作者表示,为了在下周一获得包容性,我们只需要将7添加到上一个星期一的独家公式:

SELECT DATEADD(d, DATEDIFF(day,0, @AsOfDate-1) /7*7, 0)+7;

瞧!我们现在已经在@AsOfDate之后的第一个星期一了。唯一的问题是,上面的星期一(0)在我的情况下是一个移动的目标。我需要按课程日期确定的第一个[DayOfWeek],而不是第一个星期一。我需要换掉上面0的ClassDayOfWeek计算:

DATEADD(d, DATEDIFF(d, [ClassDayOfWeek], @AsOfDate-1)/7*7, [ClassDayOfWeek])+7

我想计算ClassDayOfWeek而不依赖或不得不设置@@ datefirst。所以我相对于基准日计算了它:

DATEDIFF(d, 0, StartDate)%7

这为Mon提供0,为Sun提供6,因此我们现在可以将其插入[ClassDayOfWeek]。我应该指出,这个0-6的值是以1/1 / 1900-1 / 7/1900表示为int的日期。

DATEADD(d, DATEDIFF(d, DATEDIFF(d, 0, StartDate)%7, @AsOfDate-1)/7*7, DATEDIFF(d, 0, StartDate)%7)+7

根据问题使用:

SELECT *
FROM tbl_Class cs
INNER JOIN tbl_Enrollment sce ON cs.pk_ClassID = sce.fk_ClassID
WHERE ...
AND sce.StartDate < DATEADD(d, 
                            DATEDIFF(d, 
                                     DATEDIFF(d, 0, cs.StartDate)%7, 
                                     @AsOfDate-1)/7*7, 
                            DATEDIFF(d, 0, cs.StartDate)%7)+7

答案 2 :(得分:0)

我用一个简单的案例陈述得出了答案 在你的情况下,@ targetDOW将是班级的一周。

DECLARE @todayDOW INT = DATEPART(dw, GETDATE());
DECLARE @diff INT = (@targetDOW - @todayDOW);

SELECT
    CASE
       WHEN @diff = 0 THEN GETDATE()
       WHEN @diff > 0 THEN DATEADD(d,@diff,GETDATE())
       WHEN @diff < 0 THEN DATEADD(d,@diff + 7,GETDATE())   
    END;