GROUP BY with MAX(DATE) [重复]

Posted

技术标签:

【中文标题】GROUP BY with MAX(DATE) [重复]【英文标题】:GROUP BY with MAX(DATE) [duplicate] 【发布时间】:2011-03-30 07:29:46 【问题描述】:

我正在尝试在表格中列出每列火车的最新目的地(最大发车时间)for example:

Train    Dest      Time
1        HK        10:00
1        SH        12:00
1        SZ        14:00
2        HK        13:00
2        SH        09:00
2        SZ        07:00

期望的结果应该是:

Train    Dest      Time
1        SZ        14:00
2        HK        13:00

我尝试过使用

SELECT Train, Dest, MAX(Time)
FROM TrainTable
GROUP BY Train

我收到“ora-00979 不是 GROUP BY 表达式”错误,提示我必须在我的 group by 语句中包含“Dest”。但这肯定不是我想要的……

是否可以在一行 SQL 中完成?

【问题讨论】:

对于那些想知道的人,最干净的“plain sql”解决方案是the one by Joe。二等奖授予Claudio。 【参考方案1】:
SELECT train, dest, time FROM ( 
  SELECT train, dest, time, 
    RANK() OVER (PARTITION BY train ORDER BY time DESC) dest_rank
    FROM traintable
  ) where dest_rank = 1

【讨论】:

Thx Thilo :-) 事实上你的答案也是正确的。但由于我只能接受 1 个答案,所以我选择了 Oliver,因为我先尝试了他的答案。 @Aries - Thilo 的答案优于 Oliver 的答案,因为 Thilo 的答案往往会执行更少的 I/O。解析函数允许 SQL 一次处理表,而 Oliver 的解决方案需要多次处理。 同意,GROUP BY 会导致不必要的性能损失。使用这种方法,甚至使用左连接会更有效,尤其是对于较大的表。 上面的代码和下面使用row_number的代码有什么区别?任何人都可以向我解释。 SELECT train, dest, time FROM (SELECT train, dest, time, ROW_NUMBER() OVER (PARTITION BY train ORDER BY time DESC) rn FROM traintable) where rn = 1 @Ruslan,是的,我很同情 mysql 开发人员。【参考方案2】:

您不能在结果集中包含未分组的非聚合列。如果一列火车只有一个目的地,那么只需将目的地列添加到您的 group by 子句中,否则您需要重新考虑您的查询。

试试:

SELECT t.Train, t.Dest, r.MaxTime
FROM (
      SELECT Train, MAX(Time) as MaxTime
      FROM TrainTable
      GROUP BY Train
) r
INNER JOIN TrainTable t
ON t.Train = r.Train AND t.Time = r.MaxTime

【讨论】:

小心,如果 max(time) 有“关系”,这将不起作用,因为您将获得多行。您需要在上面的整个查询后面添加group by train,dest 好的。但是,如果内部查询连接到另一个表,这将如何工作?让我们假设 TrainTable 中的 Destination 有它自己的表。所以内部查询看起来像: select t.train, d.dest, max(time) from TrainTable t join Destination d on t.destid = d.id group by t.train, d.dest【参考方案3】:

这是一个仅使用左联接的示例,我相信它比任何分组方法都更有效:ExchangeCore Blog

SELECT t1.*
FROM TrainTable t1 LEFT JOIN TrainTable t2
ON (t1.Train = t2.Train AND t1.Time < t2.Time)
WHERE t2.Time IS NULL;

【讨论】:

我喜欢这种方法,因为它只使用标准 SQL 并且工作得非常好和快。 令人大开眼界的是,有多少人一直说这个解决方案“很棒”和“最好”,但没有人尝试过。简单地说,不起作用。正确的查询是:select t1.* from TrainTable t1 left join TrainTable t2 on (t1.Train= t2.Train and t1.Time &lt; t2.Time) where t2.Time is null @Pacerier 你是对的,查看操作所期望的结果是正确的 sql(尽管概念是相同的)。我已经更新了我的答案。 有趣,但我检查了我的 MS SQL Server 服务器(21000 条记录),这比 MAX + GROUP BY 慢 3 倍 非常慢!具有日期、从、到、汇率字段的货币换算表。总共 203161 行。 Joe Meyer 方法在集合中给出 362 行(31.29 秒)。 Oliver Hanappi 方法在集合中给出 362 行(0,04 秒)【参考方案4】:

另一种解决方案:

select * from traintable
where (train, time) in (select train, max(time) from traintable group by train);

【讨论】:

小心,如果 max(time) 有“关系”,这将不起作用,因为您将获得多行。改用这个:select * from traintable where (train, time) in (select train, max(time) from traintable group by train) group by train,dest; 【参考方案5】:

只要没有重复(火车往往一次只能到达一个车站)...

select Train, MAX(Time),
      max(Dest) keep (DENSE_RANK LAST ORDER BY Time) max_keep
from TrainTable
GROUP BY Train;

【讨论】:

“而且火车往往一次只能到达一个车站”......这没有说明。【参考方案6】:

我知道我迟到了,但试试这个...

SELECT 
    `Train`, 
    `Dest`,
    SUBSTRING_INDEX(GROUP_CONCAT(`Time` ORDER BY `Time` DESC), ",", 1) AS `Time`
FROM TrainTable
GROUP BY Train;

源:Group Concat Documentation

编辑:修正 sql 语法

【讨论】:

以上是关于GROUP BY with MAX(DATE) [重复]的主要内容,如果未能解决你的问题,请参考以下文章

使用 GROUP BY 后查找具有 MAX 值的行

MySQL使用group by 报this is incompatible with sql_mod

SQL group by with Case 语句

mysql group by和max [重复]

GROUP BY 有 MAX 日期

使用group by with order一起查询时间慢