Mysql дублировать результат с join - PullRequest
0 голосов
/ 15 ноября 2018

У меня есть таблица order_status_history , в которой хранится одна строка для каждого изменения статуса заказа, и я хочу получить последнюю запись для определенного статуса заказа.

Включенные таблицы (упрощенно):

orders
| id     | 
| 1      |  

order_products
| id     | order_id | productid | quantity| 
| 1      | 1        | 1         | 1       | 
| 2      | 1        | 1         | 2       | 
| 3      | 1        | 1         | 2       | 
| 4      | 1        | 1         | 10      |  

order_status_history
| id     | order_id | order_status_id | updatedat              | 
| 1      | 1        | 1               | 2017-05-18 18:45:50    | 
| 2      | 1        | 2               | 2017-05-19 18:45:50    | 
| 3      | 1        | 3               | 2017-05-20 18:45:50    | 
| 4      | 1        | 2               | 2017-05-21 18:45:50    | 
| 5      | 1        | 3               | 2017-05-22 18:45:50    | 

Что мне точно нужно:

Если последний статус заказа равен «3» (так как «4» означает отмененный или в любом случае более недоступный), для каждого идентификатора заказа получают только последнюю запись (на основе столбца updatedat, последний означает самый последний)

Это запрос, который я пробовал, но в этом случае возвращает 2 строки для идентичного идентификатора заказа и статуса 3:

SELECT o.id, 
       osh.updatedat, 
       op.quantity 
FROM   orders_products op 
       LEFT JOIN order_status_history osh 
              ON osh.order_id = op.orderid 
       LEFT JOIN orders o 
              ON o.id = op.orderid 
WHERE  op.productid = 1 
       AND (SELECT osh.order_status_id 
            FROM   order_status_history osh 
            WHERE  osh.order_id = o.id 
            ORDER  BY osh.updatedat DESC 
            LIMIT  1) = 3 

1 Ответ

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

Я считаю, что без какой-либо записи в таблице orders не может быть записи в таблице orders_products и order_status_history.Поэтому я бы изменил порядок объединения таблиц для простоты понимания.Более того, нет необходимости в LEFT JOIN, так как мы пытаемся выбрать строки для определенного продукта (следовательно, строки должны существовать в таблице продуктов), и для определенного order_status (следовательно, строки должны существовать в таблице истории состояний).Поэтому я заменит все LEFT JOIN в запросе на INNER JOIN.

Теперь, чтобы получить последнюю updatedat строку, соответствующую определенному статусу, нам нужно будет использовать Производная таблица.В этом подзапросе мы получим самое последнее значение updatedat для каждого заказа, когда статус будет 3 .

В конце концов мы соответствующим образом присоединим этот набор результатов подзапроса к основным таблицам,чтобы получить данные, соответствующие последнему значению строки updatedat.

Также, как правило, рекомендуется перевести условия WHERE в предложение join ON для простоты понимания.Кроме того, в будущем, когда вы переключитесь с INNER JOIN на LEFT JOIN и т. Д., Вы можете легко изменить, не беспокоясь о ненужной фильтрации, происходящей из-за WHERE.


Попробуйте выполнить следующий запрос: Просмотр на БД Fiddle

SELECT 
  o.id, 
  op.quantity, 
  osh.updatedat 
FROM 
  orders AS o 
JOIN order_products AS op 
  ON op.order_id = o.id AND 
     op.productid = 1 
JOIN order_status_history AS osh 
  ON osh.order_id = o.id 
JOIN (SELECT order_id, 
             MAX(updatedat) AS max_updated_at
      FROM order_status_history 
      WHERE order_status_id = 3
      GROUP BY order_id
     ) AS dt 
  ON dt.order_id = o.id AND 
     dt.max_updated_at = osh.updatedat;

Результат:

| id  | quantity | updatedat           |
| --- | -------- | ------------------- |
| 1   | 1        | 2017-05-22 18:45:50 |
| 1   | 2        | 2017-05-22 18:45:50 |
| 1   | 2        | 2017-05-22 18:45:50 |
| 1   | 10       | 2017-05-22 18:45:50 |

Кроме значений updatedat, есливам не нужно получать какие-либо другие столбцы из таблицы order_status_history, вы можете дополнительно оптимизировать запрос, избавившись от соединения с таблицей order_status_history

Query # 2

SELECT 
  o.id, 
  op.quantity, 
  dt.max_updated_at AS updatedat 
FROM 
  orders AS o 
JOIN order_products AS op 
  ON op.order_id = o.id AND 
     op.productid = 1 
JOIN (SELECT order_id, 
             MAX(updatedat) AS max_updated_at
      FROM order_status_history 
      WHERE order_status_id = 3
      GROUP BY order_id
     ) AS dt 
  ON dt.order_id = o.id;

Результат:

| id  | quantity | updatedat           |
| --- | -------- | ------------------- |
| 1   | 1        | 2017-05-22 18:45:50 |
| 1   | 2        | 2017-05-22 18:45:50 |
| 1   | 2        | 2017-05-22 18:45:50 |
| 1   | 10       | 2017-05-22 18:45:50 |
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...