GROUP BY - Ich verzweifel

Matthi

Benutzer
Beiträge
20
Hallo liebe Mitglieder,

meine erste Frage hier in diesem Forum und eigentlich konnte ich sowas bislang immer umgehen. Ich verzweifel allerdings gerade an einer, scheinbar, simplen Abfrage. Ich bin mir sicher, ihr könnt mir direkt helfen.

Folgendes Szenario:

Tabelle logdaten

changed_id, INT 5, Primary Key, Auto Increment
user_id, INT 5
status_id, INT 5
changed_timestamp, VARCHAR 255
comment, VARCHAR 255
insert_from, INT 5

In diese Tabelle werden Statusänderungen geschrieben. Die status_changed_id ist AI und der PK. Die user_id ist der entsprechende Benutzer (bzw. Benutzer ID) und der changed_timestamp ein UNIX Timestamp der protokolliert, wann der neue Eintrag geschrieben wurde.

Inhalt:

changed_id | user_id | status_id | changed_timestamp
1 , 20 , 4 , 1498025053
2 , 21 , 4 , 1498025083
3 , 21 , 3 , 1498027025
4 , 21 , 4 , 1498030348
5 , 21 , 3 , 1498030407
6 , 21 , 1 , 1498030556

Ich möchte jetzt gerne zu jedem Benutzer (user_id) die LETZTE (anhand des timestamps) vorkommende Zeile selektieren.

SELECT user_id,status_id FROM logdaten GROUP BY user_id

führt zu einem

user_id | status_id
20, 4
21 , 4

Ich habe schon SUB Selects probiert, verschiedene Group Kriterien und alles was mir so eingefallen ist aber im Endeffekt lieferte mir keiner das gewünschte Ergebnis. In diesem Fall bräuchte ich:

user_id | status_id
20 , 4
21, 1

Und obwohl ich 2 Spalten habe, die mir entsprechend weiterhelfen können (der timestamp und der PK) steh ich gerade voll auf dem Schlauch.

Für Hilfe wäre ich sehr dankbar!

Grüße
 
Werbung:
Danke dir für die Antwort. Das Ergebnis wäre dann:

user_id |change_timestamp
20 , 1498025053
21 , 1498030556

und wenn ich im select noch die status_id mit Abfrage, bekomme ich leider immernoch:

status_id |user_id |change_timestamp
4 , 20 , 1498025053
4 , 21 , 1498030556
 
ja was willst denn nun haben? Wäre dies hier richtig?

Code:
test=# select * from matthi ;
 c_id | u_id | s_id |  ts   
------+------+------+------------
  1 |  20 |  4 | 1498025053
  2 |  21 |  4 | 1498025083
  3 |  21 |  3 | 1498027025
  4 |  21 |  4 | 1498030348
  5 |  21 |  3 | 1498030407
  6 |  21 |  1 | 1498030556
(6 rows)

test=# select distinct on (u_id) s_id, u_id, ts from matthi order by u_id, ts desc;
 s_id | u_id |  ts   
------+------+------------
  4 |  20 | 1498025053
  1 |  21 | 1498030556
(2 rows)

test=#
 
MySQL - "distinct on()" funktioniert bei mir zumindest nicht.

Zitat von meinem Beitrag:
"Ich möchte jetzt gerne zu jedem Benutzer (user_id) die LETZTE (anhand des timestamps) vorkommende Zeile selektieren."

Nach obigem Beispiel wären das
1 , 20 , 4 , 1498025053
6 , 21 , 1 , 1498030556

und da wäre ein Ergebnis mit zweimal status_id = 4 falsch.

Grüße
 
Korrekt. In dem Falle kann man MySQL nicht mal schlecht reden, weil das ein Non-Standard-Feature ist. Nehme die andere Version, die ich schon nannte, und joine das Ergebnis zur Ausgangstabelle.
 
Ein bisschen abgewandelt mit nem right join und einem max auf die changed_id in der werte Menge des joins hat dann endlich zum Erfolg geführt.

Danke für die Denkanstöße!

Grüße
 
Schau dir bitte das einmal an ob das Ergebnis so ist wie du das haben möchtest.

Code:
SELECT h.*
FROM (
        SELECT max(changed_id) AS changed_id
        FROM logdaten
        GROUP BY user_id
    )  l
LEFT JOIN logdaten h
    ON h.changed_id = l.changed_id
ORDER BY
    h.user_id;


Beispiel:
Code:
mysql> SELECT * FROM logdaten;
+------------+---------+-----------+-------------------+---------+-------------+
| changed_id | user_id | status_id | changed_timestamp | comment | insert_from |
+------------+---------+-----------+-------------------+---------+-------------+
|          1 |      20 |         4 | 1498025053        | NULL    |        NULL |
|          2 |      21 |         4 | 1498025083        | NULL    |        NULL |
|          3 |      21 |         3 | 1498027025        | NULL    |        NULL |
|          4 |      21 |         4 | 1498030348        | NULL    |        NULL |
|          5 |      21 |         3 | 1498030407        | NULL    |        NULL |
|          6 |      21 |         1 | 1498030556        | NULL    |        NULL |
+------------+---------+-----------+-------------------+---------+-------------+
6 rows in set (0,00 sec)

mysql>
mysql>
mysql> SELECT h.*
    -> FROM (
    ->         SELECT max(changed_id) AS changed_id
    ->         FROM logdaten
    ->         GROUP BY user_id
    ->     )  l
    -> LEFT JOIN logdaten h
    ->     ON h.changed_id = l.changed_id
    -> ORDER BY
    ->     h.user_id;
+------------+---------+-----------+-------------------+---------+-------------+
| changed_id | user_id | status_id | changed_timestamp | comment | insert_from |
+------------+---------+-----------+-------------------+---------+-------------+
|          1 |      20 |         4 | 1498025053        | NULL    |        NULL |
|          6 |      21 |         1 | 1498030556        | NULL    |        NULL |
+------------+---------+-----------+-------------------+---------+-------------+
2 rows in set (0,00 sec)

mysql>
 
Werbung:
Ich danke dir BernB!

Gelöst hatte ich das, wie geschrieben, allerdings schon mit diesem Statement:


SELECT * FROM logdaten
RIGHT JOIN (
SELECT MAX(changed_id) AS max_id
FROM logdaten GROUP BY user_id )
AS rel_ids ON rel_ids.max_id = logdaten.changed_id


Aber es gibt ja immer ein paar Wege die zum Ziel führen :) Danke für deine Bemühungen und deine Hilfe

Grüße
 
Zurück
Oben