Мне нужна «небольшая» помощь с запросом SQL (MySQL).
У меня есть следующие таблицы:
COURIERS
таблица:
+------------+ | COURIER_ID | +------------+
DELIVERIES
таблица:
+-------------+------------+------------+ | DELIVERY_ID | COURIER_ID | START_DATE | +-------------+------------+------------+
ORDERS
таблица:
+----------+-------------+-------------+ | ORDER_ID | DELIVERY_ID | FINISH_DATE | +----------+-------------+-------------+
COORDINATES
таблица:
+-------------+-----+-----+------+ | DELIVERY_ID | LAT | LNG | DATE | +-------------+-----+-----+------+
В реальной базе данных у меня больше столбцов в каждой таблице, но для этого примера достаточно столбцов, указанных выше.
Что мне нужно?
SQL-запрос, который возвращает всех курьеров [
COURIER_ID
], их последние доставка [DELIVERY_ID
] (на основе последнегоSTART_DATE
), последняя координата доставки [LAT
иLNG
] (на основе последнихDATE
) и количество оставшихся заказов (общее количество заказов последней доставки, у которых нетFINISH_DATE
).У курьера не может быть доставок, в этом случае я хочу
DELIVERY_ID
= NULL,LAT
= NULL иLNG
= NULL в результате.У доставки не может быть координат, в этом случае я хочу
LAT
= NULL иLNG
= NULL в результате.
Что я смог сделать?
SELECT c.`COURIER_ID`,
d.`DELIVERY_ID`,
r.`LAT`,
r.`LNG`,
(SELECT COUNT(DISTINCT `ORDER_ID`)
FROM `ORDERS`
WHERE `DELIVERY_ID` = d.`DELIVERY_ID`
AND `FINISH_DATE` IS NULL) AS REMAINING_ORDERS
FROM `COURIERS` AS c
LEFT JOIN `DELIVERIES` AS d USING (`COURIER_ID`)
LEFT JOIN `COORDINATES` AS r ON r.`DELIVERY_ID` = d.`DELIVERY_ID`
WHERE (CASE WHEN
(SELECT MAX(`START_DATE`)
FROM `DELIVERIES`
WHERE `COURIER_ID` = c.`COURIER_ID`) IS NULL THEN d.`START_DATE` IS NULL ELSE d.`START_DATE` =
(SELECT MAX(`START_DATE`)
FROM `DELIVERIES`
WHERE `COURIER_ID` = c.`COURIER_ID`) END)
AND (CASE WHEN
(SELECT MAX(`DATE`)
FROM `COORDINATES`
WHERE `DELIVERY_ID` = d.`DELIVERY_ID`) IS NULL THEN r.`DATE` IS NULL ELSE r.`DATE` =
(SELECT MAX(`DATE`)
FROM `COORDINATES`
WHERE `DELIVERY_ID` = d.`DELIVERY_ID`) END)
GROUP BY c.`COURIER_ID`
ORDER BY d.`START_DATE` DESC
Проблема в том, что этот запрос выполняется очень медленно (от 5 до 20 секунд), когда у меня более 5 КБ COORDINATES
, и иногда он не возвращает всех курьеров.
Большое спасибо за любое решение.
2 ответа
Я не смог протестировать этот запрос, так как у меня сейчас нет настроенной базы данных mysql, тем более с этой схемой и образцами данных. Но я думаю, что это сработает для вас:
select
c.courier_id
, d.delivery_id
, co.lat
, co.lng
, oc.cnt as remaining_orders
from
couriers c
left join (
select
d.delivery_id
, d.courier_id
from
deliveries d
inner join (
select
d.delivery_id
, max(d.start_date) as start_date
from
deliveries d
group by
d.delivery_id
) dmax on dmax.delivery_id = d.delivery_id and dmax.start_date = d.start_date
) d on d.courier_id = c.courier_id
left join (
select
c.delivery_id
, c.lat
, c.lng
from
coordinates c
inner join (
select
c.delivery_id
, max(c.date) as date
from
coordinates c
group by
c.delivery_id
) cmax on cmax.delivery_id = c.delivery_id and cmax.date = c.date
) co on co.delivery_id = d.delivery_id
left join (
select
o.delivery_id
, count(o.order_id) as cnt
from
orders o
where
o.finish_date is null
group by
o.delivery_id
) oc on oc.delivery_id = d.delivery_id
Попробуй это:
SELECT C.COURIER_ID, D.DELIVERY_ID, D.START_DATE, D.FINISH_DATE,
B.LAT, B.LNG, B.DATE, C.NoOfOrders
FROM COURIERS C
LEFT JOIN ( SELECT *
FROM (SELECT *
FROM DELIVERIES D
ORDER BY D.COURIER_ID, D.START_DATE DESC
) A
GROUP BY COURIER_ID
) AS A ON C.COURIER_ID = A.COURIER_ID
LEFT JOIN ( SELECT *
FROM (SELECT *
FROM COORDINATES CO
ORDER BY CO.DELIVERY_ID, CO.DATE DESC
) B
GROUP BY CO.DELIVERY_ID
) AS B ON A.DELIVERY_ID = B.DELIVERY_ID
LEFT JOIN ( SELECT O.DELIVERY_ID, COUNT(1) NoOfOrders
FROM ORDERS O WHERE FINISH_DATE IS NULL
GROUP BY O.DELIVERY_ID
) AS C ON A.DELIVERY_ID = C.DELIVERY_ID;
Похожие вопросы
Связанные вопросы
Новые вопросы
mysql
MySQL — это бесплатная система управления реляционными базами данных (RDBMS) с открытым исходным кодом, которая использует язык структурированных запросов (SQL). НЕ ИСПОЛЬЗУЙТЕ этот тег для других БД, таких как SQL Server, SQLite и т. д. Это разные БД, которые используют свои собственные диалекты SQL для управления данными. В вопросе всегда указывайте точную версию сервера. Версии 5.x сильно отличаются по своим возможностям от версий 8+.