Struppi: order by and group by

Hallo alle

ich habe 2 Tabellen mittels LEFT JOIN hol ich mir die anzahl der einträge aus der 2. die mit einer ID aus der 1. übereinstimmen. Das klappt.

Jetzt würde ich aber gerne, um die DB Zugriffe zu senken auch noch informationen aus dem letzten Satz der 2. Tabelle in einem Aufwasch rausholen, mein versuch war so:

SELECT t.*, COUNT(m.m_id) as msg, m.user AS lastUser, m.date AS lastDate
FROM FORUM_msg m LEFT JOIN FORUM_thread t ON t.t_id = m.t_id
WHERE t.b_id='1'
GROUP BY m.t_id
ORDER BY m.t_id ASC, m.date DESC

Aber egal wie ich sortiere er wirft mir immer nur die Daten aus dem jeweils ersten Satz aus.

Ich vermute jetzt das geht nicht oder ich hab eine Möglichkeit übersehen.

Struppi.

  1. das resultset einer sql ist immer eine 2 dimensional tabelle.
    hier ist jede zeile gleich aufgebaut.

    du möchtest aber eine anzahl in dieser tabelle haben, und in einer weiteren zeile den letzten satz aus deiner tabelle.

    wie soll sql dir dieses ergebnis liefern???
    zeichne mal auf, wie diese tabelle aussehen soll. dann erledigt sich die frage.

  2. Hallo,

    so ganz habe ich zwar nicht verstanden, was Du mit "informationen aus dem letzten Satz der 2. Tabelle" meinst, aber:

    SELECT t.*, COUNT(m.m_id) as msg, m.user AS lastUser, m.date AS lastDate
    FROM FORUM_msg m LEFT JOIN FORUM_thread t ON t.t_id = m.t_id
    WHERE t.b_id='1'
    GROUP BY m.t_id
    ORDER BY m.t_id ASC, m.date DESC

    ^dieses Sortierkriterium kann niemals greifen.

    Du sortierst hauptsächlich nach m.t_id. Nur innerhalb von Datensätzen mit gleichen m.t_id würde nach m.date sortiert. Es kann aber keine gleichen m.t_id geben, weil Du diese ja mit GROUP BY m.t_id zusammenfasst.

    viele Grüße

    Axel

    1. yo,

      Es kann aber keine gleichen m.t_id geben, weil Du diese ja mit GROUP BY m.t_id zusammenfasst.

      letztlich liegt der fehler weniger in der sortierung, sondern das group by hinsichtlich der auszugebenen spalten nicht richtig formuliert wurde. alle spaltem ausser aggregat-funktionen, die angezeigt werden sollen, müssen in der group by klausel auch mit rein. der fehler wird leider immer häufiger gemacht, seit dem mysql die fehlermeldung bei solchen konstrukten unterbunden hat. ein schritt nach vorne, zwei zurück methode.

      Ilja

  3. ok. danke erstmal für die Antworten. Aber och kann nicht glauben, dass es keine Lösung gibt.

    Etwas genauer mein Problem ohne das Join, das kann ich anders lösen. Die Tablle sieht so aus:

    SELECT t_id, user, date FROM t WHERE b_id = 1 SORT BY t_id ASC, date DESC

    t_id  user   date
    1      a   2004-09-10
    1      b   2004-09-09
    1      c   2004-09-08
    2      c   2004-09-09
    2      b   2004-09-08
    2      c   2004-09-04
    3      d   2004-09-07
    3      a   2004-09-06

    Jetzt will ich im Prinzip nach t_id gruppieren

    SELECT t_id, user, date FROM t WHERE b_id = 1 GROUP BY t_id SORT BY t_id ASC, date DESC

    ergibt leider:

    t_id  user   date
    1      c   2004-09-08
    2      c   2004-09-04
    3      a   2004-09-06

    also immer den ältesten Eintrag, egal wie ich sortiere.

    Was ist mein Denkfehler, oder gibt es wirklich keine Lösung.

    Struppi.

    1. Etwas genauer mein Problem ohne das Join, das kann ich anders lösen. Die Tablle sieht so aus:

      wat willste denn jetze ?

      SELECT t_id, user, date FROM t WHERE b_id = 1 SORT BY t_id ASC, date DESC

      t_id  user   date
      1      a   2004-09-10
      1      b   2004-09-09
      1      c   2004-09-08
      2      c   2004-09-09
      2      b   2004-09-08
      2      c   2004-09-04
      3      d   2004-09-07
      3      a   2004-09-06

      Jetzt will ich im Prinzip nach t_id gruppieren

      SELECT t_id, user, date FROM t WHERE b_id = 1 GROUP BY t_id SORT BY t_id ASC, date DESC

      ergibt leider:

      t_id  user   date
      1      c   2004-09-08
      2      c   2004-09-04
      3      a   2004-09-06

      also immer den ältesten Eintrag, egal wie ich sortiere.

      was erwartest du denn ??

      1. Etwas genauer mein Problem ohne das Join, das kann ich anders lösen. Die Tablle sieht so aus:

        wat willste denn jetze ?

        Naja, beides.

        was erwartest du denn ??

        Ein Lösung ;-)

        aber ich habe verstanden, es gibt keine.

        danke an alle drei.

        Struppi.

    2. yo,

      also immer den ältesten Eintrag, egal wie ich sortiere.
      Was ist mein Denkfehler, oder gibt es wirklich keine Lösung.

      ich habe die problematik bereits weiter unten beschrieben. das problem ist das verständnis der klausel group by und was sie bewirkt. group by ist quasi eine sortierung nach einer oder mehreren spalten. --> alle <-- spalten, die nach dem SELECT kommen, sprich die du in der query angezeigt haben willst, müssen auch in der group by klausel mit angeben werden mit der ausnahme von aggregat funktion. das liegt daran, dass durch das group by immer nur ein eindeuter wert durch das dbms zugeordnet werden kann und aggregat-funktionen liefern immer genau einen wert. deshalb bekommst du auch immer nur einen wert als date.

      normalerweise geben andere dbms fehlermeldungen, wenn du eine spalte mit ausgeben willst, die nicht groupiert wurde. leider, leider wollten die entwickler von mysql bestimmte sortierungen sich ersparren, wenn zum beispiel die anderen spalten ebenfalls nur einen einzigen wert besitzen, sprich in deinem falle das date immer den gleichen wert hätte. das würde ein performance gewinn bedeuten, weil nur enmal sortiert würde. die fehlende fehlermeldung führt aber zu sehr grosser verwirrung, weil man eben auch spalten mit ausgibt, die mehrere werte haben. und genau dann wundert man sich, warum man nur einen wert bekommt.

      Ilja

    3. Hallo,

      SELECT t_id, user, date FROM t WHERE b_id = 1 SORT BY t_id ASC, date DESC

      t_id  user   date
      1      a   2004-09-10
      1      b   2004-09-09
      1      c   2004-09-08
      2      c   2004-09-09
      2      b   2004-09-08
      2      c   2004-09-04
      3      d   2004-09-07
      3      a   2004-09-06

      Jetzt will ich im Prinzip nach t_id gruppieren

      SELECT t_id, user, date FROM t WHERE b_id = 1 GROUP BY t_id SORT BY t_id ASC, date DESC

      ergibt leider:

      t_id  user   date
      1      c   2004-09-08
      2      c   2004-09-04
      3      a   2004-09-06

      also immer den ältesten Eintrag, egal wie ich sortiere.

      Nein, _irgendeinen_ Wert der 3 möglichen Werte für user und date bei t_id=1. Das dies zufällig der erste ist, ist nicht gesichert.

      Wie ich bereits schrieb kann das zweite Sortierkriterium keine Wirkung haben, weil nach der Gruppierung nach t_id jede t_id einmalig ist.

      Wie Ilja schrieb, müssen, bei einer Gruppierten Abfrage, alle Felder entweder zur Gruppierung beitragen oder in einer Aggregatfunktion stehen. Aggregatfunktionen sind SUM(), MIN(), MAX()... Andere DBMS bieten die Aggregatfunktionen FIRST() und LAST() an.

      SELECT t_id, FIRST(user), FIRST(date) FROM t WHERE b_id = 1 GROUP BY t_id ORDER BY t_id ASC

      MySQL umgeht das, und sagt, es gibt _irgendeinen_ Wert zurück, weil es keine Aggregatfunktion FIRST() und LAST() kennt. Wobei diese auch nicht sehr sicher funktionieren können. Wie soll schließlich der erste bzw. letzte Datensatz einer Datensatzgruppe definiert sein?

      SELECT t_id, MAX(date) as letztes_date FROM t WHERE b_id = 1 GROUP BY t_id ORDER BY t_id ASC

      könnte fnktionieren. Ich weiß allerdings nicht, ob MySQL den Felddatentyp DATE in MAX() bzw. MIN() verwenden kann.

      Für den user wirst Du allerdings mit einem Select keine Lösung finden.

      viele Grüße

      Axel