Andreas Schigold: (MySQL) richtige Anweisung gesucht

Hallo liebe Forummer,

ich habe da mal ein Anliegen. Bei meinem Spiel unter http://schigold.de/ habe ich ja eine Highscoreliste eingebaut. Nun tragen sich ja viele ein und auch viele mehrfach. Ist auch so gewollt. Damit jemand mit weniger Punkten sich jetzt nicht so weit unten suchen muß, habe ich eine zweite Tabelle mit dem "besten Ergebnis" eines Jeden hingesetzt.

Da ist aber ein Fehler drin:

Nimmt man zum Beispiel den 1. Platz von "Stuvar", dann sieht man links richtig stehen:

1.   84    6.6    Stuvar

in der rechten Tabelle aber steht nun quasi der erste Eintrag von Stuvar mit seinem höchsten Ergebnis gekoppelt, das ist aber falsch.

sein erster Eintrag war (13  4.2 Stuvar) plus sein bestes Ergebnis (84  6.6 Stuvar) ergibt die falsche Anzeige von (84 4.2 Stuvar)

für die linke Tabelle ist die SELECT einfach:
select laenge, schnitt, name from highscore order by laenge desc;

für die rechte Tabelle ist die SELECT momentan:
select max(laenge) as lang, schnitt, name from highscore group by name order by lang desc;
Aber wie müßte sie richtig heißen, damit eben 84  6.6 Stuvar angezeigt wird?
Bin für jeden Beitrag dankbar, und seien es nur tröstende Worte daß es nicht geht oder der Vorschlag auf Oracle umzusteigen. Die richtige SQL-Anfrage wäre mir natürlich lieber ;-)

Gruß,
Andreas

