【问题标题】:MySQL - Left Join on MAX timestampMySQL - 在 MAX 时间戳上左连接
【发布时间】:2013-01-16 22:36:18
【问题描述】:

我知道这是一个常见问题,因为我之前已经问过这个问题,并且已经看了几个,但是,尽管我的查询基于此,我仍然无法让它发挥作用。请参阅:Mysql join based on max(timestamp)mysql LEFT join for right table max value

基本上,我有一张包含不同物品(“椅子”、“桌子”)的桌子,每种类型都有针对特定椅子或桌子的带有自己 ID 的记录。然后我有一个位置表,其中保存了所有曾经的位置,包括当前位置。当前位置由 MAX 时间戳记。

我的查询旨在获取所有项目,并加入到当前位置。我遵循了其他人所说的有效方法,但它对我不起作用。任何帮助表示赞赏。

编辑:我没有说它是如何失败的:它获取记录并进行连接,它返回最大时间戳,但不返回与 MAX(timestamp) 记录对应的记录信息。所以它给出了正确的时间戳,但地板等不是来自具有 MAX 时间戳的记录。

谢谢!

查询:

$q = "SELECT
        'chairs' AS work_type,
        chairs.id AS work_id,
        chairs.title,
        chairs.dimensions,
        CurrentLocations.floor,
        CurrentLocations.bin,
        CurrentLocations.bay,
        CurrentLocations.other
       FROM chairs
             LEFT JOIN ( 
                        SELECT 
                              locations.id AS loc_id,
                              locations.work_type AS clwt,
                              locations.work_id AS clwi,
                              locations.floor,
                              locations.bin,
                              locations.bay,
                              locations.other,
                              MAX(locations.timestamp) AS latestLocation
                            FROM
                               locations
                            GROUP BY
                               locations.work_type, locations.work_id
                            ) CurrentLocations
                ON CurrentLocations.clwi = chairs.id AND CurrentLocations.clwt = 'chairs'
        WHERE cur_loc LIKE '%19th Street%'
        ORDER BY 
            FIELD(floor, 'Basement', '3rd Floor', '4th Floor', '5th Floor'), 
            bin, 
            bay,
            other";

【问题讨论】:

  • 怎么没用,你遇到了什么错误?你得到错误的结果?
  • 是的,对不起,我不知道:它给出了结果,但它选择的位置记录不是基于最新的时间戳。
  • 首先,您通常应该对给定 SELECT 子句中的每个未聚合字段进行 GROUP BY。例如。 SELECT field1,field2,MAX(field3) FROM my_table GROUP BY field1,field2;此外,您的位置表看起来需要标准化。

标签: mysql join max min


【解决方案1】:

试试这个:

    SELECT
        'chairs' AS work_type,        -- do you really need this in the result?
        c.id AS work_id,
        c.title,
        c.dimensions,
        l.floor,
        l.bin,
        l.bay,
        l.other
    FROM 
        chairs AS c
      LEFT JOIN
        ( SELECT work_id,
                 MAX(timestamp) AS latestLocation
          FROM   locations
          WHERE  work_type = 'chairs'
          GROUP BY work_id
        ) AS cl                                  -- CurrentLocations
          ON  cl.work_id = c.id
      LEFT JOIN
        locations AS l 
          ON  l.work_type = 'chairs'
          AND l.work_id = cl.work_id
          AND l.timestamp = cl.latestLocation 
    WHERE 
        c.cur_loc LIKE '%19th Street%'
    ORDER BY 
        FIELD(l.floor, 'Basement', '3rd Floor', '4th Floor', '5th Floor'), 
        l.bin, 
        l.bay,
        l.other ;

说明:

你想要:

基本上,我有一张不同物品的桌子(chairstables),每种类型的椅子或桌子都有自己的 ID 记录。然后我有一个locations 表,其中保存了所有曾经存在的位置,包括当前位置。当前位置以最大timestamp标注。

我的查询是为了获取所有物品(椅子),并加入到当前位置。

因此,对于每个项目(即chair),您只需要最新 location。对于表location 中的每个work_id,您需要MAX(timestamp)。这可以通过GROUP BY 轻松找到,正如您已经发现的那样:

        ( SELECT work_id,
                 MAX(timestamp) AS latestLocation
          FROM   locations
          GROUP BY work_type
                 , work_id
        ) AS cl

但您还想使用该表中的其他列,如果您只是将它们添加到选择列表中,则会显示错误的结果。 (请注意,在大多数 DBMS 中,为了使用不在 GROUP BY 列表中的列,您必须应用聚合函数,就像您将 MAX() 应用到 timestamp 一样。如果正确,MySQL 允许这种行为使用, 可以有一些好处. 但是它没有实现它 100% 防故障, 因此在某些情况下应用它, 像这个, 可能会给出错误的结果. Postgres 有一个更好的实现这个特性, 它不会允许错误结果。)

所以,你要做的就是使用上面的 GROUP BY 查询作为派生表(你可以将它命名为 clCurrentLocation,任何你想要的)并将它加入到 locations 表中,使用所有GROUP BY 列表中的列和聚合的列 (timestamp):

      JOIN
        locations AS l 
          ON  l.work_type = cl.work_type
          AND l.work_id = cl.work_id
          AND l.timestamp = cl.latestLocation 

之后,您可以像往常一样将它们加入chairs 表。由于您在原始查询中有 chairs LEFT JOIN locations,因此我也将这些保留在答案中。

另一个小的修改是,由于您有 CurrentLocations.work_id = 'chairs',因此您只需要 locations 表中的那些行。因此,首先进行分组然后拒绝所有不符合该条件的行是相当多余的。首先应用条件然后分组可能更有效。最终的分组查询和连接条件也相应修改。

另请注意,(work_type, work_id, timestamp) 上的索引将提高查询效率(cl 子查询将仅使用该索引进行处理,JOIN locations 也将使用该索引从位置表。)

【讨论】:

  • 就是这样,谢谢。你能 - 如果你愿意,你已经做的够多了 - 描述一下这里发生了什么以及有什么区别?但这太棒了,谢谢你们。
  • 感谢您的帮助和解释。这是非常有帮助的。如果我能再次投票给你,我会的。
猜你喜欢
  • 2016-03-18
  • 1970-01-01
  • 2011-04-20
  • 2012-03-17
  • 1970-01-01
  • 2021-02-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多