2014-11-06 62 views
0

我有一些日期希望用SQL过滤。SQL - 检查日期是否是该月当天第一次发生

我希望能够通过一个标志来说明从X日期到Y日期的所有月份的第一个星期一。

所以基本上,我想通过一个日期,并能够告诉它是否是给定月份的第一个,第二个,第三个,第四个或最后一个星期一(例如)。

我已经过滤掉了几个月和几天,我目前正在使用DATEPART(DAY, thedate)检查一天是否为< 8然后是一周< 15 2周等....但这是不正确的。

所以我卡在的部分是Where IsDateFirstOfMonth(@date) 我在哪里开始写功能IsDateFirstOfMonth? 任何帮助非常赞赏

+4

有什么不对的检查月份的一天少于8? – 2014-11-06 21:21:46

+0

您是否试图确定'@ date'是第一个星期一,还是在本月的第一个星期(即,是否在同一月的第一个日期的同一周)?这几乎听起来像你正在努力做到这一点。 – 2014-11-06 21:40:08

+0

那么我有一个完整的日期列表。让我们说从今天到今年年底的所有星期一。我希望可以选择在每个月内返回第一或第二或第三或第四个星期一或最后一个星期一。所以如果我使用> 8或> 15等逻辑。它不会总是工作的第四或最后 – user2329438 2014-11-06 21:42:07

回答

0

你可以做到这一点

alter function IsDateFirstOfMonth(@date as datetime) 
returns int 
as 
begin 
    declare @first datetime, 
      @last datetime, 
      @temp datetime, 
      @appearance int 
    declare @table table(Id int identity(1,1), 
         StartDate datetime, 
         EndDate datetime, 
         DayName nvarchar(20), 
         RowNumber int) 
    set @first=dateadd(day,1-day(@date),@date) 
    set @last=dateadd(month,1,@first)-1 
    set @[email protected] 
    while @temp<[email protected] 
    begin 
     insert into @table(StartDate,EndDate,DayName) values(@temp,@temp+6,datename(dw,@temp)) 
     set @[email protected] +1 
    end  
    select @appearance=Nb 
    from(
    select StartDate,EndDate,DayName,row_number() over (partition by DayName order by StartDate) as Nb 
    from @table) t 
    where @date between t.StartDate and t.EndDate and datename(dw,@date)=t.DayName 

    if @[email protected]<7 
     set @appearance=-1 

    return @appearance 
end 



select dbo.IsDateFirstOfMonth('31 Dec 2014')  
    select dbo.IsDateFirstOfMonth('03 Nov 2014') -- result 1 (first) monday 
    select dbo.IsDateFirstOfMonth('10 Nov 2014') -- result 2 (second) 
    select dbo.IsDateFirstOfMonth('17 Nov 2014') -- result 3 (third) 
    select dbo.IsDateFirstOfMonth('24 Nov 2014') -- result -1 (last) .... here it will be the last monday 
    select dbo.IsDateFirstOfMonth('02 Nov 2014') -- result 1 (first) sunday 

希望这将帮助你

+0

非常感谢你的帮助。这工作得很好,但只为星期一好像?也许我不太清楚,但我只是以星期一为例。如果我删除如果检查星期一,并运行'2014年11月15日'我得到2而不是3,因为它是11月的第三个星期六。再次感谢您的帮助。如果你不介意解释所有嵌套的datediffs是如何工作的,这将是最值得赞赏的,也许我可以调试自己;) – user2329438 2014-11-06 23:04:09

+0

删除if(datename(dw,@ date)='Monday'),那么它将工作一周中的所有日子 – Monah 2014-11-06 23:05:14

+0

我做到了,但就像我说的,当我运行'2014年11月15日'我得到2,而不是预期的3,因为它是11月第三个星期六.cheers – user2329438 2014-11-06 23:09:20

1

对于这样的问题,它通常更容易实现一个表所需的最新信息和加入表中,并使用它过滤。即创建一个表,这个信息:

CREATE TABLE Dates(
    Date DATE PRIMARY KEY CLUSTERED, 
    PositionInMoth TINYINT, 
    LastInMonth BIT) 

然后使用任何你想要的方式填写此表。我想你会用一个简单的临时应用程序很容易地做到这一点,但你也可以使用T-SQL脚本来创建它。

然后,您只需要将此表与此表连接起来,并使用PositionInMoth或LastInMonth列进行过滤。您还可以将其用作查找表来轻松实现所需的功能。

顺便说一下,不要忘记,有多个月有一个给定的一天的第五个例子,例如,2014年12月有5个星期一,5个星期二和5个星期三。给定motnh中有5个实例的天数为:本月的天数 - 28,例如12月份的31-28 = 3。所以你不能指望第4天是最后一天。

该表确实占用很少的空间,大致,为DATE 3个字节,对于TINYINT 1个字节,为BIT 1个字节,所以它的3 + 1 + 1 =每天5个字节,1,825字节每年和178千兆整个世纪。所以,即使你需要几个世纪才能涵盖所有可能的日期,我仍然是一个非常小的桌子。我说大致为,因为索引结构,填充因子和其他一些东西会使表格稍微大一些。如此小的表格意味着SQL Server在执行查询时可以轻松地将整个表格缓存在内存中,因此您的表格将运行得非常快。

注:您可以通过添加新BIT

非常展开该表格涵盖如检查等方面的需求,如果一天是在本月的最后一个,或最后一个或第一个工作日,在一个月内,有趣的链接,从OP评论:CALENDAR TABLES IN T-SQL

+0

谢谢JotaBe,我在这段时间找到了这篇文章,并决定与你的建议一起去http://blog.aware.co.th/calendar-tables-在-T-SQL / – user2329438 2014-11-07 16:38:10

相关问题