#php #mysql #sql #inner-join #sql-delete
#php #mysql #sql #внутреннее соединение #sql-удалить
Вопрос:
У меня есть таблица с именем tracking_history. В этой таблице будет сохранена история отслеживания посылок. По некоторым причинам, когда когда-либо выполнялась функция checkTrackStatus, все существующие статусы отслеживания повторно вставляются в таблицу. Вот последовательность статусов отслеживания. 'ACCEPTED','AT_SENDING_DEPOT','ON_THE_ROAD','AT_DELIVERY_DEPOT','DELIVERED'
Я сохраняю идентификатор отслеживания, идентификатор заказа также в этой таблице. Поэтому мне нужно, чтобы для каждого идентификатора заказа был указан последний статус отслеживания ( 'ACCEPTED','AT_SENDING_DEPOT','ON_THE_ROAD','AT_DELIVERY_DEPOT','DELIVERED'
), а оставшиеся повторяющиеся значения должны быть удалены. Я попытался с помощью приведенного ниже запроса.
`DELETE t1 FROM tracking_history t1, tracking_history t2
WHERE t1.id < t2.id AND t1.order_id = t2.order_id`
Но этот запрос сохраняет только последние записи и удаляет оставшиеся все остальные.
Means I am having all orders ids with DELIVERED Status only.
Как я могу добиться удаления повторяющихся статусов, сохранив последние статусы? Любая помощь будет принята с благодарностью.
Комментарии:
1. Можете ли вы попробовать с
AND t1.status = t2.status
? Вы убедились, что дубликаты больше не вводятся в базу данных?2. Какая у вас версия MySQL? Покажите нам вывод
SHOW CREATE TABLE tracking_historyG
.3. @El_Vanja, спасибо. Он работает так, как ожидалось.
4. Примеры данных и желаемые результаты помогут. В реальном мире пакет может проходить одни и те же статусы несколько раз, поэтому вам нужно быть очень осторожным с этой проблемой.
Ответ №1:
Я бы хотел сохранить первый идентификатор при вставке строки, а не последний идентификатор. Это связано с другой информацией, которая может быть полезной, в частности, временем вставки и тем, кто сделал вставку. Для этой цели я бы сохранил одну строку для каждого статуса, но сформулировал логику следующим образом:
delete th
from tracking_history th join
(select order_status, status, min(id) as min_id
from tracking_history th2
group by order_status, status
) th2
using (order_status, status)
where id > min_id;
Тем не менее, это все еще кажется неправильным. В конце концов, возможно, статус будет одинаковым в нескольких строках. Например, может быть несколько попыток переместить пакет из хранилища на адрес. Что вам действительно нужно, так это самый последний статус для каждой партии tracking_history
. Я не знаю, есть ли у вас какой-то «идентификатор пакета». Но позвольте мне предположить, что есть что-то, возможно, дата ввода, которая связывает все общие значения вместе.
В этом случае вам потребуется последний статус для каждой «партии»:
delete th
from tracking_history th join
(select order_status, entry_date, max(id) as max_id
from tracking_history th2
group by order_status, entry_date
) th2
using (order_status, entry_date)
where id < min_id;
Ответ №2:
Вам нужно дополнительное условие корреляции для статуса:
DELETE t1
FROM tracking_history t1
INNER JOIN tracking_history t2
ON t1.id < t2.id
AND t1.order_id = t2.order_id
AND t1.status = t2.status
Я бы рекомендовал дополнительно изменить запрос следующим образом:
DELETE t1
FROM tracking_history t1
INNER JOIN (
SELECT order_id, status, MAX(id) as id
FROM tracking_history
GROUP BY order_id, status
) t2
ON t1.id < t2.id
AND t1.order_id = t2.order_id
AND t1.status = t2.status
Преимуществом этого подхода является то, что каждая строка сопоставляется только один раз, в отличие от исходного запроса, который может пытаться удалить одну и ту же строку более одного раза. Следовательно, это более эффективно и как-то безопаснее.