Herbert R.: GROUP BY Problem mit Anzeige des letzten Datensatzes

Hallo,

ich habe folgendes Problem, bei dem ich hoffe, dass ihr mir helfen könnt.

In einer Abfrage möchte ich Datensätze, die unmittelbar hintereinander folgen und in verschiedenen Feldern (userid, eventid, value1-3) identisch sind, gruppieren. In dem angezeigten Datensatz, soll er mir aber immer den Wert aus dem letzten Eintrag anzeigen (lt. dateline den akutellsten Datensatz)

Ich habe nun folgende Query, die soweit auch funktioniert, mir jedoch bei den Feldern value1, value2 und value3 nicht den Inhalt des letzten, sondern eines anderen Datensatzes aus den Dubletten ausgibt. Das Datum des letzten erhalte ich ja über MAX. Ich habe mysql 4.

SELECT userid, eventid, dateline, MAX(dateline) AS datelinemax, val1, val2, val3
FROM db
GROUP BY userid, eventid
ORDER BY datelinemax DESC

Der Hintergrund ist, dass ich für die gleichen Events des selben Users nur eine Ausgabe brauche und zwar die des letzten. Die Ausgabe soll chronologisch absteigend erfolgen.

Ich hoffe, ich hab es verständlich formuliert.

Danke im voraus.

  1. Hello,

    nimm es nicht persönlich, aber MySQL taugt GAR NICHTS um Gruppierungen zu üben, das System ist gemessen am SQL-Standard einfach nur defekt.

    SELECT userid, eventid, dateline, MAX(dateline) AS datelinemax, val1, val2, val3
    FROM db
    GROUP BY userid, eventid
    ORDER BY datelinemax DESC

    Wenn du nach userid, eventid gruppierst, dann müssen ALLE ANDEREN Spalten in der Select Klausel mit Aggregatsfunktionen belegt sein, ist bei dir aber im Fal von dateline, val1, val2, val3 nicht der Fall. Korrigiere dein Statement, indem du das entweder änderst (wird wohl nicht den gewünschten Effekt haben), oder die entsprechenden Spalten in die Gruppierung aufnimmst (das müsste deinem Ergebnis nahe kommen).
    Warum selektierst du eigentlich nochmals dateline ohne Gruppierung?

    MfG
    Rouven

    --
    -------------------
    sh:| fo:} ch:? rl:( br:& n4:{ ie:| mo:} va:) js:| de:] zu:| fl:( ss:) ls:& (SelfCode)
    Because good guys need a break every once in a while.  --  Morty in "Click" (Columbia Pictures, 2006)
    1. Hallo Rouven,

      nimm es nicht persönlich, aber MySQL taugt GAR NICHTS um Gruppierungen zu üben, das System ist gemessen am SQL-Standard einfach nur defekt.

      immer wieder lese ich es das MySQL so "schlecht" sein soll oder zumindest den SQL Standard schlecht umsetzen soll und viele Besonderheiten hat.

      Welches SQL DB System macht das denn deiner Meinung nach dann gut?

      Würde mich nur mal so interessieren.

      vielen Dank und viele Grüße
      hawk

      1. Hallo,

        nimm es nicht persönlich, aber MySQL taugt GAR NICHTS um Gruppierungen zu üben, das System ist gemessen am SQL-Standard einfach nur defekt.

        immer wieder lese ich es das MySQL so "schlecht" sein soll oder zumindest den SQL Standard schlecht umsetzen soll und viele Besonderheiten hat.

        Rouven bezieht sich hier auf eine spezielle Eigenheit von MySQL. Das kaputte "it's not a bug, it's a feature"-Verhalten von MySQL bei GROUP BY und der Verwendung nicht aggregierter Spalten, nach denen nicht gruppiert wird.

        MySQL 5.0.12 und neuer sollte man grundsätzlich schon verwenden, vorher fehlen wichtige Sachen und erst ab MySQL 5.0.12 werden Joins richtig umgesetzt. Vorher können bei bestimmten Joins definierbar falsche Ergebnisse herauskommen :-(

        Welches SQL DB System macht das denn deiner Meinung nach dann gut?

        Nahezu jedem DBMS fehlt etwas Nettes, was ein anderes DBMS bietet ...

        Freundliche Grüße

        Vinzenz

      2. Hello,

        Welches SQL DB System macht das denn deiner Meinung nach dann gut?

        die meisten DBMS machen irgendetwas MEHR als der Standard, damit der Hersteller sich mit einem Wettbewerbsvorteil rühmen kann. Gleichzeitig ist die Umsetzung des Standards zeitaufwändig, d.h. es dürfte gemeinhin normal sein, dass ein oder zwei Versionen vergehen, eh der Standard vollständig umgesetzt ist.
        Vermutlich am nächsten dran dürften die ganz großen sein, also Oracle oder IBM DB2.
        Auf Anhieb findet sich hier mal eine kurze Liste. Eine Direktübersicht Hersteller-Version-SQL-Compliance finde ich leider af Anhieb nicht.

        MfG
        Rouven

        --
        -------------------
        sh:| fo:} ch:? rl:( br:& n4:{ ie:| mo:} va:) js:| de:] zu:| fl:( ss:) ls:& (SelfCode)
        Ambition is the last refuge of failure.  --  Oscar Wilde (Irish Poet, Novelist, Dramatist and Critic, 1854-1900)
  2. Hi,

    Ich habe nun folgende Query, die soweit auch funktioniert,

    in einem anderen DBMS als MySQL würde sie es nicht tun. Das DBMS würde es als fehlerhaft ablehnen.

    SELECT userid, eventid, dateline, MAX(dateline) AS datelinemax, val1, val2, val3
    [...]
    GROUP BY userid, eventid

    Gruppiere immer nach *allen* Werten, die nicht aus einer Gruppenfunktion berechnet werden. Denn nur Gruppenfunktionen können auf eine Gruppe angewendet werden. Welches val1 soll denn aus den hundertsiebenundzwanzigtausenddreihundertsechsundneunzig Datensätzen gewählt werden, die in der Gruppe einer userid und eventid bestehen?

    Du benötigst "GROUP BY userid, eventid, dateline, val1, val2, val3" - oder eine Änderung der SELECT-Klausel.

    Der Hintergrund ist, dass ich für die gleichen Events des selben Users nur eine Ausgabe brauche und zwar die des letzten.

    Definiere "letzter" in einer unsortierten Menge.

    Die Ausgabe soll chronologisch absteigend erfolgen.

    Nachdem Du die benötigten Datensätze selektiert hast, ist dieser Punkt trivial und, soweit ich es sehen kann, von Dir bereits gelöst.

    Ich hoffe, ich hab es verständlich formuliert.

    Nicht so, dass es eine Datenbank verstehen würde. Versuche es noch mal präziser.

    Cheatah

    --
    X-Self-Code: sh:( fo:} ch:~ rl:| br:> n4:& ie:% mo:) va:) de:] zu:) fl:{ ss:) ls:~ js:|
    X-Self-Code-Url: http://emmanuel.dammerer.at/selfcode.html
    X-Will-Answer-Email: No
    X-Please-Search-Archive-First: Absolutely Yes
    1. Ok, ihr habt recht. Eigentlich brauche ich nur val1-3 in die GROUP BY mit aufnehmen. Das Problem ist nur, dass ich dateline nicht mit aufnehme, denn dateline ist ein Timestamp und hier soll eben immer nur die letzte Aktivität angezeigt werden (deshalb der zusätzliche MAX).

      D.h. ich habe jetzt folgende Query ausprobiert. Auf den ersten Blick funtioniert sie (hoffe ich).

      SELECT userid, eventid, dateline, MAX(dateline) AS datelinemax, val1, val2, val3
      FROM db
      GROUP BY userid, eventid, val1, val2, val3
      ORDER BY datelinemax DESC

      D.h. bei gleichen Aktivitäten eines Users (userid, eventid und val1-3 müssen übereinstimme) soll in der Liste immer nur ein Datensatz mit dem Timestamp (dateline) des letzten angezeigt werden.

      Macht das obige "Ding" nach Eurer Meinung jetzt was ich möchte?

      Danke im voraus.

      1. Hallo,

        D.h. ich habe jetzt folgende Query ausprobiert. Auf den ersten Blick funtioniert sie (hoffe ich).

        nein, sie funktioniert natürlich nicht.

        SELECT userid, eventid, dateline, MAX(dateline) AS datelinemax, val1, val2, val3

        -- Wirf die Spalte dateline heraus. Deren Wert ist *zufällig*
        -- das kann durch Zufall der neueste sein, das kann der älteste sein,
        -- das kann irgend ein beliebiger sein.
        --
        -- Du hast den von Dir gewünschten Wert in der Ergebnisspalte datelinemax stehen
        -- Das ist korrekt und reicht aus.

        FROM db
        GROUP BY userid, eventid, val1, val2, val3
        ORDER BY datelinemax DESC

        Macht das obige "Ding" nach Eurer Meinung jetzt was ich möchte?

        Nein. In jedem anderen DBMS außer MySQL wirft es eine Fehlermeldung. Zu Recht!

        Freundliche Grüße

        Vinzenz

      2. Hi,

        Ok, ihr habt recht. Eigentlich brauche ich nur val1-3 in die GROUP BY mit aufnehmen. Das Problem ist nur, dass ich dateline nicht mit aufnehme, denn dateline ist ein Timestamp und hier soll eben immer nur die letzte Aktivität angezeigt werden (deshalb der zusätzliche MAX).

        oder die letzten 17, wenn diese den selben Timestamp besitzen. Dies beachtest Du nicht.

        D.h. ich habe jetzt folgende Query ausprobiert. Auf den ersten Blick funtioniert sie (hoffe ich).

        Sie besitzt immer noch den Fehler, dateline zu selektieren, ohne danach zu gruppieren.

        D.h. bei gleichen Aktivitäten eines Users (userid, eventid und val1-3 müssen übereinstimme) soll in der Liste immer nur ein Datensatz mit dem Timestamp (dateline) des letzten angezeigt werden.

        Das passiert nicht. Statt dessen werden die Datensätze mit dem letzten (also neuesten) Timestamp in dateline angezeigt. Ja, das ist ein Unterschied.

        Macht das obige "Ding" nach Eurer Meinung jetzt was ich möchte?

        Jede einzigartige Kombination aus userid, eventid, val1, val2 und val3 wird selektiert und es wird der größte Timestamp aus dieser Gruppe ermittelt.

        GROUP BY ist nicht dazu geeignet, den neuesten (ältesten, größten, schönsten, dicksten) *Datensatz* zu ermitteln, sondern nur den neuesten (ältesten, ...) *Wert* aus einer Gruppe Datensätzen, die gewisse gleichartige Eigenschaften besitzen. Du weißt weder, welcher Datensatz dazu gehört, noch wie viele es sind. Dies musst Du in einem späteren (äußeren) SELECT ermitteln. Der Umstand, dass hierbei auch mehr als ein Ergebnis rauspurzeln kann, zeigt:

        Deine Definition von "letzter Datensatz" ist mangelhaft.

        Cheatah

        --
        X-Self-Code: sh:( fo:} ch:~ rl:| br:> n4:& ie:% mo:) va:) de:] zu:) fl:{ ss:) ls:~ js:|
        X-Self-Code-Url: http://emmanuel.dammerer.at/selfcode.html
        X-Will-Answer-Email: No
        X-Please-Search-Archive-First: Absolutely Yes