Как написать запрос mySQL, чтобы составить таблицу в интерфейсе? - PullRequest
0 голосов
/ 03 мая 2020

Привет в первый раз!

Стремясь стать лучшим программистом, я решил создать веб-приложение для онлайн-бронирования. Как вы можете видеть на рисунке ниже, я создал эту базу данных, имея в виду следующие вещи:

  1. каждый клиент может записаться на прием или запросить встречу.

    i) Зарезервированные встречи имеют фиксированное время и день.

    ii) Запросы о назначении не имеют фиксированного времени и дня, пока они не будут зарезервированы вручную через бэк-офис. Они должны иметь как минимум два временных диапазона между двумя днями или более, которые указывают, когда клиент доступен, поэтому назначение должно быть записано в одном из этих временных диапазонов.

  2. каждое назначение может иметь более одного клиента (возможно, максимум 3)

  3. каждый клиент может иметь более одной услуги (здесь не определен лимит)

моя база данных

Я решил, что желаемым результатом для внешнего интерфейса является следующий (который будет иметь нумерацию страниц и ajax, но я еще не там):

таблица переднего плана

Первая успешная попытка была неэффективной, поскольку мне нужно было выполнить 4 запроса к базе данных для каждой встречи, поэтому я сразу начал думать о что-то лучше, но я потратил почти две недели и у меня пока ничего нет.

Я не могу понять, в какой части мне не хватает знаний MySQL или PHP (забыл упомянуть, что пишу это с помощью * 1 055 * но лучше поздно, чем никогда) .... очень вероятно, с обеих сторон, но я не знаю, что учиться, чтобы решить эту проблему, в то время как так много других вещей мне удалось найти что-то вокруг.

Спасибо заранее!

ОБНОВЛЕНИЕ: соответствует коду, который я использую (включая запросы):

МОДЕЛЬ

 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;
    }

КОНТРОЛЛЕР

$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>

ПРИМЕЧАНИЕ: я намереваюсь улучшить представление, а также переместить как можно больше логи c в контроллер

Ответы [ 2 ]

0 голосов
/ 06 мая 2020

Ну, мой лучший запрос выглядит так:

SELECT DISTINCT appointment_customer_services.appointment_id,
                concat_ws(' ', customers.last_name, customers.first_name) AS 'customer',
                services.name AS 'service',
                customers.status,
                appointment_customer_services.is_booking,
                SUM(services.cost) AS 'cost',
                appointments_schedule.datetime_from AS 'datetime_from',
                appointments_schedule.datetime_to AS 'datetime_to'

FROM `appointment_customer_services`

JOIN customers
    ON customers.id = appointment_customer_services.customer_id
JOIN services 
    ON services.id = appointment_customer_services.service_id
JOIN appointments_schedule
    ON appointments_schedule.appointment_id = appointment_customer_services.appointment_id

WHERE appointments_schedule.datetime_from > CURRENT_TIMESTAMP

GROUP BY customers.last_name,
   services.name,
   appointments_schedule.datetime_from
ORDER BY appointments_schedule.appointment_id

На самом деле это первый запрос, который я создал в начале, но я не смог отформатировать выходной массив, чтобы заполнить свою внешнюю таблицу, пока я ' я показывал вам выше.

Кроме того, в нем много повторяющихся данных, которые я не считаю хорошей практикой, верно? Но в то же время я не могу думать ни о каком другом.

Array
(
    [0] => Array
        (
            [appointment_id] => 1
            [customer] => lady
            [service] => service1
            [status] => 1
            [is_booking] => 1
            [cost] => 7
            [datetime_from] => 2020-05-06 12:00:00
            [datetime_to] => 2020-05-06 17:00:00
        )

    [1] => Array
        (
            [appointment_id] => 1
            [customer] => lady
            [service] => service1
            [status] => 1
            [is_booking] => 1
            [cost] => 7
            [datetime_from] => 2020-05-30 17:00:00
            [datetime_to] => 2020-05-30 20:00:00
        )

    [2] => Array
        (
            [appointment_id] => 2
            [customer] => nikole
            [service] => service1
            [status] => 1
            [is_booking] => 1
            [cost] => 50
            [datetime_from] => 2020-05-29 14:00:00
            [datetime_to] => 2020-05-29 16:00:00
        )

    [3] => Array
        (
            [appointment_id] => 2
            [customer] => nikole
            [service] => service2
            [status] => 1
            [is_booking] => 1
            [cost] => 7
            [datetime_from] => 2020-05-29 14:00:00
            [datetime_to] => 2020-05-29 16:00:00
        )

    [4] => Array
        (
            [appointment_id] => 2
            [customer] => nikole
            [service] => service3
            [status] => 1
            [is_booking] => 1
            [cost] => 240
            [datetime_from] => 2020-05-29 14:00:00
            [datetime_to] => 2020-05-29 16:00:00
        )

    [5] => Array
        (
            [appointment_id] => 3
            [customer] => jennifer
            [service] => service1
            [status] => 1
            [is_booking] => 1
            [cost] => 35
            [datetime_from] => 2020-05-28 15:00:00
            [datetime_to] => 2020-05-28 17:00:00
        )

    [6] => Array
        (
            [appointment_id] => 3
            [customer] => jennifer
            [service] => service2
            [status] => 1
            [is_booking] => 1
            [cost] => 240
            [datetime_from] => 2020-05-28 15:00:00
            [datetime_to] => 2020-05-28 17:00:00
        )

    [7] => Array
        (
            [appointment_id] => 3
            [customer] => jennifer
            [service] => service3
            [status] => 1
            [is_booking] => 1
            [cost] => 30
            [datetime_from] => 2020-05-28 15:00:00
            [datetime_to] => 2020-05-28 17:00:00
        )

    [8] => Array
        (
            [appointment_id] => 3
            [customer] => joey
            [service] => service1
            [status] => 1
            [is_booking] => 0
            [cost] => 50
            [datetime_from] => 2020-05-28 15:00:00
            [datetime_to] => 2020-05-28 17:00:00
        )

    [9] => Array
        (
            [appointment_id] => 3
            [customer] => joey
            [service] => service2
            [status] => 1
            [is_booking] => 0
            [cost] => 7
            [datetime_from] => 2020-05-28 15:00:00
            [datetime_to] => 2020-05-28 17:00:00
        )

    [10] => Array
        (
            [appointment_id] => 3
            [customer] => Aniston
            [service] => service1
            [status] => 1
            [is_booking] => 0
            [cost] => 240
            [datetime_from] => 2020-05-28 15:00:00
            [datetime_to] => 2020-05-28 17:00:00
        )

)

