2009-05-29 8 views
45

Ich habe die folgende Tabelle:Wählen Sie die 3 letzten Datensätze, bei denen die Werte einer Spalte verschieden sind

id  time  text  otheridentifier 
    ------------------------------------------- 
    1  6   apple  4 
    2  7   orange 4 
    3  8   banana 3 
    4  9   pear  3 
    5  10  grape  2 

Was ich die drei letzten Aufzeichnungen machen wollen (nach Zeit ab) wird ausgewählt, deren otheridentifier s sind verschieden. Also in diesem Fall, wäre das Ergebnis id ‚s sein: 5, 4 und 2.

id = 3 würde übersprungen werden, weil es mit dem gleichen otheridentifier Feld ein neueres Rekord ist.

Hier ist, was ich versuchte zu tun:

SELECT * FROM `table` GROUP BY (`otheridentifier`) ORDER BY `time` DESC LIMIT 3 

Aber ich Reihen von id am Ende immer = 5, und statt 5, 4, 2, wie erwartet.

Kann mir jemand sagen, warum diese Abfrage nicht das ergibt, was ich erwartet habe? Ich habe versucht, die ORDER BY zu ASC ändern, aber dies einfach umordnet die zurückgegebenen Zeilen auf 1, 3, 5.

Antwort

34

Es gibt nicht, was Sie erwarten, da Gruppierung vor der Bestellung passiert, wie durch die Position der Klauseln in der SQL-Anweisung Du wirst unglücklicher werden müssen, um die Reihen zu bekommen, die du willst. Versuchen Sie folgendes:

SELECT * 
FROM `table` 
WHERE `id` = (
    SELECT `id` 
    FROM `table` as `alt` 
    WHERE `alt`.`otheridentifier` = `table`.`otheridentifier` 
    ORDER BY `time` DESC 
    LIMIT 1 
) 
ORDER BY `time` DESC 
LIMIT 3 
+1

ich die Zeit, die ich Stunden wie diese zu beheben verbrachte erinnerte SQL- und stellt sich heraus, mysql ist 4.0 nicht verschachtelte Abfragen unterstützen; p – Unreality

+1

@Unreality: Fortu Die meisten Lösungen mit Unterabfragen können bei Bedarf als Joins ausgedrückt werden. :) – Rytmis

+1

Ja, aber diejenigen mit ORDER/LIMIT sind _nicht_ einfach ausgedrückt von JOIN ... –

2
SELECT * FROM table t1 
WHERE t1.time = 
    (SELECT MAX(time) FROM table t2 
    WHERE t2.otheridentifier = t1.otheridentifier) 
+0

Wie würde dies die letzte Zeile pro anderen Identifier auswählen? – Andomar

+0

@Andomar: Ich sollte nicht versuchen, Fragen zu beantworten, wenn ich nicht ganz wach bin. Verändert die Spaltennamen ein bisschen - sehen Sie, ob es jetzt mehr Sinn macht. :) – Rytmis

18

Sie in der Tabelle auf sich anschließen konnte den letzten Eintrag pro otheridentifier, filtern und dann die Top-3 Reihen, dass:

SELECT last.* 
FROM `table` last 
LEFT JOIN `table` prev 
    ON prev.`otheridentifier` = last.`otheridentifier` 
    AND prev.`time` < last.`time` 
WHERE prev.`id` is null 
ORDER BY last.`time` DESC 
LIMIT 3 
+0

Andomar, können Sie erklären, wie MySQL Tabelle 'prev' in Ihrer Abfrage verwendet? Ich habe versucht, dies für eine lokale Abfrage zu verwenden, und bekomme eine Fehlermeldung, dass 'database.prev' nicht existiert. –

+0

Fiddle mit OP-Daten und Ihre Abfrage. Nicht sicher, warum diese Antwort wurde 6 mal upvoted - es funktioniert hier nicht: http://sqlfiddle.com/#!2/ace0b/1 –

+1

@acoder: Du hast Recht, es gab einen kleinen Fehler in der Abfrage: die Tabellenname nach 'left join' fehlt. Ich habe die Antwort aktualisiert. – Andomar

2

Andomar's answer ist wahrscheinlich am besten in dass es keine Unterabfrage verwendet.

Ein alternativer Ansatz:

select * 
from `table` t1 
where t1.`time` in (
        select max(s2.`time`) 
        from  `table` t2 
        group by t2.otheridentifier 
        ) 
+0

Ich denke, ich sehe ein Problem hier, wenn die Zeitwerte nicht eindeutig sind - dies könnte Zeilen zurückgeben, die es nicht sollte. Angenommen, es gibt einen Zeitwert, der für einen anderen Identifizierer das Maximum ist, aber für einen anderen Identifizierer zum Beispiel zweithöchster Wert ist. Würde diese Abfrage dann nicht beide anderen Identifikatoren zurückgeben? Ich bin vielleicht völlig daneben, aber ich bin immer noch ein bisschen müde. :) – Rytmis

+0

@Rytmis: Ja, und so würde meine Abfrage, und Ihre :) hehe – Andomar

+0

@Andomar: Hmm, bist du sicher über meine Frage obwohl? Da ich es gerade getestet habe, indem ich eine Zeile (6, 7, 'Erdbeere', 3) hinzugefügt habe - ist der Zeitwert 7 der größte Wert in der Gruppe mit dem anderen Identifikator 4, aber der zweitgrößte in dem mit dem anderen Identifizierer 3. Mein Die Abfrage gibt nur die vom OP gewünschten Zeilen zurück. Ist mein Testfall falsch? :) – Rytmis

1

was

SELECT *, max(time) FROM `table` group by otheridentifier 
+0

Bearbeiten - das funktioniert auf die Daten des OP. Ich hatte einige zusätzliche Joins in meiner Abfrage. Dies funktioniert gut mit den OP-Daten. http://sqlfiddle.com/#!2/ace0b/2 –

+1

Es scheint nicht zu funktionieren. In Ihrem sqlfiddle sollte es Orange und Birne zeigen - ihr Zeitwert ist höher. – mahemoff

+0

@mahemoff Das funktioniert nicht wie gesagt. – GusDeCooL

4

hatte ich eine ähnliche Anforderung, aber ich hatte mehr erweiterte Auswahlkriterien. einige der anderen Antworten Verwenden ich nicht genau bekommen konnte, was ich brauchte, aber ich fand man noch wie diese nach und ORDER eine GROUP BY tun können:

SELECT t.* FROM (SELECT * FROM table ORDER BY time DESC) t 
GROUP BY t.otheridentifier 
+0

funktioniert fein für mich !! – wiLLiamcastrO

2

Sie diese Abfrage verwenden können, richtige Antwort zu bekommen:

SELECT * FROM 
     (SELECT * FROM `table` order by time DESC) 
      t group by otheridentifier 
0

Dies auch:

SELECT * FROM 
OrigTable T INNER JOIN 
( 
SELECT otheridentifier,max(time) AS duration 
FROM T 
GROUP BY otheridentifier) S 
ON S.duration = T.time AND S.otheridentifier = T.otheridentifier. 
Verwandte Themen