我需要一些人与一个PHP/MySQL预约系统的“最佳实践”作斗争,这个系统是我目前正在开发的一个理发师。希望我们能一起解决一些问题,避免事后重做系统。我一直在搜索SO和Google上的一些教程、最佳实践等,但我没有找到任何符合我需要的东西。
基本情况
每天有多个理发师,每个理发师都有自己的日程安排,包括他/她与客户的约会。与美发师相连的是一张桌子,上面有他/她一周的空闲时间。
表:人
+----+------+-------+-----------+
| id | name | email | available |
+----+------+-------+-----------+
| 1 | John | [email protected] | Y |
| 2 | Sara | [email protected] | N |
+----+------+-------+-----------+
Table:times(这个表有一个主键,我把它忘在下面的时间表中了)
+-----------+-------------+-----------+-----------+
| people_id | day_of_week | start | end |
+-----------+-------------+-----------+-----------+
| 1 | 1 | 08:00 | 12:00 |
| 1 | 1 | 12:30 | 17:00 |
| 1 | 3 | 09:00 | 12:00 |
| 1 | 4 | 10:30 | 16:00 |
| 1 | 5 | 09:00 | 17:00 |
| 1 | 6 | 09:00 | 12:00 |
| 2 | 1 | 09:00 | 12:00 |
| 2 | 2 | 09:00 | 12:00 |
| 2 | 3 | 09:00 | 12:00 |
+-----------+-------------+-----------+-----------+
正如你所看到的,人与时间之间存在着一对多的关系(显然,一周有7天)。除此之外,还可以选择在一天中的几个小时之间添加一个休息时间(参见people_id=1,day_of_week=1:08:00-12:00和12:30-17:00)。
此外,还有一张叫做“发型”的桌子,这是一张桌子,里面有各种类型的约会(比如染发、剪头发、洗衣服等)。此表包含此约会所需的时间(分钟)。
最后我有了一张表,非常简单:
id, people_id, types_id, sex, fullname, telephone, emailaddress, date_start, date_end
在MySQL中,Date start和Date end是完整的DATETIME字段,使用MySQL查询函数更容易计算。
最好的做法是什么?
所以,按照我设置的方式,前端用户会在一个触发ajax/jquery函数的字段中选择一个日期,该函数会查找在选择日期可用的所有理发师。然后,用户详细说明美发师(这不是强制性的:用户还可以选择“任意”美发师选项)和他/她想预约的类型。
提交第一份表格后,可以使用以下信息:
日期(日、月、年)
人员id(对于“任意”可以为0,如果选择了理发师,则可以为id)
发型(与约会所需的分钟数有关)
使用此信息,我将从选定的理发师中选择可用日期,或者循环所有可用的理发师及其可用日期。
这就是我精神崩溃的地方!因为什么是检查可用日期的最佳方法。我认为最好的方法是:
查询理发师指定日期的时间(一次1次)
使用query1结果的startdate+约会类型所需的分钟数(so:
appointments
)查询约会表一旦没有找到结果,我就假设这个位置是免费的,这是作为一个选项提供给用户的
我面临的大问题是第2点:我的头脑真的对这个查询发疯了,这是我需要找到符合特定时间跨度的约会的完整查询吗?
谢谢你的阅读和思考!:-)
//编辑:多一点“testdata”:
约翰-星期一-12:00-17:00。
约会:
-12:00-12:30
-14:30-15:30
用户希望预约2小时,在上面的示例中,我将检查:
12点到14点有预约吗?对,。。前往下一地点
14:00到16:00有预约吗?对,。。前往下一地点
16点到18点有预约吗?错误,17:00后不可用
因此。。使用10/15分钟的“时间表”可能是更好的选择。检查:
12:00-14:00
12:10-14:10
12:20-14:20等。。
这会在12:30到14:30之间找到可用的位置。
//编辑2:可能查询到步骤2
我已经在纸上写了一些东西(一张有预约和空位的桌子)。我想到了以下几点。以下情况不能预约:
有一个起始日期介于$start和$end之间的约会
有一个结束日期介于$start和$end之间的约会
有一个约会的开始日期<$开始和结束日期>$结束
将以上内容与
SELECT * FROM appointments WHERE ((date_start >= $start AND date_start <= ($start+$time)) OR (date_end > $start AND date_end <= ($start+$time)) AND people_id = 1
一起查询预约表将导致没有行(=空闲点)或一行/多行(在这种情况下,将获取点)。我想找到开放点的最好方法是在数据库中查询X分钟的块,开始间隔为10分钟。这个解决方案的缺点是我每小时需要6个查询,而每个理发师大约需要48个查询。。。关于如何减少查询量有什么想法吗?
最佳答案
最后,我选择了一个为数据库中的开始和结束日期生成时间戳的系统。检查时,我在开始时加了一秒钟,在结束时减了一秒钟,以避免约会时间重叠。
我最后做了什么
显然,我不确定这是否是最好的做法,但它确实对我有效。用户首先选择自己的性别和当天的偏好。这将发送一个AJAX请求,以获取可用的人员和各种约会类型(例如,染发、剪发等)。
选择所有设置(性别、日期、人员和类型)后,我首先进行一些简单的验证:检查日期,检查日期(“N”)是否不是7(星期日)。如果一切正常,更重要的事情就开始了:
1)从数据库中获取约会类型,包括此类型所需的总时间(30分钟、45分钟等)
2)获取可用的个人信息(当天的完整人员列表,如果选择了一个人,则仅为一个人),包括他们的可用时间
然后,这个人(或一个人)被循环,从他们自己的开始时间开始。此时,我有一组数据包含:
$duration (of the appointment type)
$startTime (starting time of the person selected in the loop)
$endTime (= $startTime + $duration)
$personStart (= starting time of the person)
$personEnd (= end time of the person)
我们来看看这个演示数据:
$duration = 30 min
$startTime = 9.00h
$endTime = 9.30h
$personStart = 9.00h
$personEnd = 12.00h
我在这里做的是:
while( $endTime < $personEnd )
{
// Check the spot for availability
$startTime = $endTime;
$endTime = $startTime + $duration;
}
显然,在这种情况下,它是完全简化的。因为当我检查可用性的时候,这个位置不是免费的。我将$startTime设置为等于找到的最新约会,并从循环中的最新约会开始。
例子:
I check for a free spot at 9.00 but the spot is not free because there's an appointment from 9.00 till 10.00, then 10.00 is returned and $startTime is set to 10.00h instead of 9.30h. This is done to keep the number of queries to a minimum since there can be quiet a lot.
检查可用性功能
// Check Availability
public static function checkAvailability($start, $end, $ape_id)
{
// add one second to the start to avoid results showing up on the full hour
$start += 1;
// remove one second from the end to avoid results showing up on the full hour
$end -= 1;
// $start and $end are timestamps
$getAppointments = PRegistry::getObject('db')->query("SELECT * FROM appointments WHERE
((
app_start BETWEEN '".date("Y-m-d H:i:s", $start)."' AND '".date("Y-m-d H:i:s", $end)."'
OR
app_end BETWEEN '".date("Y-m-d H:i:s", $start)."' AND '".date("Y-m-d H:i:s", $end)."'
)
OR
(
app_start < '".date("Y-m-d H:i:s", $start)."' AND app_end > '".date("Y-m-d H:i:s", $end)."'
))
AND
ape_id = ".PRegistry::getObject('db')->escape($ape_id));
if(PRegistry::getObject('db')->num_rows($getAppointments) == 0) {
return true;
} else {
$end = 0;
foreach(PRegistry::getObject('db')->fetch_array(MYSQLI_ASSOC, $getAppointments, false) as $app) {
if($app['app_end'] > $end) {
$end = $app['app_end'];
}
}
return $end;
}
}
因为我将约会存储为“从:10.00到:11.00”,所以我必须确保从11:00:01到11:59:59查看地点,否则11:00的约会将显示在结果中。
在函数的末尾,如果找到约会,我循环结果并返回最新的结尾。这是我前面提到的循环的下一个开始。
希望这对任何人都有帮助。正如info:
ape_id
是与之链接的“约会人员”的ID。关于php - PHP/MySQL约会/预订系统的最佳实践,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/16979992/