2011-04-14 255 views
21

Daft SQL问题。我有一个像这样的表(“PID”是自动增量主要COL)MySQL查询,MAX()+ GROUP BY

CREATE TABLE theTable (
    `pid` INT UNSIGNED PRIMARY KEY AUTO_INCREMENT, 
    `timestamp` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, 
    `cost` INT UNSIGNED NOT NULL, 
    `rid` INT NOT NULL, 
) Engine=InnoDB; 

实际的表数据:

INSERT INTO theTable (`pid`, `timestamp`, `cost`, `rid`) 
VALUES 
    (1, '2011-04-14 01:05:07', 1122, 1), 
    (2, '2011-04-14 00:05:07', 2233, 1), 
    (3, '2011-04-14 01:05:41', 4455, 2), 
    (4, '2011-04-14 01:01:11', 5566, 2), 
    (5, '2011-04-14 01:06:06', 345, 1), 
    (6, '2011-04-13 22:06:06', 543, 2), 
    (7, '2011-04-14 01:14:14', 5435, 3), 
    (8, '2011-04-14 01:10:13', 6767, 3) 
; 

我想要得到的最新行的PID为每个RID(1每个唯一RID的结果)。对于样本数据,我想:

pid | MAX(timestamp)  | rid 
----------------------------------- 
5 | 2011-04-14 01:06:06 | 1 
3 | 2011-04-14 01:05:41 | 2 
7 | 2011-04-14 01:14:14 | 3 

我试着运行下面的查询:

SELECT MAX(timestamp),rid,pid FROM theTable GROUP BY rid 

,我也得到:

max(timestamp)  ; rid; pid 
---------------------------- 
2011-04-14 01:06:06; 1 ; 1 
2011-04-14 01:05:41; 2 ; 3 
2011-04-14 01:14:14; 3 ; 7 

的PID返回总是在第一次发生PID的RID(行/ pid 1是第一次使用rid 1,row/pid 3是第一次使用RID 2,row/pid 7是第一次使用rid 3)。虽然返回每个rid的最大时间戳,但pid不是来自原始表的时间戳的pid。什么查询会给我我要找的结果?

+0

你可以告诉你正在运行的精确查询的结果? – 2011-04-14 01:09:22

+0

更新了问题:) – codinghands 2011-04-14 01:37:00

+0

可能重复的[获取具有列的最大值的行](http://stackoverflow.com/questions/121387/fetch-the-row-which-has-the-max-值为列) – outis 2011-12-23 02:33:51

回答

44

(PostgreSQL中9.something测试)

确定RID和时间戳。

select rid, max(timestamp) as ts 
from test 
group by rid; 

1 2011-04-14 18:46:00 
2 2011-04-14 14:59:00 

加入到它。

select test.pid, test.cost, test.timestamp, test.rid 
from test 
inner join 
    (select rid, max(timestamp) as ts 
    from test 
    group by rid) maxt 
on (test.rid = maxt.rid and test.timestamp = maxt.ts) 
+0

魔术,工作的一种享受。任何想法为什么'SELECT MAX(timestamp),rid,pid FROM the table GROUP BY rid'不起作用? – codinghands 2011-04-14 01:45:05

+2

因为你想为每个删除***('GROUP BY rid')***,显示“***最大时间戳***”('MAX(timestamp)')和该行,最大时间戳,***相关的pid ***。这是你的想法卡住的地方。你需要一个“窗口化”功能来做到这一点,或者将组合子查询分组,然后“JOIN”作为Catcall的解决方案。 MYSQL没有窗口功能。 – 2011-04-14 09:40:16

+2

更糟的是,MySQL不会引发错误,但会从(随机)行中获取pid。 – 2011-04-14 09:43:06

-1

尝试:

select pid,cost, timestamp, rid from theTable order by timestamp DESC limit 2; 
+0

这只返回最新的2个条目。它需要是每个RID的最新行,每个RID 1个。 – codinghands 2011-04-14 01:16:04

4
SELECT t.pid, t.cost, to.timestamp, t.rid 
FROM test as t 
JOIN (
    SELECT rid, max(tempstamp) AS maxtimestamp 
    FROM test GROUP BY rid 
) AS tmax 
    ON t.pid = tmax.pid and t.timestamp = tmax.maxtimestamp 
+0

您刚刚被@Catcall殴打。 :) 谢谢! – codinghands 2011-04-14 01:52:07

0

你也可以有这样的子查询:

SELECT (SELECT MIN(t2.pid) 
     FROM test t2 
     WHERE t2.rid = t.rid 
      AND t2.timestamp = maxtimestamp 
     ) AS pid 
    , MAX(t.timestamp) AS maxtimestamp 
    , t.rid 
FROM test t 
GROUP BY t.rid 

但这样一来,就需要多一个子查询,如果你想包含在显示的列cost

所以,group byjoin是更好的解决方案。

2

我在rid和timestamp上创建了一个索引。

SELECT test.pid, test.cost, test.timestamp, test.rid 
FROM theTable AS test 
LEFT JOIN theTable maxt 
ON maxt.rid = test.rid 
AND maxt.timestamp > test.timestamp 
WHERE maxt.rid IS NULL 

显示行0 - 2(3总计,查询花费0.0104秒)

此方法将从theTable(测试)选择所有的需要的值,留在所有的时间标记加入本身(MAXT)高于在同一个摆脱测试的人。当时间戳已经是测试中的最高时间时,maxt上没有匹配 - 这是我们正在寻找的 - maxt上的值变为NULL。现在我们使用WHERE子句maxt.rid IS NULL或maxt上的任何其他列。

6
select * 
from (
    select `pid`, `timestamp`, `cost`, `rid` 
    from theTable 
    order by `timestamp` desc 
) as mynewtable 
group by mynewtable.`rid` 
order by mynewtable.`timestamp` 

希望我帮了忙!

+0

清晰,简洁的解决方案。 – 2015-05-12 16:53:13

+0

...和唯一真正为我工作的人。 – Debriter 2015-09-18 03:34:15

+0

这太棒了,太简单了。其他答案也可以工作,但我宁愿避免自己加入表格 – ProgrammingWithRandy 2016-09-14 16:00:43

0

如果你想避免JOIN,你可以使用:

SELECT pid, rid FROM theTable t1 WHERE t1.pid IN (SELECT MAX(t2.pid) FROM theTable t2 GROUP BY t2.rid); 
+0

根据数据,较高的PID不一定与较晚的时间戳相关联。 – 2014-10-15 16:28:22

+0

你说得对。它只在时间戳在程序中的任何地方未被修改并且仅存储de creation_date时起作用。 如果不是,由于PID是autoinc和时间戳current_timestamp我认为较高PID对应于较晚的时间戳 – 2014-11-05 15:51:57