MySQL - 左加入MAX时间戳

时间:2013-01-16 22:36:19

标签: mysql join max min

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

基本上我有一个不同项目的表格('chair','tables'),每种类型的记录都有自己的ID用于特定的椅子或桌子。然后我有一个位置表,它保留了所有曾经存在的位置,包括当前位置。当前位置由MAX时间戳记记。

我的查询是为了获取所有项目,并加入当前位置。我已经按照其他人所说的工作,但它不适合我。任何帮助表示赞赏。

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

1 个答案:

答案 0 :(得分:8)

试试这个:

    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。对于表work_id中的每个location,您需要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一样。允许这种行为,如果使用得当,可以带来一些好处。但它没有实现它100%防故障,因此在某些情况下应用它,像这样,可能会给出错误的结果.Postgres有一个更好的实现这个功能,它不会导致错误的结果。)

因此,您需要做的是使用上面的GROUP BY查询作为派生表(您可以将其命名为clCurrentLocation,无论您想要什么)并将其加入{ {1}}表,使用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也将使用索引来处理找到位置表中所需的行。)