Если вы видите, что я получаю несколько массивов для каждой встречи , с большинством элементов, которые будут одинаковыми , Основное различие заключается либо в клиенте, либо в услуге, либо в дате и от.

Так что, если для assign_id = 1, есть только один клиент, но две службы, создается новый массив со всеми дублированными данными, но есть вторая служба для той же встречи для того же клиента. Разве не было бы правильно иметь только один массив для каждой встречи с вложенными массивами для охвата объекта (клиенты, услуги клиента, даты и т. Д. c), точно такой же, как формат, который мне нужен для заполнения входной таблицы?

Итак, теперь мне нужно извлечь данные из этого массива и создать новый в нужном мне формате, чтобы можно было заполнить таблицу на внешнем интерфейсе, но это кажется невозможным ...

И у меня будет два массива с одинаковым объемом данных, не будет ли это использовать больше памяти? что такое ложная практика? Идея, которая пришла мне в голову, состоит в том, чтобы удалить данные для каждой встречи из исходного массива, как только они будут скопированы в новый массив. Но все эти процессы звучат как ..... ненужная сложность? Я не знаю, что мне не хватает.

Я также пытался получить всю информацию для каждой встречи в одной строке / массиве с помощью group_concat (s), чтобы создать вывод типа:

appointment_id customers+services datetimes
1 | customer1: 1,1,service1,service2,services, customer2:.... |datetime1,datetime2

но тоже не было go, информации стало слишком много, и я даже не смог создать такой вывод, я застрял со всеми услугами каждого приема, но я не мог определить, какие пункты обслуживания к какому клиенту ...

И, наконец, еще один вопрос, который возник, заключается в том, стоит ли мне рассчитывать стоимость каждой встречи (поскольку мне нужна сумма, чтобы сократить количество встреч от самых дорогих до самых дешевых. ) на уровне приложения с PHP или, если это будет сделано на уровне дБ с mysql.

Еще раз спасибо за ваше внимание!

0 голосов
/ 04 мая 2020

Теперь мы можем видеть ваши запросы, и да, ваша догадка была верной - это неэффективный подход. Это пример того, что известно как проблема n + 1 , где вы делаете начальную SELECT для родительской записи (appointments), а затем для каждой из них (n) сделайте еще SELECT (или еще несколько, в данном случае), чтобы найти связанные данные об этих записях.

Еще одно примечание, SELECT .. WHERE IN ( ... subquery ... ) очень медленное . Постарайтесь избежать этого, если можете.

Ваша схема, кажется, хорошо нормализована, так почему бы не использовать некоторые JOIN s? AFAICT, вы должны быть в состоянии найти то, что вам нужно с помощью одного запроса. Все объединения выполняются по первичным ключам, которые все INT s, поэтому это должно быть эффективным.

Это простое и наивное объединение ваших таблиц, которое я придумал, просто просматривая ваши запросы. Вам может потребоваться выполнить GROUP BY или изменить JOIN на INNER JOIN, или выполнить какую-либо другую настройку ... Я не знаю ваших данных или схемы, поэтому это всего лишь первый удар, с которого можно начать. И, конечно, он не будет генерировать результаты в том формате, который у вас есть на данный момент, я имею в виду вложенные массивы и т. Д. c - вам придется обновить внешний интерфейс, чтобы отобразить его. Но все должно получиться намного проще.

SELECT ... FROM appointments
    JOIN appointments_schedule ON appointments.id = appointments_schedule.appointment_id
    JOIN appointment_customer_services ON appointments.id = appointment_customer_services.appointment_id
    JOIN customers ON appointment_customer_services.customer_id = customers.id
    JOIN services ON appointment_customer_services.service_id = services.id
WHERE appointments_schedule.datetime_from > CURRENT_TIMESTAMP;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...