Удаление повторяющихся идентификаторов заказов с сохранением статуса отслеживания — mysql

#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
 

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