【问题标题】:Help write a query: Confusion over order of operations of GROUP BY and ORDER BY帮忙写一个查询:对GROUP BY和ORDER BY操作顺序的混淆
【发布时间】:2008-10-25 18:06:03
【问题描述】:

我有一个名为 Info 这个架构的表:

int objectId;
int time;
int x, y;

系统中有很多冗余数据——即objectId不是UNIQUE。对于每个objectId,可以有多个time, x, y 条目。

我想检索每个对象的最新位置列表。我从这个查询开始:

SELECT * FROM Info GROUP BY objectId

这让我得到了我正在寻找的那种列表。但是我也想获得每个对象的最新时间,所以我尝试了:

SELECT * FROM Info GROUP BY objectId ORDER BY time DESC

这给了我一个time 降序信息列表。但是,我认为它没有达到我想要的效果 - 即返回每个对象的最新 time, x, y

谁能想象一个查询来做我想做的事?

更新我已经尝试了前三种解决方案,看看它们在大约 50,000 个信息的数据集上的表现如何。结果如下:

-- NO INDEX: forever
-- INDEX: 7.67 s

SELECT a.*
FROM Info AS a
  LEFT OUTER JOIN Info AS b ON (a.objectId = b.objectId AND a.time < b.time)
WHERE b.objectId IS NULL;

-- NO INDEX: 8.05 s
-- INDEX: 0.17 s

select a.objectId, a.time, a.x, a.y
  from Info a,
       (select objectId, max(time) time from Info group by objectId) b
  where a.objectId = b.objectId and a.time = b.time;

-- NO INDEX: 8.30 s
-- INDEX: 0.18 s

SELECT A.time, A.objectId, B.x, B.y
FROM
(
   SELECT max(time) as time, objectId 
   FROM Info
   GROUP by objectId
) as A 
INNER JOIN Info B
   ON A.objectId = b.objectId AND A.time = b.time;

在一定程度上,where 的表现似乎优于 inner join

【问题讨论】:

    标签: mysql sql database


    【解决方案1】:
    SELECT A.time, A.objectID, B.X, B.Y
    FROM
    (
       SELECT max(time) as time, objectID 
       FROM table
       GROUP by objectID
    ) as A 
    INNER JOIN table B
       ON A.objectID = b.objectID AND A.Time = b.Time
    

    投票者,如果 x 和 y 在时间线的任何时间点递减,解决方案将不起作用。

    【讨论】:

      【解决方案2】:

      一种方法是使用子查询。

      select distinct a.objectID, a.time, a.x, a.y
        from Info a,
             (select objectID, max(time) time from Info group by objectID) b
        where a.objectID = b.objectID and a.time = b.time
      

      编辑:添加了 DISTINCT 以防止在一个 objectId 有多个同时记录的情况下出现重复行。如果有必要,取决于您的数据,问题作者提到有很多重复的行。 (Tomalak添加

      【讨论】:

      • 使用 DISTINCT 子句可防止输出中出现重复行,以防单个 objectId 存在多个具有相同时间的条目。
      • 我比 Campbell 更喜欢 Glomek 的 SQL 风格,所以我投票赞成这个 - 但它们基本相同。这只是口味问题。
      • Tomalak:你能详细说明一下吗?您可以使用 Glomek 的 SQL 并添加您的 DISTINCT 子句吗?或者格洛梅克不会介意?
      • 完成。我想写我自己的答案不会有太大的不同。 :-)
      【解决方案3】:

      不管怎样,这是获得所需结果的另一种方法。在 MySQL 4.0 的日子里,在支持子查询之前,我养成了做这种技巧的习惯。

      SELECT a.*
      FROM Info AS a
        LEFT OUTER JOIN Info AS b ON (a.objectID = b.objectID AND a.time < b.time)
      WHERE b.objectID IS NULL;
      

      换句话说,向我显示不存在具有相同 objectID 和更长时间的其他行的行。这自然会返回每个 objectID 具有最大时间的行。不需要 GROUP BY。

      【讨论】:

      • 你不需要MAX吗?
      • 不,您不需要 MAX()。当 b.objectID 为 NULL 时,表示不满足连接条件,即当前行 'a' 具有任何具有相同 objectID 的行的最大时间值。
      【解决方案4】:

      对于属于组的一行,这是获取一行中所有信息的一种非常常见的方式。

      Select Info.*
      from Info
      inner join
         (select ObjectId, max(time) as Latest
          from Info
          group by ObjectId)  I
      on Info.ObjectId = I.ObjectID and Info.time = I.Latest
      

      在过去的几周里,同一个问题以不同的形式被问过几次。我忘记了问题的措辞。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-03-04
        • 2016-06-25
        • 2019-01-21
        • 1970-01-01
        • 1970-01-01
        • 2021-11-17
        • 1970-01-01
        相关资源
        最近更新 更多