Komplizierteste SQL-Query ever

Es gibt so ein tolles Zitat:

“Was nicht auf einer einzigen Manuskriptseite zusammengefasst werden kann, ist nicht durchdacht und nicht entscheidungsreif.”

Wenn man das auf meine SQL-Abfrage überträgt, muss ich wohl eingestehen, dass diese Abfrage undurchdacht wäre. Ist sie aber nicht! Ich habe 3 Tage an dieser Abfrage zugebracht, damit sie das Ergebnis ausgibt, welches sie jetzt ausgibt.

Die Abfrage ist für ein Wettkampf, der aus mehreren Einzeldisziplinen besteht, die an unterschiedlichen Tagen veranstaltet werden (zeitgleich und hintereinander). Der Wettkampf ist für Teams. Für jede Einzeldisziplin ist die DisziplinId, TeamId, Platz, Datum, Punktestand vorhanden. Allerdings wird für die Gesamtwertung nicht der Punktestand in der Einzeldisziplin genommen, sondern inder Gesamtwertung werden neue Punkte anhand der Platzierung in der Einzeldisziplin vergeben – z.B. so: Platz 1 – 100 Punkte, Platz 2 – 90 Punkte, usw.

Es klingt schon so natürlich sprachlich kompliziert und ehe ich hier weitere Einzelheiten versuche zu erklären, platziere ich hier einfach die 117 Zeilen lange SQL-Abfrage:
[code lang=’sql‘]
SELECT
@anzTeam := (SELECT COUNT(*) FROM pentathlon_team WHERE freigeschaltet=’1′),
@seq := @anzTeam + 1,
@rank := @anzTeam,
@letzteDatum := (SELECT DISTINCT SUBSTR(MIN(zeitpunkt),1,10) FROM pentathlon_score WHERE pentathlon_credits != 0),
@letztePunkte := 999999;
SELECT
gesamt.teamid,
@seq := IF(@letzteDatum = gesamt.zeitpunkt, @seq – 1, @anzTeam) AS seq, /*Sequenz …,3,2,1 je Datum*/
@rank := IF(@letztePunkte = gesamt.punkte, @rank, @seq) AS rank, /*Der Rank eines Teams (wenn gleiche Punktzahl gleicher Rank)*/
@letztePunkte := gesamt.punkte AS punkte,
@letzteDatum := gesamt.zeitpunkt AS zeitpunkt
FROM
(SELECT
einzelgesamt.teamid,
SUM(einzelgesamt.punkte) AS punkte,
einzelgesamt.zeitpunkt AS zeitpunkt
FROM
(SELECT DISTINCT
normale_daten.zeitpunkt,
normale_daten.teamid,
normale_daten.disziplinid,
IF(normale_daten.punkte IS NOT NULL,
normale_daten.punkte,
IF((SELECT von FROM pentathlon_disziplin WHERE disziplinid = normale_daten.disziplinid) > normale_daten.zeitpunkt,
0, /*Disziplin noch nicht gestartet*/
(SELECT DISTINCT /*Disziplin ist beendet: Punkte des letzten Stands*/
IF (pentathlon_score.rank > 25,
0, /*Keine Punkte mehr ab Platz 25*/
pentathlon_punkte.punkte
) AS punkte
FROM
pentathlon_score
LEFT JOIN
pentathlon_punkte
ON
pentathlon_score.rank = pentathlon_punkte.rank
WHERE
pentathlon_score.disziplinid = normale_daten.disziplinid AND
pentathlon_score.teamid = normale_daten.teamid AND
pentathlon_score.zeitpunkt = (SELECT DISTINCT
MAX(zeitpunkt)
FROM pentathlon_score
WHERE disziplinid = normale_daten.disziplinid)
)
)
) AS punkte,
IF(normale_daten.rank IS NOT NULL,
normale_daten.rank,
IF((SELECT von FROM pentathlon_disziplin WHERE disziplinid = normale_daten.disziplinid) > normale_daten.zeitpunkt,
0, /*Disziplin noch nicht gestartet*/
(SELECT DISTINCT /*Disziplin ist beendet: Punkte des letzten Stands*/
pentathlon_score.rank
FROM
pentathlon_score
WHERE
pentathlon_score.disziplinid = normale_daten.disziplinid AND
pentathlon_score.teamid = normale_daten.teamid AND
pentathlon_score.zeitpunkt = (SELECT DISTINCT
MAX(zeitpunkt)
FROM pentathlon_score
WHERE disziplinid = normale_daten.disziplinid)
)
)
) AS rank
FROM
(SELECT DISTINCT
alle_daten.zeitpunkt,
alle_daten.teamid,
alle_daten.disziplinid,
pentathlon_score.rank,
IF (pentathlon_score.rank > 25,
0, /*Keine Punkte mehr ab Platz 25*/
pentathlon_punkte.punkte
) AS punkte
FROM
(SELECT DISTINCT
SUBSTR(pentathlon_score.zeitpunkt,1,10) as zeitpunkt,
pentathlon_team.teamid,
pentathlon_disziplin.disziplinid,
pentathlon_teamdisziplin.webrpc
FROM
pentathlon_score
JOIN
pentathlon_team
JOIN
pentathlon_disziplin
INNER JOIN
pentathlon_teamdisziplin
ON pentathlon_disziplin.disziplinid = pentathlon_teamdisziplin.disziplinid
WHERE
pentathlon_score.pentathlon_credits != 0 AND
pentathlon_team.freigeschaltet = ‚1‘) AS alle_daten
LEFT JOIN
pentathlon_score
ON
alle_daten.teamid = pentathlon_score.teamid AND
alle_daten.disziplinid = pentathlon_score.disziplinid AND
IF(SUBSTR(alle_daten.webrpc,1,33) = ‚http://www.worldcommunitygrid.org‘,
alle_daten.zeitpunkt = SUBSTR(pentathlon_score.zeitpunkt,1,10),
alle_daten.zeitpunkt = DATE_ADD(SUBSTR(pentathlon_score.zeitpunkt,1,10), INTERVAL -1 DAY) AND
SUBSTR(pentathlon_score.zeitpunkt,12,2)=’01‘
)

LEFT JOIN
pentathlon_punkte
ON
pentathlon_score.rank = pentathlon_punkte.rank) AS normale_daten

) AS einzelgesamt
GROUP BY
einzelgesamt.zeitpunkt,
einzelgesamt.teamid
) AS gesamt
ORDER BY
gesamt.zeitpunkt,
gesamt.punkte DESC
[/code]
Natürlich hätte ich das auch alles durch einfache Abfragen lösen können, die ich dann in PHP zusammenfüge, aber in PHP ist das einfügen und sortieren der Daten so ineffizient.

Die @variable sind User-Variablen in MySQL, mit denen man die Platzierung in der Abfrage berechnen kann.

Jetzt würde ich meine Fähigkeiten in SQL mit einer 1,2 benoten.. ;)

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.