【问题标题】:PHP Time Filtering and MYSQL FilteringPHP时间过滤和MYSQL过滤
【发布时间】:2012-01-22 23:09:13
【问题描述】:

我有 3 列:Day、start_schedule 和 end_schedule。

   Day  |  start_schedule | end_schedule
 -------|-----------------|--------------
 Monday |     1:00        |   3:00
 Monday |     6:00        |   8:00
 Monday |     8:00        |  10:00

我还在学习 php。我将如何根据数据库中存储的时间筛选我输入的开始时间表和结束时间表是否有效?

例如,如果我想添加时间

  • start_schedule = 3:00 和 end_schedule = 7:00

因为有6:00 - 8:00,所以你不应该被允许添加这个时间表。

  • start_schedule = 7:00 和 end_schedule = 11:00

由于有6:00 - 8:00 和8:00 - 10:00,因此不应允许您添加此时间表。

【问题讨论】:

  • 我编辑了你的问题。我想我明白你在问什么,但我可能错了。您是在谈论 MySQL 数据库,还是只是 PHP 数组?如果是这样,请添加 MySQL 标记。
  • 我们是否假设时间在24 hour clock 中?此外,MySQL TIME type 也很有用。
  • 你明白了,先生,这就是确切的流程。你有这个问题的示例 php 代码和 sql 查询吗?花了好几个星期才弄清楚这个问题。
  • @regilero 非常感谢先生,这是圣诞节的早期礼物。我现在要试试这个。我希望一切正常
  • @Jared Farrish 它是 24 小时格式

标签: php mysql time filter filtering


【解决方案1】:

我会在 mysql 中完成大部分逻辑,因为它会非常简单直接地处理这些类型的表达式。

在 PHP 中,在插入新条目之前,我们需要检查 1 件事:

  1. end_time 是否小于 start_time?如果是,请中止。

在 MySQL 中,当尝试插入新条目时,我们需要检查 4 件事:

  1. start_time 是否在任何现有条目中?如果是,请中止。
  2. end_time 是否在任何现有条目中?如果是,请中止。
  3. 在我们的新条目中是否有任何开始的条目?如果是,请中止。
  4. 我们的新条目中是否有任何条目结尾?如果是,请中止。

上面其实可以重构为一个步骤:

  1. 我们的开始时间是否小于任何条目的结束时间,并且我们的结束时间是否大于整个开始时间?如果是,请中止。

mysql> describe sample;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| start | time        | YES  |     | NULL    |       |
| end   | time        | YES  |     | NULL    |       |
| day   | varchar(50) | YES  |     | Monday  |       |
+-------+-------------+------+-----+---------+-------+

mysql> SELECT * FROM sample;
+--------+----------+----------+
| day    | start    | end      |
+--------+----------+----------+
| Monday | 01:00:00 | 03:00:00 |
| Monday | 06:00:00 | 08:00:00 |
| Monday | 08:00:00 | 11:00:00 |
+--------+----------+----------+

PHP查询数据库的示例实现:

支持@regilero 发布所需的 where 子句的重构版本。

$new_entries = array (
  array('Monday', '00:00:00', '23:59:00'),
  array('Monday', '12:00:00', '15:00:00'),
  array('Monday', '07:00:00', '10:00:00')
);

foreach ($new_entries as $new) {
  list ($day, $start, $end) = $new;

  $q_day   = "'$day'";
  $q_end   = "'$end'";
  $q_start = "'$start'";

  $sql = <<<EOQ
    INSERT INTO `sample` (day,start,end)
    SELECT $q_day, $q_start, $q_end FROM DUAL
    WHERE NOT EXISTS (
      SELECT * FROM `sample`
      WHERE day = $q_day AND (
        $q_start < end AND $q_end > start
      )
    )
EOQ;

  mysql_query ($sql) or die (mysql_error ());

  if (mysql_affected_rows () == 0)
    print join (' ', $new) . " was not inserted!\n";
  else
    print join (' ', $new) . " was inserted!\n";
}

