Mysql如何通过最大日期时间减少行数并按非唯一标识

时间:2015-06-18 23:09:56

标签: mysql datetime join group-by

我患有严重的肠胀气。

保持简单,我有3个表:订单状态 XrefOrdersStatuses

我已经设置了一个带有简化模式和一些编辑行数据的SQLFiddle(SQLFiddle Here)。

我需要获得的是包含最新XrefOrdersStatuses的订单(与状态一起加入)。我可以使用以下查询来执行此操作:

SELECT o.shopper_name_first, o.shopper_name_last, os.os_name, x.xos_order_id, x.xos_status_id, x.xos_datetime
FROM Orders AS o 
INNER JOIN XrefOrdersStatuses AS x ON x.xos_order_id = o.order_id
LEFT JOIN Statuses AS os ON os.os_id = x.xos_status_id
ORDER BY x.xos_order_id, x.xos_datetime DESC

结果如下:

| shopper_name_first | shopper_name_last |             os_name | xos_order_id | xos_status_id |           xos_datetime |
|--------------------|-------------------|---------------------|--------------|---------------|------------------------|
|              Sally |               Sue | Order Pre-Processed |        34049 |            31 | June, 18 2015 12:42:50 |
|              Sally |               Sue |          Order Paid |        34049 |            20 | June, 18 2015 12:36:30 |
|              Sally |               Sue |       Order Created |        34049 |            10 | June, 18 2015 12:34:56 |
|                Joe |            Schmoe | Order Pre-Processed |        34050 |            31 | June, 18 2015 12:54:50 |
|                Joe |            Schmoe |          Order Paid |        34050 |            20 | June, 18 2015 12:38:30 |
|                Joe |            Schmoe |       Order Created |        34050 |            10 | June, 18 2015 12:34:56 |
|              Peter |             Piper |          Order Paid |        34051 |            20 | June, 18 2015 12:37:30 |
|              Peter |             Piper |       Order Created |        34051 |            10 | June, 18 2015 12:34:56 |

在生产场景中,我 SELECT (更多)/所有Orders表列,为了简单起见,将它们留在这里。请注意重复的订单,但状态排列。

在视图中,我正在努力的目的不是找到最新的状态。此视图列出了订单,我希望根据最大日期时间列值加入/匹配每个订单及其各自的最新状态。一对多架构(一个订单有很多状态)。

所以我想做的是:

  • SELECT订单
  • 使用MAX(xos_datetime)GROUP BY xos_order_id
  • 加入外部参照
  • 加入状态以获取定义

订单必须保留在查询中的左侧表(对于与其他表一起使用的其他连接)。在经历了许多其他SO问题和答案以及许多谷歌搜索后,我还没有找到我需要的东西。

如果需要按照最大日期时间获取XrefOrdersStatuses并按订单ID分组,这将是查询....

SELECT x.*
FROM XrefOrdersStatuses AS x
JOIN (
  SELECT xos_order_id, MAX(xos_datetime) AS maxdate
  FROM XrefOrdersStatuses
  GROUP BY xos_order_id
  ) AS x1 ON x1.xos_order_id = x.xos_order_id AND x1.maxdate = x.xos_datetime;

导致:

| xos_id | xos_order_id | xos_status_id |           xos_datetime |
|--------|--------------|---------------|------------------------|
| 118287 |        34051 |            20 | June, 18 2015 12:37:30 |
| 118289 |        34049 |            31 | June, 18 2015 12:42:50 |
| 118290 |        34050 |            31 | June, 18 2015 12:54:50 |

......耶!每个订单的最新状态!

唉,我需要Orders表作为左侧表(其他连接和搜索位置 - 即名称,活动/非活动,分配给用户等)。

我的麻烦是将Orders查询与XrefOrdersStatuses查询相结合。我似乎无法让他们一起玩。我的尝试因订购,分组和各种激烈的混乱而失败。

我觉得这让我很接近,但是让分组和订购正确是我在讨人喜欢的地方:

SELECT o.shopper_name_first, o.shopper_name_last, os.os_name, x.xos_order_id, x.xos_status_id, x.xos_datetime
FROM Orders AS o 
JOIN (
  SELECT xz.*
  FROM XrefOrdersStatuses AS xz
  JOIN (
    SELECT xos_order_id, MAX(xos_datetime) AS maxdate
    FROM XrefOrdersStatuses
    GROUP BY xos_order_id
  ) AS x1 ON x1.xos_order_id = xz.xos_order_id AND x1.maxdate = xz.xos_datetime
) AS x
LEFT JOIN Statuses AS os ON os.os_id = x.xos_status_id
ORDER BY x.xos_order_id, x.xos_datetime DESC;

