Rang mit MySQL bei einzelauslese unter Verwendung von Order definieren

Marius Heil hat gesagt.:
Tut mir Leid, dass ich so viele Fragen stell, bin am überelgen, ob ich per Cronjob die Liste einmal täglich ordnen soll, dann müsst ich dich nciht mit den Fragen belästigen^^
Dann frag' lieber.
Aber führe Deine Fragen etwas mehr aus, ggf. mit Beispielen (kurzer Auszug an Beispieldaten, gewünschte Ergebnistabelle).
Wenn Du nach anderen Kriterien auswählen willst, musst Du die WHERE-Klausel entsprechend anpassen. Wenn Du nach anderen Kriterien sortieren willst, musst Du den Teil vom ORDER BY anpassen.

Gruß hpvw

Lit.:
http://v.hdm-stuttgart.de/~riekert/lehre/db-kelz/index.htm
http://dev.mysql.com/doc/mysql/de/select.html
http://www.little-idiot.de/mysql/
 
Hi,

tut mir leid, dass ich so lange nicht geantwortet hab, ich hatte in letzter zeit aber mordsmäßig viel mit Schule zu tun....
Ich kan gar nicht dazu irgendwas zu machen.
Die Querys hab ich jetzt einigermaßen verstanden, zumindest das, das alle Benutzer der Reihe nach durchgeht, das, das einen einzelnen User auswählt hab ich fast verstanden.
Was müsste ich denn machen, wenn ich zu einem Rang springen will?
Sprich in der Highscoreliste gibt der user zb Rang 77 ein, dann sucht MySQL nach Rang 77 und gibt von Rang 70 bis 84 aus.


Marius
---
Ach ja, ich hab dir meine Tabellen mal angehängt:
CREATE TABLE `user` (
`Email` VARCHAR( 40 ) NOT NULL ,
`Username` VARCHAR( 17 ) NOT NULL ,
`Pwd` VARCHAR( 32 ) NOT NULL ,
`Geschlecht` TINYINT( 1 ) DEFAULT '0' NOT NULL ,
`Ort` VARCHAR( 30 ) NOT NULL ,
`Herausforderbar` TINYINT( 1 ) DEFAULT '1' NOT NULL ,
`EmailAnzeige` TINYINT( 1 ) DEFAULT '1' NOT NULL ,
`Icq` VARCHAR( 15 ) NOT NULL ,
`IcqAnzeige` TINYINT( 1 ) DEFAULT '1' NOT NULL ,
`Msn` VARCHAR( 40 ) NOT NULL ,
`MsnAnzeige` TINYINT( 1 ) DEFAULT '1' NOT NULL ,
`Punkte` MEDIUMINT UNSIGNED DEFAULT '0' NOT NULL ,
`Geld` MEDIUMINT UNSIGNED DEFAULT '0' NOT NULL ,
`SkillO` TINYINT UNSIGNED DEFAULT '3' NOT NULL ,
`SkillM` TINYINT UNSIGNED DEFAULT '3' NOT NULL ,
`SkillU` TINYINT UNSIGNED DEFAULT '3' NOT NULL ,
`Gewonnen` MEDIUMINT UNSIGNED DEFAULT '0' NOT NULL ,
`Verloren` MEDIUMINT UNSIGNED DEFAULT '0' NOT NULL ,
`GeworbeneUser` SMALLINT UNSIGNED DEFAULT '0' NOT NULL ,
`Anmeldedatum` DATE NOT NULL ,
`LastOnTime` DATE NOT NULL ,
`Premium` TINYINT( 1 ) DEFAULT '0' NOT NULL ,
PRIMARY KEY ( `Email` )
UNIQUE KEY `Username` (`Username`)

);
CREATE TABLE `kaempfe` (
`KampfID` MEDIUMINT( 7 ) UNSIGNED NOT NULL AUTO_INCREMENT ,
`EmailU` VARCHAR( 40 ) NOT NULL ,
`EmailG` VARCHAR( 40 ) NOT NULL ,
`Kampfdaten` VARCHAR( 14 ) NOT NULL ,
`KampfdatenG` VARCHAR( 14 ) NOT NULL ,
`FigImageWahl` VARCHAR( 3 ) NOT NULL ,
`Einsatz` SMALLINT UNSIGNED NOT NULL ,
`Kampfdatum` DATE NOT NULL ,
PRIMARY KEY ( `KampfID` )
);
CREATE TABLE `buddys` (
`BuddyID` MEDIUMINT UNSIGNED NOT NULL AUTO_INCREMENT ,
`Email` VARCHAR( 40 ) NOT NULL ,
`EmailG` VARCHAR( 40 ) NOT NULL ,
PRIMARY KEY ( `BuddyID` )
);
CREATE TABLE `anwaerter` (
`Username` VARCHAR( 17 ) NOT NULL ,
`Pwd` VARCHAR( 32 ) NOT NULL ,
`Email` VARCHAR( 40 ) NOT NULL ,
`Zufallsnummer` VARCHAR( 10 ) NOT NULL ,
`Anfragedatum` DATE NOT NULL ,
`Validierung` VARCHAR( 5 ) NOT NULL ,
PRIMARY KEY ( `Username` )
);
Das ist zurzeit glabu cih alles, aber nur zurzeit, das wird immer merh^^ schrecklich.
 
