Vinzenz Mai: Lösung mit korrelierter Unterabfrage

Beitrag lesen

Hallo Martin,

Ich denke viele klicken das Thema gar nicht erst an, da es schon so oft vorkam.

die Lösung zu Deinem Problem ist es, sich von GROUP BY zu lösen.
Du suchst eine korrelierte Unterabfrage. Schauen wir es uns an Deinem Beispiel an:

Tabelle stream:

stream_id   user_id     type_id     linux_timestamp
----------- ----------- ----------- ---------------
1           230         2           1268615468
2           180         2           1268615483
3           230         1           1268615504
4           230         3           1268615555
5           320         1           1268615567

Tabelle benutzer

user_id     nickname   vorname    vornameview
----------- ---------- ---------- -----------
180         martin     Martin     1
230         theo       Theodor    1
320         jonas      Jonas      1

Tabelle type (mit leicht modifizierten Inhalten)

type_id     type_text  icon
----------- ---------- ----------
1           Text 1     Icon 1
2           Text 2     Icon 2
3           Text 3     Icon 3

Du suchst zunächst die zwei neuesten Einträge in stream unter der Randbedingung, dass sie von unterschiedlichen Benutzern stammen. Die user_id und den zugehörigen linux_timestamp könntest Du zwar über GROUP BY mit Hilfe der Aggregatsfunktion MAX() bestimmen, nicht jedoch den zugehörigen Eintrag in der Spalte type_id. Dazu benötigst Du - wie bereits erwähnt - eine korrelierte Unterabfrage:

Wir beschaffen uns im ersten Schritt die neuesten Einträge *aller* Benutzer und sortieren die Ergebnismenge absteigend nach dem Eintragszeitpunkt, um die neuesten als erste zu erhalten:

SELECT                            -- Gib mir die Inhalte der Spalten  
    s1.stream_id,                 -- stream_id  
    s1.user_id,                   -- user_id  
    s1.type_id,                   -- type_id  
    s1.linux_timestamp,           -- und Timestamp  
FROM                              -- aus  
    stream s1                     -- der Tabelle stream, die unter dem  
                                  -- Namen s1 angesprochen wird.  
                                  -- Der Aliasname ist notwendig, weil wir  
                                  -- im Subselect auf die gleiche Tabelle  
                                  -- zugreifen, um äußeren von innerem Zugriff  
                                  -- unterscheiden zu können  
WHERE                             -- wobei uns nur die Datensätze interessieren,  
    s1.linux_timestamp = (        -- deren Timestamp mit  
    SELECT                        -- dem  
        MAX(s2.linux_timestamp)   -- maximalen Timestamp  
    FROM                          -- aus der Tabellle  
        stream s2                 -- stream, hier zur Unterscheidung über  
                                  -- den Alias s2 angesprochen,  
                                  -- übereinstimmt  
    WHERE                         -- wobei nur die Datensätze interessieren,  
        s1.user_id = s2.user_id   -- bei denen die user_id innen und außen  
                                  -- gleich ist.  
                                  -- Das ist die Korrelation des Subselects  
                                  -- mit der äußeren Abfrage.  
)  
ORDER BY                          -- Ergebnisse bitte  
    s1.linux_timestamp DESC       -- nach Timestamp-Spalte absteigend sortiert  

Ergebnis:

stream_id   user_id     type_id     linux_timestamp
----------- ----------- ----------- ---------------
5           320         1           1268615567
4           230         3           1268615555
2           180         2           1268615483

Im zweiten Schritt besorgen wir uns über entsprechende Joins die Daten aus den anderen Tabellen und limitieren die Ergebnismenge auf zwei Datensätze:

SELECT  
    s1.stream_id,  
    s1.user_id,  
    s1.type_id,  
    s1.linux_timestamp,  
    b.nickname,  
    b.vorname,  
    b.vornameview,  
    t.type_text,  
    t.icon  
FROM  
    stream s1  
INNER JOIN                           -- ganz normale INNER JOINs  
    benutzer b  
ON  
    s1.user_id = b.user_id  
INNER JOIN  
    `type` t                         --  
ON  
    s1.type_id = t.type_id  
WHERE  
    s1.linux_timestamp = (  
    SELECT  
        MAX(s2.linux_timestamp)  
    FROM  
        stream s2  
    WHERE  
        s1.user_id = s2.user_id  
)  
ORDER BY  
    s1.linux_timestamp DESC  
LIMIT 2                              -- limitiere die Ergebnismenge

Ergebnis (wie gewünscht):

stream_id   user_id     type_id     linux_timestamp nickname   vorname    vornameview type_text  icon
----------- ----------- ----------- --------------- ---------- ---------- ----------- ---------- ----------
5           320         1           1268615567      jonas      Jonas      1           Text 1     Icon 1
4           230         3           1268615555      theo       Theodor    1           Text 3     Icon 3

Freundliche Grüße

Vinzenz