第一次问好!
为了成为一名更好的程序员,我决定构建一个在线预订Web应用程序。如您在下图中所看到的,我在创建数据库时考虑了以下几点。
每个客户都可以预约或要求预约。
i)预定的约会有固定的日期和时间。
ii)约会请求没有固定的时间和日期,直到通过后台。他们必须在两天之间至少有两个时间范围,或者更长,以声明何时客户可用,因此必须在以下时间范围之一内预定约会。
每个约会可能有一个以上的客户(可能最多3个)
我确定的前端的理想结果是以下内容(也将具有分页和ajax,但我还没有出现):
第一次成功的尝试完全没有效率,因为我需要为每个约会对数据库运行4个查询,所以我立即开始考虑更好的方法,但是我浪费了将近两个星期,但是我什么都没有。
我不明白我缺少哪一部分的MySQL或PHP知识(忘了说我正在用PHP编写它,但是迟到总比没有好。。。。。)学习解决这个问题,而我设法找到了很多其他东西。
提前感谢!
更新:遵循我使用的代码(包括查询):
模型
public function getAppointments()
{
$db = \Config\Database::connect();
// get future appointments
$query = $db->query('
SELECT DISTINCT`appointment_id`
FROM `appointments_schedule`
WHERE `datetime_from` > CURRENT_TIMESTAMP
');
$appointments = $query->getResultArray();
return $appointments;
}
public function getAppointmentDateTimes($appointment_id)
{
$db = \Config\Database::connect();
$query = $db->query('
SELECT `datetime_from`, `datetime_to`
FROM `appointments_schedule`
WHERE `appointment_id` = ' . $appointment_id
);
$appointmentDateTimes = $query->getResultArray();
return $appointmentDateTimes;
}
public function getAppointmentCustomers($appointment_id)
{
$db = \Config\Database::connect();
$query = $db->query('
SELECT `id`, `last_name`, `first_name`, customers.status, `is_booking`
FROM customers
INNER JOIN appointment_customer_services ON appointment_customer_services.customer_id = customers.id
WHERE id IN(
SELECT `customer_id`
FROM appointment_customer_services
WHERE appointment_id = ' . $appointment_id . ')
GROUP BY customers.last_name'
);
$appointmentCustomers = $query->getResultArray();
return $appointmentCustomers;
}
public function getCustomerServices($appointment_id, $customer_id)
{
$db = \Config\Database::connect();
$query = $db->query('
SELECT `name` AS `service_name`
FROM services
WHERE id IN(SELECT `service_id`
FROM appointment_customer_services
WHERE `customer_id` =' . $customer_id . '
AND `appointment_id` =' . $appointment_id . ')
');
$CustomerServices = $query->getResultArray();
return $CustomerServices;
}
CONTROLLER
$data['appointments'] = [];
foreach ( $model->getAppointments() as $appointment )
{
foreach ( $appointment as $id )
{
foreach ( $model->getAppointmentDateTimes($id) as $key => $timeDates )
{
$data['appointments'][$id]['timeDates'][] = $timeDates;
}
foreach ( $model->getAppointmentCustomers($id) as $appointmentCustomers )
{
foreach ( $model->getCustomerServices($id, $appointmentCustomers['id']) as $services )
{
foreach ( $services as $service )
{
$appointmentCustomers['services'][] = $service;
}
}
$data['appointments'][$id]['customers'][] = $appointmentCustomers;
}
}
}
PRINT_R OUTPUT
Array
(
[1] => Array
(
[timeDates] => Array
(
[0] => Array
(
[datetime_from] => 2020-04-28 14:00:00
[datetime_to] => 2020-04-28 17:00:00
)
[1] => Array
(
[datetime_from] => 2020-05-06 12:00:00
[datetime_to] => 2020-05-06 17:00:00
)
[2] => Array
(
[datetime_from] => 2020-05-30 17:00:00
[datetime_to] => 2020-05-30 20:00:00
)
)
[customers] => Array
(
[0] => Array
(
[id] => 1
[last_name] => Jolie
[first_name] => Angelina
[status] => 1
[is_booking] => 1
[services] => Array
(
[0] => service1
)
)
)
)
[2] => Array
(
[timeDates] => Array
(
[0] => Array
(
[datetime_from] => 2020-05-29 14:00:00
[datetime_to] => 2020-05-29 16:00:00
)
)
[customers] => Array
(
[0] => Array
(
[id] => 2
[last_name] => Lopez
[first_name] => Jennifer
[status] => 1
[is_booking] => 1
[services] => Array
(
[0] => service1
[1] => service2
[2] => service3
)
)
)
)
[3] => Array
(
[timeDates] => Array
(
[0] => Array
(
[datetime_from] => 2020-05-28 15:00:00
[datetime_to] => 2020-05-27 17:00:00
)
)
[customers] => Array
(
[0] => Array
(
[id] => 3
[last_name] => Charlize
[first_name] => Theron
[status] => 1
[is_booking] => 1
[services] => Array
(
[0] => service1
[1] => service2
[2] => service3
)
)
[1] => Array
(
[id] => 4
[last_name] => Bullock
[first_name] => Sandra
[status] => 1
[is_booking] => 0
[services] => Array
(
[0] => Service1
[1] => Service2
)
)
[2] => Array
(
[id] => 5
[last_name] => Aniston
[first_name] => Joe
[status] => 1
[is_booking] => 0
[services] => Array
(
[0] => service1
)
)
)
)
)
查看(我用上面的数据填满的表)
<table class="table table-hover">
<thead class="text-warning">
<?php foreach ( $table_head as $th) : ?>
<th <?php if ($th == "timeDates"){echo "style="."text-align:center;";} ?>>
<?php echo $th; ?>
</th>
<?php endforeach; ?>
</thead>
<tbody>
<?php
/* the table has 3 cells and does not contain nested tables
each row represents one customer, with his services in a unordered list
the times cell has a rowspan = the number of the appointment customers
*/
?>
<?php foreach ( $appointments as $appointment ) : ?>
<tbody class="appointments-table">
<?php foreach ( $appointment['customers'] as $index => $customer) : ?>
<tr class="appointments-table">
<td <?php echo $customer['is_booking'] ? "style='font-weight: bold;'" : ''; ?>><?php echo $customer['last_name'] . ' ' . $customer['first_name'];?></td>
<td>
<?php foreach ( $customer['services'] as $service ) : ?>
<ul style="list-style-type:none; padding-left: 0; margin-bottom: 0;">
<li><?php echo $service; ?></li>
</ul>
<?php endforeach; ?>
</td>
<?php if ( $index == 0 ) : ?>
<td class="appointments-table" rowspan=<?php echo count($appointment['customers']); ?>>
<ul class="pl-0 mb-0" style="list-style-type:none; text-align: center; margin-bottom: 0;">
<?php foreach ( $appointment['timeDates'] as $timeDate ) : ?>
<li><?php echo $timeDate['datetime_to'] ?
( date_format(date_create($timeDate['datetime_from']), "d/m/Y H:i") . ' until ' .
date_format(date_create($timeDate['datetime_to']), "d/m/Y H:i") ) :
date_format(date_create($timeDate['datetime_from']), "d/m/Y H:i"); ?></li>
<?php endforeach; ?>
</ul>
</td>
<?php endif; ?>
</tr>
<?php endforeach; ?>
</tbody>
<?php endforeach; ?>
</table>
注意:我打算改善视图,以便将尽可能多的逻辑移至控制器
现在我们可以看到您的查询,是的,您的预感是正确的-这不是一种有效的方法。这是所谓的n+1 problem的示例,其中您对父记录(SELECT
)进行了初始appointments
,然后对每个记录(n
)进行了另外一个SELECT
(或(在这种情况下,还有更多),以查找有关这些记录的相关数据。
[另一个注释,SELECT .. WHERE IN ( ... subquery ... )
is very slow。如果可以的话,请尽量避免这种情况。
您的架构似乎已经很好地规范化了,那么为什么不使用某些SELECT .. WHERE IN ( ... subquery ... )
? AFAICT您应该可以通过单个查询找到所需的内容。所有联接均位于主键上,这些主键均为JOIN
,因此这应该很有效率。
这是您仅通过查询您的查询就得出的表中最简单,最幼稚的联接。您可能需要进行一些INT
处理,或将GROUP BY
更改为JOIN
,或进行其他一些调整...我不知道您的数据或架构,因此这只是使您入门的第一步。当然,它不会以您当前使用的格式生成结果,我的意思是嵌套数组等-您必须更新前端才能显示它。但这最终会更简单。
INNER JOIN