Je joue à un match de basket qui permet de sortir ses statistiques sous forme de fichier de base de données, donc on peut en calculer des statistiques qui ne sont pas implémentées dans le jeu. Jusqu'à présent, je n'ai eu aucun problème à calculer les statistiques que je voulais, mais maintenant j'ai rencontré un problème: compter le nombre de doubles doubles et / ou triples doubles réalisés par un joueur au cours de la saison à partir de ses statistiques de jeu.
La définition d'un double double et d'un triple double est la suivante:
Double double:
Un double-double est défini comme une performance dans laquelle un joueur accumule un nombre total à deux chiffres dans deux des cinq catégories statistiques - points, rebonds, passes décisives, interceptions et tirs bloqués - dans une partie.
Triple-double:
Un triple-double est défini comme une performance dans laquelle un joueur accumule un nombre total à deux chiffres dans trois des cinq catégories statistiques - points, rebonds, passes décisives, interceptions et tirs bloqués - dans une partie.
Quadruple-double (ajouté pour clarification)
Un quadruple double est défini comme une performance dans laquelle un joueur accumule un nombre total à deux chiffres dans quatre des cinq catégories statistiques - points, rebonds, passes décisives, interceptions et tirs bloqués - dans une partie.
Le tableau "PlayerGameStats" stocke les statistiques de chaque jeu joué par un joueur et se présente comme suit:
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);
La sortie que je veux atteindre ressemble à ceci:
| player_id | team | doubleDoubles | tripleDoubles |
|-----------|---------|---------------|---------------|
| 1 | Nuggets | 4 | 1 |
La seule solution que j'ai trouvée jusqu'à présent est si horrible qu'elle me fait vomir ...; o) ... Cela ressemble à ceci:
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
... et maintenant vous êtes probablement aussi en train de vomir (ou de rire fort) après avoir lu ceci. Je n'ai même pas écrit tout ce qui serait nécessaire pour obtenir toutes les combinaisons doubles doubles, et j'ai omis la déclaration de cas pour les doubles doubles parce que c'est encore plus ridicule.
Y a-t-il une meilleure manière de faire cela? Soit avec la structure de table que j'ai, soit avec une nouvelle structure de table (je pourrais écrire un script pour convertir la table).
Je peux utiliser MySQL 5.5 ou PostgreSQL 9.2.
Voici un lien vers SqlFiddle avec des exemples de données et ma terrible solution que j'ai publiée ci-dessus: http://sqlfiddle.com/#!2/af6101/3
Notez que je ne suis pas vraiment intéressé par les quadruples doubles (voir ci-dessus) car ils ne se produisent pas dans le jeu que je joue pour autant que je sache, mais ce serait un plus si la requête est facilement extensible sans trop de réécriture pour le compte pour quadruple-double.
CASE
instructions car les expressions booléennes sont évaluées à 1 lorsqu'elles sont vraies et à 0 lorsqu'elles sont fausses. Je l'ai ajouté à ma réponse ci-dessous avec un cri car vous ne pouvez pas poster le bloc de code SQL complet en commentaire ici.CASE
et luiSUM/COUNT
permet également de fonctionner sur Postgres.CASE
est généralement un tout petit peu plus rapide. J'ai ajouté une démo avec quelques autres améliorations mineures.Essayez ceci (travaillé pour moi sur MySQL 5.5):
Ou encore plus court, en arrachant ouvertement le code de JChao de sa réponse, mais en supprimant les
CASE
déclarations inutiles puisque boolean expr est évalué à {1,0} lorsque {True, False}:Sur la base des commentaires que le code ci-dessus ne fonctionnera pas dans PostgreSQL car n'aime pas faire booléen + booléen. Je n'aime toujours pas
CASE
. Voici un moyen de sortir sur PostgreSQL (9.3), en effectuant un cast versint
:la source
=
ou>=
comme bon vous semble.CAST(... AS int)
( stackoverflow.com/questions/12126991/… ). MySQL peut le faireCAST(... AS UNSIGNED)
, ce qui fonctionne dans cette requête, mais pas PostgreSQL. Pas sûr qu'il y ait un communCAST
que les deux peuvent faire pour la portabilité. Le pire des cas, pourrait être coincéCASE
à la fin si la portabilité est primordiale.Voici une autre vision du problème.
À mon avis, vous travaillez essentiellement avec des données pivotées pour le problème actuel, donc la première chose à faire est de le débloquer. Malheureusement, PostgreSQL ne fournit pas de bons outils pour le faire, donc sans entrer dans la génération SQL dynamique en PL / PgSQL, nous pouvons au moins faire:
Cela met les données sous une forme plus malléable, mais ce n'est certainement pas joli. Ici, je suppose que (player_id, seasonday) est suffisant pour identifier de manière unique les joueurs, c'est-à-dire que l'ID du joueur est unique d'une équipe à l'autre. Si ce n'est pas le cas, vous devrez inclure suffisamment d'autres informations pour fournir une clé unique.
Avec ces données non pivotées, il est désormais possible de les filtrer et de les agréger de manière utile, comme:
C'est loin d'être joli, et ce n'est probablement pas si rapide. Il est cependant maintenable, nécessitant des modifications minimales pour gérer de nouveaux types de statistiques, de nouvelles colonnes, etc.
C'est donc plus un "hé, avez-vous pensé" qu'une suggestion sérieuse. Le but était de modéliser le SQL pour correspondre à l'énoncé du problème aussi directement que possible, plutôt que de le rendre rapide.
Cela a été rendu beaucoup plus facile par votre utilisation d'inserts sensés à valeurs multiples et de cotations ANSI dans votre SQL orienté MySQL. Merci; c'est sympa de ne pas voir de backticks pour une fois. Tout ce que j'ai dû changer, c'est la génération de clés synthétiques.
la source
explain analyze
les plans de requête (ou équivalent MySQL) et comprendre ce qu'ils font tous et comment :)Ce que @Joshua affiche pour MySQL , fonctionne également dans Postgres.
Boolean
les valeurs peuvent être convertiesinteger
et additionnées. Le casting doit cependant être explicite. Fait pour le code très court:SELECT
.Détails dans cette réponse connexe.
Cependant,
CASE
- même si plus verbeux - est généralement un tout petit peu plus rapide. Et plus portable, si cela importe:SQL Fiddle.
la source
Utilisation de la division entière et de la conversion binaire
la source
Je veux juste laisser ici une variante de la version de @Craig Ringers que j'ai trouvée par accident, peut-être que c'est utile pour quelqu'un à l'avenir.
Au lieu de plusieurs UNION ALL, il utilise unnest et array. Source d'inspiration: /programming/1128737/unpivot-and-postgresql
SQL Fiddle: http://sqlfiddle.com/#!12/4980b/3
la source