Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/postgresql/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mysql 如何创建包含可轻松查询的事件的SQL日历?_Mysql_Postgresql_Calendar - Fatal编程技术网

Mysql 如何创建包含可轻松查询的事件的SQL日历?

Mysql 如何创建包含可轻松查询的事件的SQL日历?,mysql,postgresql,calendar,Mysql,Postgresql,Calendar,我检查了几个关于这个主题的老问题,比如这个问题:但是,答案在性能方面非常糟糕,而且在实现中非常麻烦。从另一个答案中,很容易看出为什么接受的答案是个坏主意:一个月的事件需要90个查询。这是不能接受的 不管怎么说,这是我面临的问题,这样你就不会重读这些问题: 以允许事件重复发生的方式存储事件。想想谷歌日历吧,在那里你可以指定“每月1号发生”或“每月2号星期一发生”(后者对我来说不太重要) 查询某个时间段的事件列表。例如,我想向某人显示未来2个月的事件列表,但我不想查询该月的每一天。这样做只会杀死服务

我检查了几个关于这个主题的老问题,比如这个问题:但是,答案在性能方面非常糟糕,而且在实现中非常麻烦。从另一个答案中,很容易看出为什么接受的答案是个坏主意:一个月的事件需要90个查询。这是不能接受的

不管怎么说,这是我面临的问题,这样你就不会重读这些问题:

  • 以允许事件重复发生的方式存储事件。想想谷歌日历吧,在那里你可以指定“每月1号发生”或“每月2号星期一发生”(后者对我来说不太重要)
  • 查询某个时间段的事件列表。例如,我想向某人显示未来2个月的事件列表,但我不想查询该月的每一天。这样做只会杀死服务器(数千行事件中的每个用户)
  • DB不可知论。我使用PgSQL,并在其他论坛上看到许多关于这个问题的答案,这些论坛使用MS SQL特定的东西或Oracle

  • 我非常感谢您的帮助!我读了几篇关于此主题的论文,但仍然找不到可以在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