PS: ich hoffe, daß mein Spiel keinen zu sehr von der Arbeit abhält *g*

  1. ehrlcih gesagt, finde ich da nirgends ein spiel auf deiner Page, oder war das ein lustiger trick um traffic auf deine Page zu bekommen :o). Posta mal, wo dein spiel ist, dann kann ich es vielleicht besser nachvollziehen

    -----------------------------
    http://www.script-fabrik.de
    jetzt neu mit Quiz

    1. Hi Script-fabrik,

      sorry, war ein Fehler aus der Gewohnheit. Die angegebene Seite ist ja meine HP. Das Spiel ist nicht durchgelinkt und liegt unter

      http://schigold.de/spiel/

      Aber ich war natürlich in der Zwischenzeit nicht untätig und habe nach langem verzweifelten Suchen einen ganz versteckten Link auf mysql.com gefunden:

      http://www.mysql.com/doc/e/x/example-Maximum-column-group-row.html
      Dort ist halt eine etwas umständliche Lösung angegeben, aber geht wohl in MySQL nicht besser. Schade, das wär nämlich ein echtes Argument für subselects, denn eine temporary table kann doch nicht das Gelbe vom Ei sein.

      Problem war, daß zwar die höchste Länge eines jeden Spielers ausgegeben wurde und auch der richtige Name, aber die "durchschnittliche Längenzunahme je 10 sec" war eben nicht die passend zur größten Länge, sondern die passend zum (zeitlich) ersten Eintrag.

      Naja, auf der MySQL-Seite ist ja die Sub-Select angegeben, die das Ziel sein soll.

      Trotzdem danke für's gucken auf meiner Hauptseite, ich hoffe, ich kann Euch mit meinem kleinen Spiel ein wenig dafür entschädigen. (Diesmal habe ich die Links vorm Absenden nochmal angeschaut, sollte jetzt hinhauen)

      Gruß
      Andreas

  2. Hi Andreas,

    select max(laenge) as lang, schnitt, name from highscore
    group by name order by lang desc;

    ich habe Dein DB-Schema nicht ganz verstanden.
    Aber Dein Problem klingt so, als würdest Du auch auf der rechten Seite
    _einen_ Datensatz aus Deiner Tabelle holen wollen.
    Das tust Du aber nicht - Du mischst gespeicherte und berechnete Werte
    (weil Du "max" verwendest).

    Was Du tatsächlich willst, ist,

    • zuerst die Datensätze nach Spielern zu gruppieren,
    • davon aber jeweils nur den einen Datensatz mit dem höchsten Wert zu
        nehmen (DISTINCT, ORDER BY, LIMIT 1?), und
    • das Ergebnis dieser Auswahl dann wiederum nach dem Wert zu sortieren.

    Ich weiß im Moment nicht, ob diese doppelte Sortierung mit einem einzigen
    SELECT geht; es kann sein, daß dafür ein SubSelect erforderlich wäre, was
    mySQL nicht direkt unterstützt.
    In diesem Fall könntest Du aber den ersten SELECT in eine temporäre Tabelle
    lenken und aus dieser mit dem zweiten die endgültige Sortierung heraus-
    fischen.

    Viele Grüße
          Michael

    1. Hi Andreas,

      select max(laenge) as lang, schnitt, name from highscore
      group by name order by lang desc;

      ich habe Dein DB-Schema nicht ganz verstanden.
      Aber Dein Problem klingt so, als würdest Du auch auf der rechten Seite
      _einen_ Datensatz aus Deiner Tabelle holen wollen.
      Das tust Du aber nicht - Du mischst gespeicherte und berechnete Werte
      (weil Du "max" verwendest).

      Was Du tatsächlich willst, ist,

      • zuerst die Datensätze nach Spielern zu gruppieren,
      • davon aber jeweils nur den einen Datensatz mit dem höchsten Wert zu
          nehmen (DISTINCT, ORDER BY, LIMIT 1?), und
      • das Ergebnis dieser Auswahl dann wiederum nach dem Wert zu sortieren.

      Ich weiß im Moment nicht, ob diese doppelte Sortierung mit einem einzigen
      SELECT geht; es kann sein, daß dafür ein SubSelect erforderlich wäre, was
      mySQL nicht direkt unterstützt.
      In diesem Fall könntest Du aber den ersten SELECT in eine temporäre Tabelle
      lenken und aus dieser mit dem zweiten die endgültige Sortierung heraus-
      fischen.

      So isses, habe nach langem verzweifelten Suchen bei mysql.com folgende Seite gefunden, die genau mein Ziel nochmal in einem Subselect zeigt und die MySQL-Lösung vorstellt, finde ich aber ziemlich umständlich im Gegensatz zum Subselect:

      http://www.mysql.com/doc/e/x/example-Maximum-column-group-row.html

      Trotzdem vielen Dank

      Viele Grüße
            Michael

      Jo, auch von mir; Falls Du zum Ausgleich für Deine Bemühungen ein bisschen spielen willst: das Spiel liegt nicht (wie fälschlicherweise angegeben) unter schigold.de, sondern unter http://schigold.de/spiel/.

      1. Hi Andreas,

        finde ich aber ziemlich umständlich im Gegensatz zum Subselect:

        das Beispiel wird m. E. deshalb so umständlich, weil es gleichzeitig
        eine potentielle Transaktion am Leben halten will. Und das ist bei zwei
        Statements nun mal nicht dasselbe wie bei nur einem im AutoCommit-Modus.

        Im Prinzip siehst Du bei mySQL ja nur, wie jede Datenbank ein Subselect
        intern realisieren muß - hier mußt Du es halt explizit hinschreiben.
        (Potentiell könnte man SubSelects beliebig tief schachteln, und das
        stellt dann so hohe Anforderungen an eine effiziente Verwaltung der
        Ressourcen, daß sich mySQL dieser Herausforderung bisher anscheinend
        nicht stellen möchte.)

        Wenn Du nur lesend auf Deine Tabelle zugreifen willst und keine hohe
        Prirität darauf legst, daß Dein Skript niemals inkonsistente Daten
        im Falle gleichzeitiger Zugriffe anzeigt, könntest Du das LOCK und
        das UNLOCK weglassen. Und auch das DROP brauchst Du bei einer tempo-
        rären Tabelle nicht, wenn Du mal eben einen CGI-Zugriff machst - die
        existiert nur während Deiner Datenbankverbindung.
        Wäre Dein Programm als daemon dauerhaft mit der Datenbank verbinden,
        dann wäre das sofortige, aktive Aufräumen der Tabelle wichtiger.

        Das Beispiel zeigt Dir die "volle Dröhnung" unter Berücksichtigung
        aller Eventualitäten. In Deinem Falle geht es wohl auch "billiger".

        Viele Grüße
              Michael