Mysql 与连接重复的结果
Mysql duplicate result with join
我有一个 table 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 列,最后一个表示最新)
这是我试过的查询,但在本例中 returns 2 行相同的订单 ID 和状态 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
我相信 orders
table 中没有任何条目,orders_products
和 order_status_history
table 中也不会有任何条目。因此,为了便于理解,我会更改 table 连接的顺序。此外,不需要 LEFT JOIN
,因为我们正在尝试获取特定产品的行(因此,产品 table 中应该存在行),并且在特定的 order_status(因此,状态历史记录中应该存在行 table)。所以我将查询中的所有 LEFT JOIN
更改为 INNER JOIN
.
现在,要获取与特定状态对应的最后 updatedat
行,我们将不得不使用 Derived Table。在此子查询中,当状态为 3.
时,我们将为每个订单获取最新的 updatedat
值
最后,我们将这个子查询结果集适当加入主tables,得到最新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
table 中获取任何其他列,您可以通过删除进一步优化查询加入 order_status_history
table
查询#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 |
我有一个 table 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 列,最后一个表示最新)
这是我试过的查询,但在本例中 returns 2 行相同的订单 ID 和状态 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
我相信 orders
table 中没有任何条目,orders_products
和 order_status_history
table 中也不会有任何条目。因此,为了便于理解,我会更改 table 连接的顺序。此外,不需要 LEFT JOIN
,因为我们正在尝试获取特定产品的行(因此,产品 table 中应该存在行),并且在特定的 order_status(因此,状态历史记录中应该存在行 table)。所以我将查询中的所有 LEFT JOIN
更改为 INNER JOIN
.
现在,要获取与特定状态对应的最后 updatedat
行,我们将不得不使用 Derived Table。在此子查询中,当状态为 3.
updatedat
值
最后,我们将这个子查询结果集适当加入主tables,得到最新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
table 中获取任何其他列,您可以通过删除进一步优化查询加入 order_status_history
table
查询#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 |