如果这样的假期是经常性的(即新年),我有一张整齐的假期表,显示日期和复发情况
现在,我需要计算两个日期之间的假期数。如果这是一个简单的日期列表,没有关于重复的信息(因此它会显示2000-01-01和2015-01-01之间的所有新年),那将非常简单,例如
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)
但是现在我们有一个整齐的复发,所以上面的查询将不会计算所有新年,圣诞节等已被宣布为“每年从”开始的事件。
我 COULD 创建一个包含此类列表的表,但我一直在想,还有其他方法吗?
编辑:让我准确地记住我的想法:如果事件发生一次,我想正常计算事件(我假设用户必须填写所有不规则的假期,即复活节),但是当复发&lt;&gt;一次,然后获取事件开始并计算该日期和最终日期之间的年份。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:遗憾的是,如果我想在两个日期之间计算,这个解决方案不起作用(或者至少变得非常复杂),其中一个是从另一个表中获取的,即我是否想要计算定期假期在unit.time_in和getddate()之间:/
答案 0 :(得分:1)
最直接的方法是将它们全部一次性出现。
该表不会是那个大,你不能在每个星期天添加。每年只有52或53个参赛作品。
如果您这样做,现在可以做类似的事情,
select count(*) from events where event_date between start_date and end_date
完成。
但这样做的主要原因是,你的一些假期很难计算。你需要计算(或查找)耶稣受难日,复活节星期一和其他日期。它们基于月相。
为什么不直接计算它们并使您的查询变得非常简单?
最后,重要的是你的数据结构的“整洁”程度,以及你的代码是否完成它应该做的事情,完成它需要多长时间以及需要花费多少精力等等。让它工作。
答案 1 :(得分:0)
您可以创建一个功能,在您的假期表中搜索每种类型的假期(每周,每月,每年,一次性,等等)或甚至“Nth / Last / Nth Last Wonnaday of the of Marchmonth”(这将是一个变体) on Yearly),对于每个假日,按间隔间隔,循环并递增每个假日日期,并检查它是否在函数需要作为参数的StartDate
和EndDate
日期之间。您甚至可以找到复活节日期计算算法并插入它。
但是,这样的函数不会像简单的Select
语句那样简单或快速 - 你需要决定是否值得花费时间和精力来开发这样一个函数,以及它可能带来的性能损失强加于您的查询是值得的,它会给您和您的用户带来灵活性。
几乎所有都可以完成;你还应该问一下是否应该完成......
答案 2 :(得分: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
,例如用数字表。整件事情都很可怕。
要求你们被欺骗。