【问题标题】:Displaying Scheduled Events显示预定事件
【发布时间】:2010-12-26 15:23:57
【问题描述】:

几年前我遇到了这个问题,当时我实施了“不同的逻辑”来交付项目,但我的脑海中仍然存在疑问,希望在你的帮助下我现在能够理解它。

假设我的数据库中有一些预定事件可能会在几天内产生,也可能不会产生:

id    event           start          end
-----------------------------------------------
1     fishing trip    2009-12-15     2009-12-15
2     fishCON         2009-12-18     2009-12-20
3     fishXMAS        2009-12-24     2009-12-25

现在我想在日历中显示事件,让我们以 12 月份为例:

for ($day = 1; $day <= 31; $day++)
{
    if (dayHasEvents('2009-12-' . $day) === true)
    {
        // display the day number w/ a link
    }

    else
    {
        // display the day number
    }
}

dayHasEvents() 函数应该执行什么查询来检查当天是否有(或没有)事件?我猜SELECT .. WHERE .. BETWEEN 在这里最有意义,但我不知道如何实现它。我的方向正确吗?

提前致谢!


@詹姆斯:

假设我们在 12 月 19 日

SELECT *
FROM events
WHERE start >= '2009-12-19 00:00:00'
  AND end <= '2009-12-19 23:59:59'

应该返回事件#2,但什么也不返回。 =\

【问题讨论】:

  • @Alix,我的代码有错误。我交换了比较标志。再次检查:)
  • 谢谢,这很简单。猜猜那是我犯的同一个错误。

标签: php database calendar scheduling


【解决方案1】:

您应该放弃该方法并预先获取给定月份的所有事件,这样您只需要执行一次查询,而不是 N 次查询,其中 N 是该月的天数。

然后您可以将返回的结果存储在一个多维数组中,如下所示:

// assume event results are in an array of objects in $result
$events = array();
foreach ($result as $r) {
    // add event month and day as they key index
    $key = (int) date('j', strtotime($r->start));
    // store entire returned result in array referenced by key
    $events[$key][] = $r;
}

现在您将拥有给定月份的多维事件数组,其中键是日期。您可以通过以下方式轻松检查某一天是否存在任何事件:

$day = 21;
if (!empty($events[$day])) {
    // events found, iterate over all events
    foreach ($events[$day] as $event) {
        // output event result as an example
        var_dump($event);
    }
}

【讨论】:

  • 不幸的是,您的方法不包括多日活动...如果活动开始 @2011-01-26 并结束 @2011-01-30,则只会突出显示开始日期。我还没有弄清楚如何正确应用@James 提供的工作解决方案,并且整个月只发出一个查询。
【解决方案2】:

您绝对是在正确的轨道上。以下是我将如何去做:

SELECT *
FROM events
WHERE start <= '2009-12-01 00:00:00'
  AND end >= '2009-12-01 23:59:59'

您显然只是将这些日期值替换为您正在检查的日期。

【讨论】:

  • @Alix,我的代码有错误。我交换了比较标志。再次检查:)
【解决方案3】:

James 对 SQL 语句的想法是正确的。您绝对不想在 for 循环中运行多个 MySQL SELECTs。如果daysHasEvents 运行SELECT,那就是31 个单独的SQL 查询。哎哟!真是个性能杀手。

相反,将一个月中发生事件的日期加载到数组中(使用一个 SQL 查询),然后遍历这些天。像这样的:

$sql= "SELECT start, end FROM events WHERE start >= '2009-12-01' AND end <= '2009-12-31'";
$r= mysql_query($sql);
$dates= array();
while ($row = mysql_fetch_assoc($r)) {
  // process the entry into a lookup
  $start= date('Y-m-d', strtotime($row['start']));
  if (!isset($dates[$start])) $dates[$start]= array();
  $dates[$start][]= $row;
  $end= date('Y-m-d', strtotime($row['end']));
  if ($end != $start) {
    if (!isset($dates[$end])) $dates[$end]= array();
    $dates[$end][]= $row;
  }
}

// Then step through the days of the month and check for entries for each day:
for ($day = 1; $day <= 31; $day++)
{
    $d= sprintf('2009-12-%02d', $day);
    if (isset($dates[$d])) {
        // display the day number w/ a link
    } else {
        // display the day number
    }
}

为了您的目的,更好的 SQL 语句应该是获取开始日期和每天的事件数的语句。只有当起始列是没有时间分量的日期列时,此语句才能正常工作:

$sql= "SELECT start, end, COUNT(*) events_count FROM events WHERE start >= '2009-12-01' AND end <= '2009-12-31' GROUP BY start, end";

【讨论】:

  • 您的代码似乎无法处理多日事件,$dates 数组仅填充了开始和结束日期 - 不考虑两者之间的日期。
猜你喜欢
  • 2016-08-09
  • 1970-01-01
  • 1970-01-01
  • 2022-12-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-30
  • 1970-01-01
相关资源
最近更新 更多