web-dev-qa-db-de.com

MySQL-Abfrage, MAX () + GROUP BY

Daft SQL-Frage. Ich habe eine Tabelle wie diese ("pid" ist automatisch inkrementelle primäre Spalte)

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;

Aktuelle Tabellendaten:

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)
;

Ich möchte die PID der letzten Zeile für jedes Rid erhalten (1 Ergebnis pro eindeutiger RID). Für die Beispieldaten möchte ich:

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

Ich habe versucht, die folgende Abfrage auszuführen:

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

und ich bekomme:

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

Die zurückgegebene PID ist immer das erste Vorkommen der PID für eine RID (Zeile/PID 1 ist das erste Mal, dass RID 1 verwendet wird, Zeile/PID 3, wenn RID 2 zum ersten Mal verwendet wird; Zeile/PID 7 wird zum ersten Mal, wenn RID 3 verwendet wird ). Obwohl der maximale Zeitstempel für jedes Rid zurückgegeben wird, sind die Pids nicht die Pids für die Zeitstempel aus der Originaltabelle. Welche Abfrage würde mir die gewünschten Ergebnisse liefern?

26
codinghands

(Getestet in PostgreSQL 9.etwas)

Identifizieren Sie das Datum und den Zeitstempel.

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

Mach mit!.

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)
select *
from (
    select `pid`, `timestamp`, `cost`, `rid`
    from theTable 
    order by `timestamp` desc
) as mynewtable
group by mynewtable.`rid`
order by mynewtable.`timestamp`

Hoffe ich habe geholfen! 

7
anzize
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
4
dkretz

Ich habe einen Index für Rid und Timestamp erstellt.

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 

Zeige Zeilen 0 - 2 (3 gesamt, Abfrage dauerte 0.0104 sec)

Bei dieser Methode werden alle gewünschten Werte aus theTable (test) ausgewählt, wobei sich der Link (maxt) auf allen Zeitstempeln verbindet, die höher sind als die im Test mit dem gleichen Ergebnis. Wenn der Zeitstempel bereits der höchste im Test ist, gibt es keine Übereinstimmungen bei maxt - was wir suchen - die Werte für maxt werden NULL. Jetzt verwenden wir die WHERE-Klausel maxt.rid IS NULL oder eine beliebige andere Spalte von maxt.

2
Caio Iglesias

Wenn Sie ein JOIN vermeiden möchten, können Sie Folgendes verwenden:

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

Sie könnten auch solche Unterabfragen haben:

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

Auf diese Weise benötigen Sie jedoch eine weitere Unterabfrage, wenn Sie cost in die angezeigten Spalten usw. aufnehmen möchten. 

Daher ist group by und join die bessere Lösung.

0
ypercubeᵀᴹ