这将输出:

Monday 00:00:00 23:59:00 was not inserted!
Monday 12:00:00 15:00:00 was inserted!
Monday 07:00:00 10:00:00 was not inserted!

【讨论】:

  • 我在我的函数中添加了对封装时间的检查。如果您还有其他时间条件,请告诉我。
  • 大声笑:说我错了,但没有显示我的查询错误的任何情况并构建了一个更复杂的查询......抱歉,你的解决方案太复杂了,重叠问题总是用 new_start 解决 现有开始;找到它不起作用的情况,您的解决方案正在修复它。
  • 我还没有完全理解 @regilero 的 WHERE 是如何工作的......这让我很困扰。
  • @JaredFarrish 这很简单。如果new_end 大于start 并且new_start 小于end,则表示它们重叠。如果您在一张纸上拼凑一些数据并自己检查,或者查询数据库并实时查看结果,会更容易。
【解决方案2】:

如果可以的话,我会推荐 MySQL TIME 类型的方法。不过,这是 PHP 中的一个方法,以备不时之需。

注意,它依赖于 24 小时制的时间,这意味着 22:00 是 10pm。此外,我不会将0:00 视为使用此代码的午夜,并且它不会跨越几天(即22:00 和5:00)。这只是简单的当日检查,它将时间转换为整数表示,然后将时间作为数字进行比较。

您还需要弄清楚如何获得自己的$schedules 数组设置。例如,您可以将其作为另一个参数传入。

编辑

一种基于 Regilero 使用的方法:

function checkNewTime($day, $start, $end, &$error) {
    $_start = str_replace(':', '', $start);
    $_end = str_replace(':', '', $end);
    $error = '';
    $schedules = array(
        'Monday' => array(
            array('1:00', '3:00'),
            array('6:00', '7:00'),
            array('8:00', '10:00')
        )
    );

    if ($_end <= $_start) {
        $error = "The new start time ($start) cannot be after the end time ($end).";
        return false;
    }

    $schedules = $schedules[$day];
    $c_schedules = count($schedules);

    for ($i = 0; $i < $c_schedules; $i++) {
        $interval = "{$schedules[$i][0]} and {$schedules[$i][1]}";

        $interval_start = str_replace(':', '', $schedules[$i][0]);
        $interval_end = str_replace(':', '', $schedules[$i][1]);

        if ($_start < $interval_end && $_end > $interval_start) {
            $error = "The start is between schedules time $interval.";
            return false;
        }

    }

    return true;
}

http://codepad.org/hznpATft

功能:

function checkNewTime($day, $start, $end, &$error) {
    $_start = str_replace(':', '', $start);
    $_end = str_replace(':', '', $end);
    $error = '';
    $schedules = array(
        'Monday' => array(
            array('1:00', '3:00'),
            array('6:00', '8:00'),
            array('8:00', '10:00')
        )
    );

    if ($_end <= $_start) {
        $error = "The new start time ($start) cannot be after the end time ($end).";
        return false;
    }

    $schedules = $schedules[$day];
    $c_schedules = count($schedules);

    for ($i = 0; $i < $c_schedules; $i++) {
        $interval = "{$schedules[$i][0]} and {$schedules[$i][1]}";

        $interval_start = str_replace(':', '', $schedules[$i][0]);
        $interval_end = str_replace(':', '', $schedules[$i][1]);

        if ($_start > $interval_start && $_start < $interval_end) {
            $error = "The start is between schedules time $interval.";
        }

        if ($_end < $interval_end && $_end > $interval_start) {
            $error .= " The end is between schedule times $interval.";
        }

        if ($_start < $interval_start && $_end > $interval_end) {
            $error .= " The schedule encapsulates the schedule times $interval.";
        }

        if ($error != '') return false;
    }

    return true;
}

测试用例:

