web-dev-qa-db-de.com

Wählen Sie die drei letzten Datensätze aus, bei denen die Werte einer Spalte unterschiedlich sind

Ich habe folgende Tabelle:

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

Ich möchte die 3 letzten Datensätze (nach Zeitabnahme) auswählen, deren otheridentifiers verschieden sind. In diesem Fall wäre das Ergebnis also ids: 5, 4 und 2.

id = 3 wird übersprungen, da es einen neueren Datensatz mit demselben otheridentifier-Feld gibt.

Folgendes habe ich versucht:

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

Am Ende bekomme ich jedoch Zeilen mit id = 5, 3 und 1 anstelle von 5, 4, 2 wie erwartet. 

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

45
atp

Es gibt nicht das zurück, was Sie erwarten, da die Gruppierung vor der Anordnung erfolgt, wie durch die Position der Klauseln in der SQL-Anweisung angegeben. Sie werden leider schicker werden müssen, um die gewünschten Reihen zu erhalten. Versuche dies:

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
34
chaos

Sie können die Tabelle in sich zusammenfügen, um den letzten Eintrag nach otheridentifier zu filtern, und dann die obersten drei Zeilen davon übernehmen:

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
18
Andomar

Ich hatte eine ähnliche Anforderung, hatte jedoch erweiterte Auswahlkriterien. Mit einigen anderen Antworten konnte ich nicht genau das bekommen, was ich brauchte, aber ich fand, dass Sie immer noch eine GROUP BY und ORDER BY so machen können:

SELECT t.* FROM (SELECT * FROM table ORDER BY time DESC) t 
GROUP BY t.otheridentifier
4
11101101b
SELECT * FROM table t1 
WHERE t1.time = 
    (SELECT MAX(time) FROM table t2 
     WHERE t2.otheridentifier = t1.otheridentifier)
2
Rytmis

Andomars Antwort ist wahrscheinlich am besten, da keine Unterabfrage verwendet wird.

Ein alternativer Ansatz: 

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

Sie können diese Abfrage verwenden, um die richtige Antwort zu erhalten:

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

wie wäre es mit 

SELECT *, max(time) FROM `table`  group by otheridentifier
1
mbo

Das 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.
0
user2450223