Ich habe drei Tabellen in MySQL, die zwar zusammenhängen, aber technisch nicht durch einen Fremdschlüssel miteinander verbunden sind. Sie sind: Benutzer , Ebenen et Klassen .
Die Tabelle Benutzer hat eine Karma-Spalte, einen numerischen Typ. Basierend auf dieser Karma Nummer, möchte ich den Namen des Benutzers wissen Ebene die ich aus der Tabelle der Ebenen abrufe. Dies ist keine harte Beziehung, da eine Ebene mit einer Stufe verbunden ist. Bereich von Karmawerten, etwa so:
- Stufe 1 (Mindestkarma: 0)
- Stufe 2 (Mindestkarma: 100)
- Stufe 3 (Mindestkarma: 500)
- ...
Wenn also ein Benutzer ein Karma von 400 hat, sollte der Rückgabewert 2 sein. Um die Dinge etwas komplizierter zu machen, gibt die Levelnummer die Stufe des Benutzers an Klasse , deren Definitionen in der Tabelle Klassen gespeichert sind. Auch dies ist eine Bereich Beziehung:
- Klasse Ameise (mindestens Stufe 1)
- Klasse Eule (mindestens Stufe 5)
- Klasse Löwe (mindestens Stufe 100)
- ...
Zusammengefasst geht es um drei Tabellen, die auf der Grundlage von Bereichswerten eine implizite Beziehung zueinander haben. Meine Frage bezieht sich darauf, wie man diese Tabellen effektiv abfragen kann. Ich benötige häufig Informationen für einen oder mehrere Benutzer auf der Grundlage einer Bedingung. Die Ergebnismenge sollte die Benutzerdetails, aber auch die Stufe und Klasse des Benutzers enthalten.
Für einen einzelnen Benutzer ist es mir gelungen, diese Abfrage zu schreiben, die gut funktioniert:
SELECT u.*, lv.num as level, lvc.title as class, lvc.id as classid
FROM user as u, level as lv, levelclass as lvc
WHERE u.id = ? AND lv.min_karma <= u.karma AND lv.num <= lvc.minlevel_num
ORDER BY lv.num DESC LIMIT 1;
Wenn ich jedoch die Ergebnismenge erweitern würde, indem ich WHERE u.id = ? belasse und LIMIT 1 entferne, so dass ich nach einer Liste von Benutzern, erhalte ich die Kombination aller drei Tabellen. Normalerweise würden Sie die Zeilen durch einen inneren Join auf Schlüssel reduzieren, aber da dies eine Bereichsprüfung ist, funktioniert das nicht. Ich habe versucht, die Bereichsprüfung in einer inneren Verknüpfungsbedingung zu verwenden, aber das führt zum gleichen Ergebnis. Auch mit der Gruppierung erhalte ich nicht das gewünschte Ergebnis.
In einem verzweifelten Versuch habe ich mir diese Abfrage ausgedacht, die funktioniert:
SELECT usr.*,
(SELECT lv.num as level
FROM user as u, level as lv, levelclass as lvc
WHERE u.id = usr.id AND lv.min_karma <= u.karma AND lv.num <= lvc.minlevel_num
ORDER BY lv.num DESC LIMIT 1) as level,
(SELECT lvc.title as class
FROM user as u, level as lv, levelclass as lvc
WHERE u.id = usr.id AND lv.min_karma <= u.karma AND lv.num <= lvc.minlevel_num
ORDER BY lv.num DESC LIMIT 1) as class,
(SELECT lvc.image as class_image
FROM user as u, level as lv, levelclass as lvc
WHERE u.id = usr.id AND lv.min_karma <= u.karma AND lv.num <= lvc.minlevel_num
ORDER BY lv.num DESC LIMIT 1) as class_image,
(SELECT lvc.id as classid
FROM user as u, level as lv, levelclass as lvc
WHERE u.id = usr.id AND lv.min_karma <= u.karma AND lv.num <= lvc.minlevel_num
ORDER BY lv.num DESC LIMIT 1) as classid
FROM user as usr
ORDER BY usr.$sortby $direction LIMIT ?,?
Das scheint mir jedoch sehr ineffizient zu sein. Im Grunde schreibe ich hier eine Unterabfrage für jede Spalte(!) die ich aus den Tabellen der Stufen und Klassen benötige. Wenn ich mehrere Spalten der Ebenen- oder Klassentabellen in einer Unterabfrage abfrage, werden wieder die Kombinationen aller Werte zurückgegeben. Ich habe das Gefühl, dass es eine Lücke in meinen DB-Kenntnissen gibt, etwas Offensichtliches, das mir fehlt, eine Funktion, die ich nicht kenne...
Können Sie mir helfen? Wie schreibt man eine effiziente Abfrage für einen Satz von Zeilen, der Spalten aus drei Tabellen kombiniert, aber nicht durch Schlüssel (stattdessen Bereiche) verknüpft ist?
PS: Ich weiß, dass ich das Szenario stark vereinfachen könnte, wenn ich dieses Schema denormalisieren würde, um Ebenen und Klassen in der Tabelle "Benutzer" zusammenzufassen, aber es gibt einen bestimmten Grund, warum ich das brauche, glauben Sie mir.