2011-04-14 266 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