Несколько объединений в таблицах MySQL с объединением - PullRequest
0 голосов
/ 29 ноября 2018

В MySQL у меня возникла проблема при попытке получить правильные данные.Я думаю, что я должен использовать union, чтобы получить все результаты из обеих таблиц, но не уверен, как это сделать.

Описание таблиц:

  • Порядок содержит номера заказов
  • Сотрудник удерживает сотрудника
  • Зона содержит имена зон
  • Фактическое время имеет идентификатор зоны, идентификатор заказа и количество часов, которое требуется для доставки
  • Сведения о доставке содержат идентификатор сотрудника, зону, в которую доставлен сотрудник, и количество часов, которое потребовалось для доставки

Заказ

| id | number |
|----|--------|
| 1  |  0001  |

сотрудников

| id | name |
|----|------|
| 1  | Jon  |

зоны

| id | name  |
|----|-------|
| 1  | ZoneA |
| 2  | ZoneB |

actual_times

| id | zone_id | eta_hours | order_id |
|----|---------|-----------|----------|
| 1  |    1    |     5     |     1    |
| 2  |    2    |     4     |     1    |

delivery_details

| id | order_id | employee_id | zone_id | hours |
|----|----------|-------------|---------|-------|
| 1  |     1    |      1      |    1    |   3   |
| 2  |     1    |      1      |    1    |   1   |

Я надеюсь получить название зоны, количество часов, необходимое для доставки исумма часов, которые сотрудник занял, доставить.Если сотрудник не доставил в эту зону, то покажите 0

Ожидаемый результат

| zone_name | hours | eta_hours | employee_name |
|-----------|-------|-----------|---------------|
|   ZoneA   |   4   |     5     |      Jon      |
|   ZoneB   |   0   |     4     |      Jon      |

Я пытался объединить все в реальном времени, но я не понял его правильно.

Это то, что я пытался (обратите внимание, что это просто для того, чтобы получить правильные зоны с временем доставки и фактическим временем).

SELECT deliver_details.zone_id, actual_times.zone_id, zones.zone_name FROM actual_times
RIGHT JOIN deliver_details ON actual_times.order_id = deliver_details.order_id
INNER JOIN zones ON zones.id = deliver_details.zone_id
WHERE deliver_details.order_id = 1
GROUP BY deliver_details.zone_id
UNION ALL
SELECT deliver_details.zone_id, actual_times.zone_id, zones.zone_name FROM actual_times
LEFT JOIN deliver_details ON actual_times.order_id = deliver_details.order_id
INNER JOIN zones ON zones.id = actual_times.zone_id 
WHERE actual_times.order_id = 1
group by actual_times.zone_id

Я в значительной степени пытаюсь получить все это в одном запросе.Есть ли способ сделать это?

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

Ответы [ 3 ]

0 голосов
/ 29 ноября 2018

Если у вас есть только один сотрудник для каждой зоны, у вас должен работать следующий запрос:

SELECT   Z.name  AS zone_name
        ,DT.hours_total
        ,ACT.eta_hours_total
        ,E.name AS employee_name
FROM zones Z
INNER JOIN (SELECT  zone_id
                    , SUM(eta_hours) eta_hours_total 
            FROM actual_times 
            GROUP BY zone_id) ACT ON Z.zone_id = ACT.zone_id
INNER JOIN (SELECT  zone_id
                    , employee_id
                    , SUM(hours) hours_total 
            FROM deliver_details 
            GROUP BY zone_id, employee_id) DT ON Z.zone_id = DT.zone_id
INNER JOIN employees E ON DT.employee_id = E.employee_id
0 голосов
/ 29 ноября 2018

Я придумал аналогичное решение для GMB, но использовал UNION для получения строк с 0 часами ...:

SELECT z.name, sum(dd.hours), at.eta_hours, e.name 
FROM zones z JOIN deliver_details dd ON z.id = dd.zone_id
JOIN actual_times at ON z.id = at.zone_id
JOIN employees e ON dd.employee_id = e.id
GROUP BY z.name, at.eta_hours, e.name

UNION

SELECT z.name, 0, at.eta_hours, e.name
FROM zones z JOIN actual_times at ON z.id = at.zone_id,
employees e
WHERE e.id NOT IN (SELECT employee_id FROM deliver_details WHERE zone_id = z.id)
0 голосов
/ 29 ноября 2018

Не нужно использовать UNION.

Начните с таблицы employees, затем CROSS JOIN с zones и actual_times, чтобы получить простые декартовы произведения.Затем найдите в deliver_details доставки, выполненные каждым сотрудником в каждой зоне;используйте LEFT JOIN для этого.Если epmplyee не доставил в данную зону, используйте COALESCE, чтобы вернуть 0 вместо NULL.

Запрос:

select
    z.name,
    coalesce(sum(dd.hours), 0),
    at.eta_hours,
    e.name
from 
    employees e
    cross join zones z
    inner join actual_times at on at.zone_id = z.id
    left join deliver_details dd on dd.employee_id = e.id and dd.id = at.zone_id
group by 
    z.name, at.eta_hours, e.name
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...