$times = array(
    array('5:00','8:00'),
    array('3:30','6:00'),
    array('4:30','5:00'),
    array('5:30','7:00'),
    array('9:00','10:00'),
    array('9:30','11:00'),
    array('21:30','12:00'),
    array('11:30','11:30'),
    array('12:30','20:00'),
    array('15:30','18:00'),
    array('12:30','19:00'),
    array('19:30','24:00'),
    array('17:30','23:45')
);

$c_times = count($times);
$error = '';

for ($i = 0; $i < $c_times; $i++) {
    if (checkNewTime('Monday', $times[$i][0], $times[$i][1], $error)) {
        echo "{$times[$i][0]}, {$times[$i][1]} does not conflict.\n\n";
    } else {
        echo "{$times[$i][0]}, {$times[$i][1]} does conflict.\nError: $error\n\n";
    }
}

http://codepad.org/pEq9Wdh4

输出:

5:00, 8:00 does conflict.
Error:  The schedule encapsulates the schedule times 6:00 and 7:00.

3:30, 6:00 does not conflict.

4:30, 5:00 does not conflict.

5:30, 7:00 does conflict.
Error:  The end is between schedule times 6:00 and 8:00.

9:00, 10:00 does conflict.
Error: The start is between schedules time 8:00 and 10:00.

9:30, 11:00 does conflict.
Error: The start is between schedules time 8:00 and 10:00.

21:30, 12:00 does conflict.
Error: The new start time (21:30) cannot be after the end time (12:00).

11:30, 11:30 does conflict.
Error: The new start time (11:30) cannot be after the end time (11:30).

12:30, 20:00 does not conflict.

15:30, 18:00 does not conflict.

12:30, 19:00 does not conflict.

19:30, 24:00 does not conflict.

17:30, 23:45 does not conflict.

【讨论】:

    【解决方案3】:

    如果是 MySQL 存储,您将需要执行 SQL 查询以检索与当前新记录重叠的记录,然后再尝试插入新记录。然后,如果您的重叠检查没有返回任何行,您可以安全地插入您的行(如果所有这些都在事务中完成,否则有人可能在您的检查和插入之间插入了一些东西,请执行 transactions 和把锁放在桌子上,这样在你检查和插入的时候没有人可以插入)。

    基本上要找到重叠的行,您需要这样的查询(myday mystart 和 myend 是您要插入的新值):

    SELECT count(*)
     FROM mytable
     WHERE Day=myday
      AND mystart < end_schedule
      AND myend > start_schedule
    

    如果您有很多记录要简单地执行并且 EXISTS 操作而不是计数(因为 1 个重叠时段足以决定您不应该继续),则可以优化此查询。

    现在,如果您有一些重叠两天的时间表,那就更复杂了。实际上,您不能将这些计划存储在您的数据库模型中。如果我想从周日的 22:00 开始,周一的 04:00 甚至周四的 06:00 结束……那么也许你正在打破你的时间表来插入几个时间表,每天一个。然后,您必须仔细检查您的所有 scheds 零件是否都可以插入,而不仅仅是其中一个。当然,仍然在事务中做所有这些事情。

    编辑:

    重叠测试:

         s------------------------e
      s1----------e1
                            s2----------e2
             s3----------e3
    
    • s &lt; e1
    • s &lt; e2
    • s &lt; e3
    • e &gt; s1
    • e &gt; s2
    • e &gt; s3

    【讨论】:

    • 不会是AND ((mystart &gt; start_schedule AND mystart &lt; end_schedule) OR (myend &lt; end_schedule AND myend &gt; start_schedule))吗?要检查介于两者之间的那些?
    • @refp - 我不听你的评论。
    • @refp - 7-11, 1-5.
    • @Jared Farrish:所有评论都是可移除的。我会删除我的。对于读者来说,这里有一些关于它为什么真的有效的讨论。
    • 好吧,不知何故,我们最终弄明白了;如果我表现得粗鲁或其他,我深表歉意。我不打算这样做,我只是无法理解为什么会起作用。当它真的很聪明时,它看起来很简单。有趣的是,当我把我的函数放在一起时,我一直在想有一些简单的方法可以做到这一点,但我没有想到。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多