【问题标题】:Mysql duplicate result with joinMysql重复结果与连接
【发布时间】:2019-04-18 04:41:07
【问题描述】:

我有一个表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”表示已取消或无论如何都不可用),则对于每个订单 ID,只获取最后一个条目(基于 updatedat 列,最后一个表示最近的)

这是我尝试过的查询,但在这种情况下,为相同的订单 ID 和状态 3 返回 2 行:

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 

【问题讨论】:

标签: mysql distinct-values


【解决方案1】:

我相信orders表中没有任何条目,orders_productsorder_status_history表中就不可能有任何条目。所以,为了便于理解,我会改变表连接的顺序。此外,不需要LEFT JOIN,因为我们正在尝试获取特定产品的行(因此,行应该存在于 products 表中)和特定的 order_status (因此,行应该存在于状态历史表中)。所以我将查询中的LEFT JOIN全部改成INNER JOIN

现在,要获得与特定状态相对应的最后一行 updatedat,我们必须使用 Derived Table。在这个子查询中,当状态为 3 时,我们将为每个订单获取最新的 updatedat 值。

最终,我们将这个子查询结果集适当地加入到主表中,以获取与最新的updatedat行值对应的数据。

此外,为了便于理解,将WHERE 条件转移到连接ON 子句通常是一个好习惯。此外,将来当您从INNER JOIN 更改为LEFT JOIN 等时,您可以轻松更改,而不必担心由于WHERE 而发生不必要的过滤。


尝试以下查询: View on DB 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 表的连接来进一步优化查询

查询 #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 |

【讨论】:

    猜你喜欢
    • 2018-12-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-22
    • 2017-10-25
    • 2019-03-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多