Das Query für einen User ist genau das gleiche, wie das für alle User. Es wird lediglich in der WHERE-Klausel mit der Bedingung auf den einzelnen User reduziert.
Das Reduzieren auf bestimmte Ränge ist ebenfalls ein Fall für die WHERE-Klausel. Da MySQL keine Aliasfelder in der WHERE-Klausel zulässt (Vereinfachung der internen Query-Optimierung) muss das Subquery dort erneut angegeben werden:
Code:
SELECT 
t1.`id`, 
t1.`name`, 
t1.`punkte`, 
t1.`geld`,
(SELECT 
  (COUNT(*)+1)
  FROM userrang AS t2
    WHERE t2.`Punkte`>t1.`punkte`
    OR (
      t2.`Punkte`=t1.`punkte`
      AND t2.`geld`>t1.`geld`
  )
) AS `Rang`
FROM userrang AS t1
WHERE (SELECT 
      (COUNT(*)+1)
      FROM userrang AS t3
        WHERE t3.`Punkte`>t1.`punkte`
        OR (
          t3.`Punkte`=t1.`punkte`
          AND t3.`geld`>t1.`geld`
      )
    ) = 77 # <-- der gesuchte Rang
ORDER BY `Rang`
Für eine gewisse Spanne von Rängen benötigt man logischerweise zwei mit AND verknüpfte Vergleiche:
Code:
SELECT 
t1.`id`, 
t1.`name`, 
t1.`punkte`, 
t1.`geld`,
(SELECT 
  (COUNT(*)+1)
  FROM userrang AS t2
    WHERE t2.`Punkte`>t1.`punkte`
    OR (
      t2.`Punkte`=t1.`punkte`
      AND t2.`geld`>t1.`geld`
  )
) AS `Rang`
FROM userrang AS t1
WHERE (SELECT 
      (COUNT(*)+1)
      FROM userrang AS t3
        WHERE t3.`Punkte`>t1.`punkte`
        OR (
          t3.`Punkte`=t1.`punkte`
          AND t3.`geld`>t1.`geld`
      )
    ) >= 70 # <-- der gesuchte minimale Rang
  AND (SELECT 
      (COUNT(*)+1)
      FROM userrang AS t4
        WHERE t4.`Punkte`>t1.`punkte`
        OR (
          t4.`Punkte`=t1.`punkte`
          AND t4.`geld`>t1.`geld`
      )
    ) <= 84 # <-- der gesuchte maximale Rang
ORDER BY `Rang`

Ich bin jetzt nicht auf Deine konkrete DB-Struktur eingegangen (Cut'n'Paste der vorhanden Querys war einfacher schneller), aber wenn die anderen Querys anzupassen waren, schaffst Du das hier auch.

Hier könnte es allerdings sein, dass es ab einer größeren Anzahl User langsam wird. Das solltest Du am besten vorher mal testen.

Gruß hpvw
 
Hast du schonmal was von Normalformen gehört ? ;-)

Ich würde die Tabelle etwas mehr aufteilen, sonst wird das immer unübersichtlicher.
Ausserdem kommen Daten doppelt vor (du kannst anhand der Kapfdaten zB ermitteln, wieviele Kämpfe einer grwonnen hat, dazu bräuchtest du keinen extra Eintrag).

Ich habe mal gehört, es sei von der Performance her besser, Daten zu trennen: die die sich ändern und die, die immer gleich bleiben
 
MissPiggy hat gesagt.:
Ich würde die Tabelle etwas mehr aufteilen, sonst wird das immer unübersichtlicher.
Alleine mit dem Aufteilen einer Tabelle nur der Übersicht wegen erreichst Du keine Normalisierung. Ich würde die Tabelle nicht aufteilen, solange es nicht durch eine der Normalformen geboten ist.
MissPiggy hat gesagt.:
Ausserdem kommen Daten doppelt vor (du kannst anhand der Kapfdaten zB ermitteln, wieviele Kämpfe einer grwonnen hat, dazu bräuchtest du keinen extra Eintrag).
Ich kann zwar kaum glauben, dass ich das jetzt schreibe, aber bei diesen Anforderungen kann ich mir ab einer (noch zu definierenden) größeren Datenmenge vorstellen, dass eine Denormalisierung zur Performancesteigerung bezüglich der gewonnen und verlorenen Kämpfe angebracht ist. Vorraussetzung ist dann natürlich eine aussergewöhnlich sorgsame Anwendungsprogrammierung, um Anomalien zu vermeiden. Auf den Rang wurde ja bereits verzichtet. Die Querys von oben würden sicherlich interessanter werden, wenn man die Siege, Verluste und ggf. daraus resultierende Punkte auch noch mit Joins und Subquerys in dem Query ermitteln würde.
MissPiggy hat gesagt.:
Ich habe mal gehört, es sei von der Performance her besser, Daten zu trennen: die die sich ändern und die, die immer gleich bleiben
Ich kenne dazu keine Performancetests, aber ich denke, dass das sehr stark von den durchzuführenden Abfragen abhängt. Werden diese Daten überwiegend gemeinsam benötigt, sind bei einer (nicht durch die Normalisierung bedingten) Aufteilung in mehrere Tabellen Joins nötig, die ggf. Performancelastiger sind, als eine breite Tabelle.

