Juego un juego de baloncesto que permite generar sus estadísticas como un archivo de base de datos, para poder calcular estadísticas que no se implementan en el juego. Hasta ahora no he tenido problemas para calcular las estadísticas que quería, pero ahora me he encontrado con un problema: contar el número de dobles dobles y / o triples dobles que un jugador hizo durante la temporada a partir de las estadísticas de su juego.
La definición de doble doble y triple doble es la siguiente:
Doble doble:
Un doble doble se define como una actuación en la cual un jugador acumula un total de dos dígitos en dos de las cinco categorías estadísticas: puntos, rebotes, asistencias, robos y tiros bloqueados en un juego.
Triple doble:
Un triple-doble se define como una actuación en la que un jugador acumula un número total de dos dígitos en tres de las cinco categorías estadísticas (puntos, rebotes, asistencias, robos y tiros bloqueados) en un juego.
Cuádruple-doble (agregado para aclaración)
Un cuádruple-doble se define como una actuación en la que un jugador acumula un número total de dos dígitos en cuatro de cinco categorías estadísticas (puntos, rebotes, asistencias, robos y tiros bloqueados) en un juego.
La tabla "PlayerGameStats" almacena estadísticas de cada juego que juega un jugador y tiene el siguiente aspecto:
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);
El resultado que quiero lograr se ve así:
| player_id | team | doubleDoubles | tripleDoubles |
|-----------|---------|---------------|---------------|
| 1 | Nuggets | 4 | 1 |
La única solución que encontré hasta ahora es tan horrible que me hace vomitar ...; o) ... Se ve así:
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
... y ahora probablemente también estás vomitando (o riéndote fuerte) después de leer esto. Ni siquiera escribí todo lo que se necesitaría para obtener todas las combinaciones dobles dobles, y omití la declaración del caso para los dobles triples porque es aún más ridículo.
¿Hay una mejor manera de hacer esto? Ya sea con la estructura de tabla que tengo o con una nueva estructura de tabla (podría escribir un script para convertir la tabla).
Puedo usar MySQL 5.5 o PostgreSQL 9.2.
Aquí hay un enlace a SqlFiddle con datos de ejemplo y mi horrible solución que publiqué anteriormente: http://sqlfiddle.com/#!2/af6101/3
Tenga en cuenta que no estoy realmente interesado en los dobles cuádruples (ver arriba) ya que no ocurren en el juego que juego hasta donde yo sé, pero sería una ventaja si la consulta se puede expandir fácilmente sin tener que volver a escribir en la cuenta para dobles cuádruples.
fuente
CASE
sentencias ya que las expresiones booleanas evalúan a 1 cuando es verdadero y 0 cuando es falso. Lo agregué a mi respuesta a continuación con un saludo, ya que no puedo publicar el bloque de código SQL completo en el comentario aquí.CASE
ySUM/COUNT
permite que funcione en Postgres también.CASE
generalmente es un poco más rápido. Agregué una demostración con algunas otras mejoras menores.Pruebe esto (funcionó para mí en MySQL 5.5):
O incluso más corto, arrancando descaradamente el código de JChao de su respuesta, pero sacando las
CASE
declaraciones innecesarias ya que boolean expr se evalúa en {1,0} cuando {True, False}:Según los comentarios, el código anterior no se ejecutará en PostgreSQL ya que no le gusta hacer boolean + boolean. Aún no me gusta
CASE
. Aquí hay una salida en PostgreSQL (9.3), enviando aint
:fuente
=
o>=
según te convenga.CAST(... AS int)
( stackoverflow.com/questions/12126991/… ). MySQL puede hacerloCAST(... AS UNSIGNED)
, lo que funciona en esta consulta, pero PostgreSQL no. No estoy seguro de que haya algo comúnCAST
que ambos puedan hacer para la portabilidad. En el peor de los casos,CASE
al final puede quedar atrapado si la portabilidad es primordial.Aquí hay otra versión del problema.
A mi modo de ver, básicamente estás trabajando con datos pivotados para el problema actual, por lo que lo primero que debes hacer es desconectarlo. Lamentablemente, PostgreSQL no proporciona buenas herramientas para hacerlo, por lo que sin entrar en la generación dinámica de SQL en PL / PgSQL, al menos podemos hacer:
Esto pone los datos en una forma más maleable, aunque seguramente no es bonita. Aquí supongo que (player_id, seasonday) es suficiente para identificar de forma única a los jugadores, es decir, la ID del jugador es única en todos los equipos. Si no es así, deberá incluir suficiente información adicional para proporcionar una clave única.
Con esos datos no divididos ahora es posible filtrarlos y agregarlos de maneras útiles, como:
Esto está lejos de ser bonito, y probablemente no sea tan rápido. Sin embargo, es mantenible y requiere cambios mínimos para manejar nuevos tipos de estadísticas, nuevas columnas, etc.
Por lo tanto, es más un "oye, ¿pensaste?" Que una sugerencia seria. El objetivo era modelar el SQL para que se correspondiera con la declaración del problema lo más directamente posible, en lugar de hacerlo rápido.
Esto se hizo mucho más fácil gracias al uso de inserciones sanas de valores múltiples y las citas ANSI en su SQL orientado a MySQL. Gracias; Es bueno no ver backticks por una vez. Todo lo que tuve que cambiar fue la generación de claves sintéticas.
fuente
explain analyze
los planes de consulta (o el equivalente de MySQL) y averiguar qué hacen todos y cómo :)Lo que @Joshua muestra para MySQL también funciona en Postgres.
Boolean
los valores se pueden convertirinteger
y sumar. Sin embargo, el elenco debe ser explícito. Hace para código muy corto:SELECT
.Detalles en esta respuesta relacionada.
Sin embargo,
CASE
aunque es más detallado, generalmente es un poco más rápido. Y más portátil, si eso importa:SQL Fiddle.
fuente
Usando división entera y conversión binaria
fuente
Solo quiero dejar una variación de la versión de @Craig Ringers aquí que encontré por accidente, tal vez sea útil para alguien en el futuro.
En lugar de múltiples UNION ALL, usa unnest y array. Fuente de inspiración: /programming/1128737/unpivot-and-postgresql
SQL Fiddle: http://sqlfiddle.com/#!12/4980b/3
fuente