2016-07-29 17 views
1
+------+---------+--------+---------+---------+---------+ 
| id | user_id | obj_id | created | applied | content | 
+------+---------+--------+---------+---------+---------+ 
| 1 |  1 |  1 |  1 |  1 | ...  | 
| 2 |  1 |  2 |  1 |  1 | ...  | 
| 3 |  1 |  1 |  1 |  2 | ...  | 
| 4 |  1 |  2 |  2 |  2 | ...  | 
| 5 |  2 |  1 |  1 |  1 | ...  | 
| 6 |  2 |  2 |  1 |  1 | ...  | 
+------+---------+--------+---------+---------+---------+ 

Ich habe eine Tabelle ähnlich der oben genannten. id, user_id und obj_id sind Fremdschlüssel; created und applied sind Zeitstempel, die als Ganzzahlen gespeichert sind. Ich muss die gesamte Zeile, gruppiert von user_id und obj_id, mit dem maximalen Wert von applied bekommen. Wenn zwei Zeilen den gleichen applied Wert haben, muss ich den maximalen Wert von created bevorzugen. Also für die obigen Daten, meine gewünschte Ausgabe ist:MySQL erhält das Maximum der Spalte mit Fallback zur zweiten Spalte

+------+---------+--------+---------+---------+---------+ 
| id | user_id | obj_id | created | applied | content | 
+------+---------+--------+---------+---------+---------+ 
| 1 |  1 |  1 |  1 |  1 | ...  | 
| 4 |  1 |  2 |  2 |  2 | ...  | 
| 5 |  2 |  1 |  1 |  1 | ...  | 
| 6 |  2 |  2 |  1 |  1 | ...  | 
+------+---------+--------+---------+---------+---------+ 

Meine aktuelle Lösung ist alles geordnet werden von applied dann created:

select * from data order by applied desc created desc; 

und Dingen aussortieren im Code, aber diese Tabelle wird ziemlich groß und ich würde gerne eine SQL-Lösung, die nur die Daten, die ich brauche.

+0

➕1 für die ASCII-Kunst; Aber für CVE: Bitte fügen Sie Ihre erste Anfrage hinzu. –

+0

@LinusKleen Wie meinst du das? Die Abfrage, die ich gerade verwende, oder die Abfragen, um die obigen Daten zu replizieren? –

+0

Entschuldigung. "Initial" wie in: "derjenige, der dich beunruhigt." –

Antwort

0

Danke an Mark Heintz in den Kommentaren, this answer brachte mich dahin, wo ich sein muss.

SELECT 
    data.id, 
    data.user_id, 
    data.obj_id, 
    data.created, 
    data.applied, 
    data.content 
FROM data 
LEFT JOIN data next_max_applied ON 
    next_max_applied.user_id = data.user_id AND 
    next_max_applied.obj_id = data.obj_id AND (
     next_max_applied.applied > data.applied OR (
      next_max_applied.applied = data.applied AND 
      next_max_applied.created > data.created 
     ) 
    ) 
WHERE next_max_applied.applied IS NULL 
GROUP BY user_id, obj_id; 

Lesen Sie die Antwort für Details, wie es funktioniert; Die left join versucht, eine jüngst angewendete Zeile für denselben Benutzer und dasselbe Objekt zu finden. Wenn es keinen gibt, wird eine Zeile gleichzeitig angewendet, aber neuer erstellt.

Das obige bedeutet, dass jede Zeile ohne eine neuere Zeile, die sie ersetzen soll, einen next_max_applied.applied-Wert von null hat. Diese Zeilen werden nach der IS NULL-Klausel gefiltert.

Schließlich behandelt die group by-Klausel alle Zeilen mit identischen Benutzer-, Objekt-, angewendeten und erstellten Spalten.

0
select * 
from my_table 
where id in (
    /* inner subquery b */ 
    select max(id) 
     from my_table where 
     (user_id, obj_id, applied, created) in (
      /* inner subquery A */ 
      select user_id, obj_id, max(applied), max(created) 
      from my_table 
      group by user_id, obj_id 
    ) 
); 

Dann innere Unterabfrage A die (distinct) Zeilen zurückgeben user_id, obj_id, max(applied), max(created) aufweist. Unter Verwendung dieser mit in-Klausel rekurriert die Unterabfrage B eine Liste von einzelnen IDs, wobei jede die Zeile mit einem geeigneten Wert von user_id, obj_id, max (angewandt), max (erzeugt) aufruft. Sie haben also eine Sammlung von gültigen ID für Ihr Ergebnis.

Die Hauptauswahl verwenden diese ID für die Auswahl des gewünschten Ergebnisses.

+0

Hinzugefügt Erklärung Hoffnung ist klar – scaisEdge