结果如下所示:

| shopper_name_first | shopper_name_last |             os_name | xos_order_id | xos_status_id |           xos_datetime |
|--------------------|-------------------|---------------------|--------------|---------------|------------------------|
|                Joe |            Schmoe | Order Pre-Processed |        34049 |            31 | June, 18 2015 12:42:50 |
|              Peter |             Piper | Order Pre-Processed |        34049 |            31 | June, 18 2015 12:42:50 |
|              Sally |               Sue | Order Pre-Processed |        34049 |            31 | June, 18 2015 12:42:50 |
|                Joe |            Schmoe | Order Pre-Processed |        34050 |            31 | June, 18 2015 12:54:50 |
|              Peter |             Piper | Order Pre-Processed |        34050 |            31 | June, 18 2015 12:54:50 |
|              Sally |               Sue | Order Pre-Processed |        34050 |            31 | June, 18 2015 12:54:50 |
|              Peter |             Piper |          Order Paid |        34051 |            20 | June, 18 2015 12:37:30 |
|              Sally |               Sue |          Order Paid |        34051 |            20 | June, 18 2015 12:37:30 |
|                Joe |            Schmoe |          Order Paid |        34051 |            20 | June, 18 2015 12:37:30 |

我尝试了不同的变化,尝试向前,向后,向左,向右,向内,向外,向上,向下,热,冷,湿,干......你得到了图片。

我需要的是它看起来像这样:

| shopper_name_first | shopper_name_last |             os_name | xos_order_id | xos_status_id |           xos_datetime |
|--------------------|-------------------|---------------------|--------------|---------------|------------------------|
|              Sally |               Sue | Order Pre-Processed |        34049 |            31 | June, 18 2015 12:42:50 |
|                Joe |            Schmoe | Order Pre-Processed |        34050 |            31 | June, 18 2015 12:54:50 |
|              Peter |             Piper |          Order Paid |        34051 |            20 | June, 18 2015 12:37:30 |

如果您回到第一个查询...我需要这些结果,但会减少,以便只保留每个订单的最新状态。我实际上是在PHP之后执行此操作...因此我正在重新查询查询以从PHP中删除看似不必要的步骤。

也许我的解决方案是XrefOrdersStatuses查询(上面的第二个),但使用RIGHT JOIN来获取Order和Status表?

有人想到吗?很抱歉让这么久(几乎TL;我自己的DR),但我希望我已经适当地注释了这个问题。

BTW - 我是SO的长期潜伏者(从这里发现的问题中收集了无数的问题和提示!)但这是我第一次陷入困境并且无法弄清楚如何获得我需要什么。

编辑/解答:按照我需要的方式设置查询,发现我的性能问题与列和索引相关。有点像去医院腹痛,只是被告知你有Crohns,然后发现你的肾脏有肿瘤 - 最后事情变得很好。

# Query for answer to user Linoff with mods
SELECT o.shopper_name_first, o.shopper_name_last, s.os_name, x.*
FROM Orders o 
RIGHT JOIN XrefOrdersStatuses x ON x.xos_order_id = o.order_id 
RIGHT JOIN
(
  SELECT xos_order_id, MAX(xos_datetime) AS maxdate
  FROM XrefOrdersStatuses
  GROUP BY xos_order_id
) xmax ON xmax.xos_order_id = x.xos_order_id AND xmax.maxdate = x.xos_datetime
LEFT JOIN Statuses s ON s.os_id = x.xos_status_id
ORDER BY o.order_datetime DESC;

1 个答案:

答案 0 :(得分:0)

这是你在找什么?

SELECT <choose your columns here>
FROM Orders o LEFT JOIN
     XrefOrdersStatuses x
     ON x.xos_order_id = o.order_id LEFT JOIN
     (SELECT xos_order_id, MAX(xos_datetime) AS maxdate
      FROM XrefOrdersStatuses
      GROUP BY xos_order_id
     ) xmax
     ON xmax.xos_order_id = x.xos_order_id AND
        xmax.maxdate = x.xos_datetime;

只有在没有状态记录的订单时才需要LEFT JOIN