Mysql 如何创建包含可轻松查询的事件的SQL日历?
我检查了几个关于这个主题的老问题,比如这个问题:但是,答案在性能方面非常糟糕,而且在实现中非常麻烦。从另一个答案中,很容易看出为什么接受的答案是个坏主意:一个月的事件需要90个查询。这是不能接受的 不管怎么说,这是我面临的问题,这样你就不会重读这些问题:Mysql 如何创建包含可轻松查询的事件的SQL日历?,mysql,postgresql,calendar,Mysql,Postgresql,Calendar,我检查了几个关于这个主题的老问题,比如这个问题:但是,答案在性能方面非常糟糕,而且在实现中非常麻烦。从另一个答案中,很容易看出为什么接受的答案是个坏主意:一个月的事件需要90个查询。这是不能接受的 不管怎么说,这是我面临的问题,这样你就不会重读这些问题: 以允许事件重复发生的方式存储事件。想想谷歌日历吧,在那里你可以指定“每月1号发生”或“每月2号星期一发生”(后者对我来说不太重要) 查询某个时间段的事件列表。例如,我想向某人显示未来2个月的事件列表,但我不想查询该月的每一天。这样做只会杀死服务
我非常感谢您的帮助!我读了几篇关于此主题的论文,但仍然找不到可以在SQL中特别使用的东西。我提出的解决方案是,我有一个事件表,其中有五个字段定义了事件的重复性,如下所述。然后,我还有一个用实际事件填充的计划表事件的发生。我确实需要一个结束日期,即使他们指定了几年后的某个事件,这也是一个每月类型的事件,不会在日程表中创建那么多条目。
因此,事件存储在一个事件表中,其中startDateTime和endDateTime描述了事件的整个持续时间(如果没有重复发生)。这两个datetime字段还定义了事件的总体开始和结束(如果是重复发生的事件)。在同一个事件表中,我们有五个字段定义了重复发生,如下所示低。 时间表表存储每个事件的单个事件。因此它有一个eventId、startDateTime和endDateTime。此开始和结束仅指每个事件,而不是整个跨度。 要查询一段时间内发生的所有计划事件,我只需查询计划表,检查是否有符合此条件的事件:
select * from schedule where schedule.startDateTime < @queryPeriodEnd and schedule.endDateTime > @queryPeriodStart
从schedule.startDateTime<@queryPeriodEnd和schedule.endDateTime>@queryPeriodStart所在的计划中选择*
此查询仅提供查询期间内部分或全部发生的计划条目。要获取事件数据,只需连接到事件表即可。
有趣的部分是计算一个月的第二个星期四。这发生在计算给定事件的所有预定事件的实际代码中。我也在下面附上我的代码
事件重复字段
重现
0=无复发
1=每日
2=每周
3=每月
递归间隔
这是两次复发之间的周期数。如果事件每5天复发一次,Recurse\u间隔将为5,Recurse将为1。如果事件每3周复发一次,Recurse\u间隔将为3,Recurse将为2
重现一天
如果用户选择了每月类型的定期,则为每月的某一天(例如:10日或14日)。该日期为该日期。如果用户未选择每月或特定的每月定期日期,则该值为0。否则,该值为1到31
递归顺序
如果用户选择了每月类型的定期,但选择了日期的顺序类型(例如:第一个星期一、第二个星期四、上个星期五)。这将具有顺序号。如果用户未选择此类型的定期,则值为0。
1=第一个
2=秒
3=第三
4=第四
5=最后一个
重复工作日
对于每周和每月的顺序重复,它存储重复发生的工作日。1=星期日
2=星期一
4=星期二
8=星期三
16=星期四
32=星期五
64=星期六
所以,每4周的周六和周日都是
递归=2,递归间隔=4,递归工作日=65(64+1)
同样,每月的第一个星期五每三个月一次
递归=3,递归间隔=3,递归顺序=1,递归工作日=32
代码
thisEvent.occurrences = new List<ScheduleInstance>();
DateTime currentDateTime = (DateTime) thisEvent.start;
DateTime currentEndTime;
BitArray WeekDayRecurrenceBits = new BitArray(new Byte[] {(Byte) thisEvent.recursWeekdays});
while (currentDateTime < thisEvent.end)
{
currentEndTime = new DateTime(currentDateTime.Year, currentDateTime.Month, currentDateTime.Day,
thisEvent.end.Value.Hour, thisEvent.end.Value.Minute, thisEvent.end.Value.Second);
switch (thisEvent.recurs)
{
case (RecurrenceTypeEnum.None):
AddOccurrenceToRooms(thisEvent, currentDateTime, currentEndTime);
currentDateTime = (DateTime)thisEvent.end;
break;
case (RecurrenceTypeEnum.Daily):
AddOccurrenceToRooms(thisEvent, currentDateTime, currentEndTime);
currentDateTime = currentDateTime.AddDays(thisEvent.recursInterval);
break;
case (RecurrenceTypeEnum.Weekly):
int indexIntoCurrentWeek = (int) currentDateTime.DayOfWeek;
while ((indexIntoCurrentWeek < 7) && (currentDateTime < thisEvent.end))
{
if (WeekDayRecurrenceBits[(int) currentDateTime.DayOfWeek])
{
AddOccurrenceToRooms(thisEvent, currentDateTime, currentEndTime);
}
currentDateTime = currentDateTime.AddDays(1);
currentEndTime = currentEndTime.AddDays(1);
indexIntoCurrentWeek++;
}
currentDateTime = currentDateTime.AddDays(7 * (thisEvent.recursInterval - 1));
break;
case (RecurrenceTypeEnum.Monthly):
if (thisEvent.recursDay == 0)
{
DateTime FirstOfTheMonth = new DateTime(currentDateTime.Year, currentDateTime.Month, 1);
int daysToScheduleOccurrence = ((thisEvent.recursWeekdays - (int)FirstOfTheMonth.DayOfWeek + 7) % 7)
+ ((thisEvent.recursOrdinal - 1) * 7)
- currentDateTime.Day + 1;
if (daysToScheduleOccurrence >= 0)
{
currentDateTime = currentDateTime.AddDays(daysToScheduleOccurrence);
currentEndTime = currentEndTime.AddDays(daysToScheduleOccurrence);
if (currentDateTime < thisEvent.end)
{
AddOccurrenceToRooms(thisEvent, currentDateTime, currentEndTime);
}
}
}
else
{
if (currentDateTime.Day <= thisEvent.recursDay && thisEvent.recursDay <= DateTime.DaysInMonth(currentDateTime.Year, currentDateTime.Month) )
{
currentDateTime = currentDateTime.AddDays(thisEvent.recursDay - currentDateTime.Day);
currentEndTime = currentEndTime.AddDays(thisEvent.recursDay - currentEndTime.Day);
AddOccurrenceToRooms(thisEvent, currentDateTime, currentEndTime);
}
}
currentDateTime = currentDateTime.AddDays((currentDateTime.Day - 1) * -1).AddMonths(thisEvent.recursInterval);
break;
default:
break;
}
}
thisEvent.occurrents=new List();
DateTime currentDateTime=(DateTime)thisEvent.start;
日期时间currentEndTime;
BitArray WeekDayRecurrenceBits=新的位数组(新字节[]{(字节)thisEvent.RecurseWeekdays});
while(currentDateTime