Gruß hpvw

Lit.:
http://www.logic.at/~moschm/LV/dbs_vo/dbs_vo.html#SECTION00043300000000000000
http://de.wikipedia.org/wiki/Normalisierung_(Datenbank)
http://v.hdm-stuttgart.de/~riekert/lehre/db-kelz/chap4.htm
http://www.tinohempel.de/info/info/datenbank/normalisierung.htm
 
Wegen der Form der Tabelle, ich hab das eigentlich gt bedacht.
Ich muss gewonnene und verlorene Kämpfe deshalb zählen, weil alte ämpfe aus der Kampftabelle gelöscht werden.
Außerdem ist es sicherlich schneller die Zahl auszulesen und azuzeigen anstatt alle Kämpfe durchzulaufen und dann zu prüfen.
Was genau meinst du mit dem mehr aufteilen? Ich glaube, viel mehr aufteilen muss ichs nicht.
@hpvw: Rießigen Dank nochmal, ich werds gleich nach dem Essen testen.
Ich denke, ich werd mir wohl auch heute noch ein MySQL Buch schnappen und ein wenig lernen, ich komm zwar mit den Grundfunktionen zurecht und das reicht unter normalen Umständen auch, ich hab das halt aus den MySQL Kapiteln in den PHP Büchern gelernt, da wird nicht sonderlich auf so Sachen geachtet.
Wegen der Datenmenge. Zurzeit ist die noch nciht genau definiert, aber die, die Prügelpause kennen, die wissen vielleicht noch, dass dort als immer um die 200-300 User online waren.
Ich bin gewillt, das alles so gut wie möglich zu programmieren, zeichnen, designen,.....
Mal schauen, obs was wird, ich hab schon vor es mindestens genausogut wie Prügelpause zu machen, mal sehen, was sich da machen lässt.


Marius
----
So, funktioneirt spitzenmäßig, wie zu erwarten :)
Du hast das gnaze so geschreiben, dass Ränge mit gleicher Punktezahl den gleichen Rangplatz bekommen. Das gibt aber Probleme wenn ich jetzt nur 14 Ränge ausgeben will, ich kann die Abfrage natürlich mit Limit einschränken, aber wenn der User nun eins nach unten in der Rangliste blättert, dann bekommst er nciht die nächsten 14 Ergebnisse sondern die nächsten 14 ab dem nächsten Rangplatz.
Ich muss gestehen, dass ich immer noch nciht kapiert habe, wie die Abfragen konkret funktioneiren... Vielleciht nach meiner MySQL Lektüre.


Marius
 
Zuletzt bearbeitet:
Marius Heil hat gesagt.:
Du hast das gnaze so geschreiben, dass Ränge mit gleicher Punktezahl den gleichen Rangplatz bekommen. Das gibt aber Probleme wenn ich jetzt nur 14 Ränge ausgeben will, ich kann die Abfrage natürlich mit Limit einschränken, aber wenn der User nun eins nach unten in der Rangliste blättert, dann bekommst er nciht die nächsten 14 Ergebnisse sondern die nächsten 14 ab dem nächsten Rangplatz.
Ich muss gestehen, dass ich immer noch nciht kapiert habe, wie die Abfragen konkret funktioneiren... Vielleciht nach meiner MySQL Lektüre.
Wenn Du dem ORDER BY noch die ID anfügst und damit eine absolut eindeutige Reihenfolge erzeugst kannst Du doch eine ganz normale Blätterfunktion mit LIMIT bauen.

Gruß hpvw

PS: Muss es denn nicht so sein, dass Punkt- und Geldgleiche User auf dem gleichen Rang stehen? Ansonsten müsstest Du Dir noch ein weiteres (eindeutiges) Kriterium überlegen, welches im Zweifelsfall den Ausschlag gibt.
 
Na ja, eigentlich ahst du ja Recht, aber der Punktestand ist so breit gefächert, (so bis 5000 oder so) da solltes eigentlich nciht zu oft vorkommen, im Prinzp hast du aber Recht, ich dachte nur, es ist ein klein wneig performancesparender es eifnach so zu machen. Bin zurzeit am Grübeln ob das nciht zu viel Arbeit für den Server gibt.
Aber ich denke, ich werd Geld dann wohl doch ncoh dazu nehmen, aber doppelte darfs keien geben, gleiches Geld und gleiche Punkte sind so selten, und da dann ncoh mir Arbeit machen wegen doppelten Rängen, das muss cnith sein^^ Gibt sonst noch massig zu tun.
Hab die Version grad vor ein paar Tagen mal auf nen Server geladen, so weis aussieht gehts perfekt (bis auf, dass der server kein mail() unterstützt).
Musste nur in meienr config die Daten ändern und es lief perfekt.


Marius
 
Zurück