3

如果这样的假期是经常性的(即新年),我有一个整洁的假期表,显示日期和重复性

在此处输入图像描述

现在,我需要计算两个日期之间的假期数。如果它是一个简单的日期列表,没有关于重复的信息(即它会显示 2000 年 1 月 1 日到 2015 年 1 月 1 日之间的所有新年),那将很容易,即类似于

declare @start_Date Date= '2013-01-02',
@end_date Date ='2014-01-02'



SELECT  COUNT(CE.name) AS holidays_count
FROM dbo.argo_cal_event AS CE INNER JOIN  dbo.argo_cal_event_type AS CET 
ON CE.event_type_gkey = CET.gkey
WHERE (CET.name = 'EXEMPT_DAY') AND (CE.name <> 'Sundays')
AND (CE.occ_start BETWEEN @start_Date AND @end_date) 

但是现在我们有一个简洁的重复,所以上面的查询不会计算所有被宣布为“每年开始”发生的新年、圣诞节等。

我可以用这样的列表创建一个表,但我一直在想,还有其他方法吗?

编辑:让我准确地说出我的想法:如果事件发生一次,我想正常计算事件(我在这里假设用户必须填充所有不规则的假期,即复活节),但是当重复< > 一次,然后获取发生开始并计算该日期和最终日期之间的年数。

EDIT2:我想我已经明白了 - 对于我可以使用的经常性假期

SELECT sum (datediff (year, ce.occ_start, @end_date)) as recurrent_holidays
FROM dbo.argo_cal_event AS CE INNER JOIN  dbo.argo_cal_event_type AS CET 
ON CE.event_type_gkey = CET.gkey
 WHERE (CET.name = 'EXEMPT_DAY') and (CE.repeat_interval ='ANNUALLY')

EDIT3:不幸的是,如果我想在两个日期之间计数,其中一个是从另一个表中取出的,即如果我想计算单元之间的经常性假期,那么这个解决方案不起作用(或者至少变得相当复杂)。 time_in 和 getddate() :/

4

3 回答 3

1

最直接的方法是让它们都一次性出现。

桌子不会那么大,你不能在每个星期天添加。每年只有 52 或 53 个条目。

如果你现在这样做,你可以做类似的事情,

select count(*) from events where event_date between start_date and end_date

完毕。

但是,这样做的主要原因是您的某些假期很难计算。您需要计算(或查找)耶稣受难日、复活节星期一等的日期。它们基于月相。

为什么不把它们全部计算出来,让您的查询变得非常简单呢?

最后,你的数据结构有多“整洁”并不重要,重要的是你的代码是否完成了它应该做的事情,完成它需要多长时间,以及让它工作需要多少努力.

于 2013-09-30T22:44:16.407 回答
0

一种可怕的方法:

declare @Holidays as Table ( Name VarChar(16), OccurrenceStart Date, Recurrence VarChar(10) );
insert into @Holidays ( Name, OccurrenceStart, Recurrence ) values
  ( 'New Year Day', '20000101', 'Annually' ),
  ( 'Sundays', '20000202', 'Weekly' ),
  ( 'Labour Day 2014', '20141027', 'Once' );
select * from @Holidays;

declare @Start as Date = '20130102';
declare @End as Date = '20150101';

with DateRange as ( -- All dates from   @Start   to   @End .
  select @Start as ADate
  union all
  select DateAdd( day, 1, DR.ADate )
    from DateRange as DR
    where DR.ADate < @End ),
  Once as ( -- Holidays that occur once within the date range.
  select DR.ADate as Holiday
    from DateRange as DR inner join
      @Holidays as H on H.OccurrenceStart = DR.ADate and H.Recurrence = 'Once' ),
  Weekly as ( -- Holidays that occur weekly within the date range, give or take.
  select DateAdd( week, case when H.OccurrenceStart < @Start then DateDiff( week, H.OccurrenceStart, @Start ) else 0 end, H.OccurrenceStart ) as Holiday
    from @Holidays as H
    where H.OccurrenceStart <= @End and H.Recurrence = 'Weekly'
  union all
  select DateAdd( week, 1, W.Holiday )
    from Weekly as W
    where DateAdd( week, 1, W.Holiday ) <= @End ),
  Annually as ( -- Holidays that occur annually within the date range, give or take.
  select DateAdd( year, case when H.OccurrenceStart < @Start then DateDiff( year, H.OccurrenceStart, @Start ) else 0 end, H.OccurrenceStart ) as Holiday
    from @Holidays as H
    where H.OccurrenceStart <= @End and H.Recurrence = 'Annually'
  union all
  select DateAdd( year, 1, A.Holiday )
    from Annually as A
    where DateAdd( year, 1, A.Holiday ) <= @End )
  select Count( 42 ) as 'Number of Holidays'
    from DateRange as DR inner join
      ( select Holiday from Once union
        select Holiday from Weekly union
        select Holiday from Annually ) as H on H.Holiday = DR.ADate
  option ( MaxRecursion 0 );

请注意,一天中的多次“点击”,例如周日落在元旦,被计为一个假期。有更有效的方法来生成DateRange,例如使用数字表。整个事情是可怕的。

问,你会被欺骗。

于 2013-10-01T03:12:36.153 回答
0

您可以创建一个函数,在您的假期表中搜索每种类型的假期(每周、每月、每年、一次性等),甚至“Nth/Last/Nth Last Whateverday of Whichevermonth”(这将是每年的变体) , 并且对于每个假期,按时间间隔,循环并递增每个假期日期,并检查它是否落在函数需要作为参数的日期StartDate和日期之间。EndDate您甚至可以找到复活节日期计算算法并将其插入。

但是,这样的函数不会像简单的Select语句那样简单或快速 - 您需要决定是否值得花费时间和精力来开发这样的函数,并且它可能对您的查询造成的性能损失值得灵活性它会给你和你的用户。

几乎什么可以做;你也应该问是否应该这样做......

于 2013-09-30T22:54:43.737 回答