Ich spiele ein Basketballspiel, bei dem die Statistiken als Datenbankdatei ausgegeben werden können, sodass man daraus Statistiken berechnen kann, die nicht im Spiel implementiert sind. Bisher hatte ich keine Probleme, die von mir gewünschten Statistiken zu berechnen, aber jetzt bin ich auf ein Problem gestoßen: Zählen der Anzahl der doppelten und / oder dreifachen Doppelten, die ein Spieler im Laufe der Saison aus seinen Spielstatistiken gemacht hat.
Die Definition eines doppelten Doppelten und eines dreifachen Doppelten lautet wie folgt:
Doppel-Doppel:
Ein Double-Double ist eine Leistung, bei der ein Spieler eine zweistellige Gesamtsumme in zwei von fünf statistischen Kategorien - Punkte, Abpraller, Vorlagen, Diebstähle und geblockte Schüsse - in einem Spiel ansammelt.
Triple-Double:
Ein Triple-Double ist eine Leistung, bei der ein Spieler eine zweistellige Gesamtsumme in drei von fünf statistischen Kategorien - Punkte, Abpraller, Vorlagen, Diebstähle und geblockte Schüsse - in einem Spiel ansammelt.
Vierfach-Doppel (zur Verdeutlichung hinzugefügt)
Ein Vierfach-Doppel ist eine Leistung, bei der ein Spieler eine zweistellige Gesamtsumme in vier von fünf statistischen Kategorien - Punkte, Abpraller, Vorlagen, Diebstähle und geblockte Schüsse - in einem Spiel ansammelt.
Die "PlayerGameStats" -Tabelle speichert Statistiken für jedes Spiel, das ein Spieler spielt, und sieht folgendermaßen aus:
CREATE TABLE PlayerGameStats AS SELECT * FROM ( VALUES
( 1, 1, 1, 'Nuggets', 'Cavaliers', 6, 8, 2, 2, 0 ),
( 2, 1, 2, 'Nuggets', 'Clippers', 15, 7, 0, 1, 3 ),
( 3, 1, 6, 'Nuggets', 'Trailblazers', 11, 11, 1, 2, 1 ),
( 4, 1, 10, 'Nuggets', 'Mavericks', 8, 10, 2, 2, 12 ),
( 5, 1, 11, 'Nuggets', 'Knicks', 23, 12, 1, 0, 0 ),
( 6, 1, 12, 'Nuggets', 'Jazz', 8, 8, 11, 1, 0 ),
( 7, 1, 13, 'Nuggets', 'Suns', 7, 11, 2, 2, 1 ),
( 8, 1, 14, 'Nuggets', 'Kings', 10, 15, 0, 3, 1 ),
( 9, 1, 15, 'Nuggets', 'Kings', 9, 7, 5, 0, 4 ),
(10, 1, 17, 'Nuggets', 'Thunder', 13, 10, 10, 1, 0 )
) AS t(id,player_id,seasonday,team,opponent,points,rebounds,assists,steals,blocks);
Die Ausgabe, die ich erreichen möchte, sieht folgendermaßen aus:
| player_id | team | doubleDoubles | tripleDoubles |
|-----------|---------|---------------|---------------|
| 1 | Nuggets | 4 | 1 |
Die einzige Lösung, die ich bisher gefunden habe, ist so schrecklich, dass ich kotze ...; o) ... Es sieht so aus:
SELECT
player_id,
team,
SUM(CASE WHEN(points >= 10 AND rebounds >= 10) OR
(points >= 10 AND assists >= 10) OR
(points >= 10 AND steals >= 10)
THEN 1
ELSE 0
END) AS doubleDoubles
FROM PlayerGameStats
GROUP BY player_id
... und jetzt kotzen (oder lachen) Sie wahrscheinlich auch, nachdem Sie dies gelesen haben. Ich habe nicht einmal alles aufgeschrieben, was nötig wäre, um alle Double-Double-Kombinationen zu erhalten, und die case-Anweisung für die Triple-Double weggelassen, weil sie noch lächerlicher ist.
Gibt es einen besseren Weg, dies zu tun? Entweder mit der Tabellenstruktur, die ich habe, oder mit einer neuen Tabellenstruktur (ich könnte ein Skript schreiben, um die Tabelle zu konvertieren).
Ich kann MySQL 5.5 oder PostgreSQL 9.2 verwenden.
Hier ist ein Link zu SqlFiddle mit Beispieldaten und meiner schrecklichen Lösung, die ich oben gepostet habe: http://sqlfiddle.com/#!2/af6101/3
Beachten Sie, dass ich nicht wirklich an Vierfach-Doppel interessiert bin (siehe oben), da sie meines Wissens nicht in dem Spiel vorkommen, das ich spiele, aber es wäre ein Plus, wenn die Abfrage leicht erweiterbar wäre, ohne viel umzuschreiben für Vierbettzimmer.
quelle
CASE
Anweisungen müssen nicht verwendet werden , da boolesche Ausdrücke bei true den Wert 1 und bei false den Wert 0 annehmen. Ich habe es zu meiner Antwort unten mit einem Gruß an Sie hinzugefügt, da ich hier keinen vollständigen SQL-Codeblock im Kommentar posten kann.CASE
undSUM/COUNT
kann es auch auf Postgres angewendet werden.CASE
aber in der Regel ein kleines bisschen schneller. Ich habe eine Demo mit ein paar anderen kleinen Verbesserungen hinzugefügt.Probieren Sie dies aus (bei mir mit MySQL 5.5):
Oder noch kürzer, indem Sie JChaos Code aus seiner Antwort herausnehmen, aber die nicht benötigten
CASE
Anweisungen herausnehmen, da der boolesche Ausdruck {1,0} ergibt, wenn {True, False}:Basierend auf den Kommentaren, dass der obige Code in PostgreSQL nicht ausgeführt wird, da er nicht gerne Boolean + Boolean ausführt. Ich mag es immer noch nicht
CASE
. Hier ist ein Ausweg aus PostgreSQL (9.3)int
:quelle
=
oder>=
als fit.CAST(... AS int)
( stackoverflow.com/questions/12126991/… ). MySQL kann dasCAST(... AS UNSIGNED)
, was in dieser Abfrage funktioniert, aber PostgreSQL nicht. IchCAST
bin mir nicht sicher, ob es eine Gemeinsamkeit gibt , die beide für die Portabilität tun können. Schlimmster Fall, könnteCASE
am Ende stecken bleiben, wenn Portabilität von größter Bedeutung ist.Hier ist eine andere Sicht auf das Problem.
So wie ich das sehe, arbeiten Sie im Wesentlichen mit Pivot-Daten für das aktuelle Problem. Das erste, was Sie tun müssen, ist, die Pivot-Funktion aufzuheben. Leider bietet PostgreSQL dafür keine nützlichen Tools. Daher können wir zumindest Folgendes tun, ohne in die dynamische SQL-Generierung in PL / PgSQL einzusteigen:
Dies bringt die Daten in eine formbarere Form, obwohl es sicher nicht schön ist. Hier gehe ich davon aus, dass (player_id, seasonday) ausreicht, um Spieler eindeutig zu identifizieren, dh die Spieler-ID ist für alle Teams eindeutig. Ist dies nicht der Fall, müssen Sie genügend weitere Informationen angeben, um einen eindeutigen Schlüssel bereitzustellen.
Mit diesen nicht zugewiesenen Daten ist es jetzt möglich, sie auf nützliche Weise zu filtern und zu aggregieren, wie zum Beispiel:
Das ist alles andere als hübsch und wahrscheinlich nicht so schnell. Es ist jedoch wartbar und erfordert nur minimale Änderungen, um mit neuen Arten von Statistiken, neuen Spalten usw. umzugehen.
Es ist also eher ein "Hey, hast du daran gedacht" als ein ernstzunehmender Vorschlag. Ziel war es, die SQL so zu modellieren, dass sie der Problemstellung so direkt wie möglich entspricht, anstatt sie zu beschleunigen.
Dies wurde durch die Verwendung vernünftiger mehrwertiger Einfügungen und ANSI-Anführungszeichen in Ihrem MySQL-orientierten SQL-Code erheblich vereinfacht. Vielen Dank; Es ist schön, einmal keine Backticks zu sehen. Alles, was ich ändern musste, war die Erzeugung synthetischer Schlüssel.
quelle
explain analyze
Informationen finden Sie in den Abfrageplänen (oder in MySQL-Entsprechungen) und finden Sie heraus, was sie alle tun und wie :)Was @Joshua für MySQL anzeigt , funktioniert auch in Postgres.
Boolean
Werte können umgewandeltinteger
und addiert werden. Die Besetzung muss jedoch eindeutig sein. Für sehr kurzen Code:SELECT
.Details in dieser verwandten Antwort.
Allerdings
CASE
- obwohl ausführlicher - ist es in der Regel ein kleines bisschen schneller. Und tragbarer, wenn das etwas ausmacht:SQL-Geige.
quelle
Verwenden der Ganzzahldivision und der binären Umwandlung
quelle
Ich möchte hier nur eine Variation der @Craig Ringers-Version hinterlassen, die ich zufällig gefunden habe. Vielleicht ist sie für jemanden in der Zukunft nützlich.
Anstelle von mehreren UNION ALLs werden unnest und array verwendet. Quelle für Inspiration: /programming/1128737/unpivot-and-postgresql
SQL Fiddle: http://sqlfiddle.com/#!12/4980b/3
quelle