2016-09-19 4 views
1

Ich habe eine Reihe von Rennwagenfahrern, die auf verschiedenen Strecken fahren. Ich möchte ihre beste Rundenzeit auf jeder einzelnen Strecke abrufen und sie mit den besten Rundenzeiten anderer Benutzer auf der jeweiligen Strecke vergleichen. Ich möchte dies für alle Benutzer auf allen Spuren tun. Ich möchte also eine große Rangliste zurückgeben.Finden Sie den Rang der niedrigsten Rundenzeit eines Benutzers

Grundsätzlich, wenn ich 10 Rennwagenfahrer habe, die jeweils 25 Runden auf der Strecke 1 absolviert haben, möchte ich nur die beste Rundenzeit jedes Rennwagenfahrers ermitteln und diese Zeiten gegeneinander auf jeder Strecke bewerten.

Ich glaube, ich es fast haben, siehe Abfrage unten und eine SQLFiddle Link: http://sqlfiddle.com/#!9/64d6c/2

Um sicherzustellen, dass Sie alle Teile haben, gibt es auch eine „tracks.verified“ Spalte. Dies bestimmt, ob die Spur verifiziert wurde oder nicht. Sie müssen sich nicht wirklich um diesen Parameter kümmern und können ihn auslassen, wenn Sie möchten. Ich beziehe mich auf dieser Linie:

AND s1.track_id IN (SELECT id FROM tracks WHERE verified=1) 

http://sqlfiddle.com/#!9/64d6c/2

SELECT track_id, user_id, duration, @rank := @rank + 1 AS rank FROM 
(
    SELECT DISTINCT s1.track_id, s1.user_id, s1.duration 
    FROM session_lap_times s1 
    LEFT JOIN session_lap_times s2 
    ON s1.user_id=s2.user_id 
    AND s1.track_id = s2.track_id 
    AND s1.duration > s2.duration 
    WHERE s2.duration IS NULL 
    AND s1.track_id IN (SELECT id FROM tracks WHERE verified=1) 
    ORDER BY s1.duration ASC 
) zz, (SELECT @rank := 0) z; 

Diese Ausgänge:

+----------+---------+------------------+------+ 
| track_id | user_id | duration   | rank | 
+----------+---------+------------------+------+ 
|  15 |  2 | 71001.5129995350 | 1 | 
|  15 |  1 | 75001.5129995350 | 2 | 
|  17 |  1 | 90258.1180334090 | 3 | 
|  17 |  2 | 90897.0659971240 | 4 | 
+----------+---------+------------------+------+ 

Das Problem ist, es ist alles gegeneinander Ranking, und nicht gegen alle von jeder Spur . Diese Ergebnisse sollten wie folgt aussehen:

+----------+---------+------------------+------+ 
| track_id | user_id | duration   | rank | 
+----------+---------+------------------+------+ 
|  15 |  2 | 71001.5129995350 | 1 | 
|  15 |  1 | 75001.5129995350 | 2 | 
|  17 |  1 | 90258.1180334090 | 1 | 
|  17 |  2 | 90897.0659971240 | 2 | 
+----------+---------+------------------+------+ 

Ich denke, diese Linie ist das Problem:

AND s1.track_id IN (SELECT id FROM tracks WHERE verified=1) 

Denn wenn ich setzen s1.track_id = 15 (zum Beispiel), das funktioniert wie für einen einzelnen erwartet Spur. Nur nicht alle.

Jede Hilfe wird geschätzt!

EDIT:

Ich versuche, die Ergebnisse von User_id zu filtern. Also habe ich deine ganze Anfrage genommen und in eine Unterabfrage gestellt. Gibt es eine Möglichkeit, dies zu tun, ohne es in eine Unterabfrage zu stellen? Dank

select track_id, user_id, duration, rank from (SELECT track_id, user_id,duration, 
    CASE WHEN [email protected] THEN @rank:=0 END as reset, 
    @rank := @rank + 1 AS rank, 
    @track:=track_id 
FROM 
(
    SELECT DISTINCT s1.track_id, s1.user_id, s1.duration 
    FROM session_lap_times s1 
    LEFT JOIN session_lap_times s2 
    ON s1.user_id=s2.user_id 
    AND s1.track_id = s2.track_id 
    AND s1.duration > s2.duration 
    WHERE s2.duration IS NULL 
    AND s1.track_id IN (SELECT id FROM tracks WHERE verified=1) 
    ORDER BY s1.duration ASC 
) zz, (SELECT @rank := 0, @track := null) z) as x where user_id=1 

Was die Gesamtzahl der Treiber zählen Abfrage ich habe:

SELECT track_id, COUNT(user_id) FROM (SELECT track_id,user_id FROM session_lap_times GROUP BY track_id,user_id) as z GROUP BY track_id 

Auch hier gibt es eine schönere Art und Weise dies ohne die Unterabfrage zu tun? Vielen Dank! :)

Antwort

1
SELECT track_id, user_id, duration, 
    CASE WHEN [email protected] THEN @rank:=0 END as reset, 
    @rank := @rank + 1 AS rank, 
    @track:=track_id 
FROM 
(
    SELECT DISTINCT s1.track_id, s1.user_id, s1.duration 
    FROM session_lap_times s1 
    LEFT JOIN session_lap_times s2 
    ON s1.user_id=s2.user_id 
    AND s1.track_id = s2.track_id 
    AND s1.duration > s2.duration 
    WHERE s2.duration IS NULL 
    AND s1.track_id IN (SELECT id FROM tracks WHERE verified=1) 
    ORDER BY s1.duration ASC 
) zz, (SELECT @rank := 0, @track := null) z; 

Getestet mit deiner Geige.

eine zusätzliche Variable einführen und rank auf track_id Wechsel zurück

+0

OH wow. Genial!! Ist es möglich, auch einen Rang "out of" Wert zurückzugeben? Insgesamt alle Fahrer, die auf dieser Strecke gefahren sind? Also kann ich in meiner App so etwas anzeigen: Rang 1 von 2000 Treibern? Lassen Sie mich wissen, ob es nicht angemessen ist, dies in derselben Abfrage zu tun, und ob es eher eine eigene Abfrage haben soll. – toast

+0

Nach weiteren Überlegungen denke ich, es könnte einfacher sein, es in einer separaten Abfrage zu tun. Passen Sie die Ergebnisse später in meinem App-Code an. Kennen Sie eine Abfrage, die dies tun könnte? Vielen Dank! – toast

+0

In der ursprünglichen Abfrage, die Sie gepostet haben, gibt es eine Möglichkeit, die Ergebnisse nach user_id zu filtern? So sollte beispielsweise user_id 1 den Rang 1 bei track_id 17 und den Rang 2 bei track_id 15 haben. – toast

0

ich Ihre SQL verwirrend finden. Ich würde GROUP BY verwenden.

SELECT track_id, user_id, MIN(duration) as best_time 
FROM session_lap_times 
GROUP BY track_id, user_id 
ORDER BY track_id, best_time; 
Verwandte Themen