Eu jogo um jogo de basquete que permite exibir suas estatísticas como um arquivo de banco de dados, para que possamos calcular estatísticas que não foram implementadas no jogo. Até agora, não tive nenhum problema em calcular as estatísticas que queria, mas agora me deparei com um problema: contar o número de duplos duplos e / ou triplos duplos que um jogador fez ao longo da temporada a partir de suas estatísticas de jogo.
A definição de um duplo duplo e um triplo duplo é a seguinte:
Dobro dobro:
Um duplo duplo é definido como um desempenho no qual um jogador acumula um total de dois dígitos em duas das cinco categorias estatísticas - pontos, rebotes, assistências, roubadas de bola e bloqueios - em um jogo.
Triplo duplo:
Um triplo-duplo é definido como um desempenho no qual um jogador acumula um total de dois dígitos em três das cinco categorias estatísticas - pontos, rebotes, assistências, roubadas de bola e bloqueios - em um jogo.
Quádruplo-duplo (adicionado para esclarecimento)
Um quádruplo-duplo é definido como um desempenho no qual um jogador acumula um total de dois dígitos em quatro das cinco categorias estatísticas - pontos, rebotes, assistências, roubadas de bola e bloqueios - em um jogo.
A tabela "PlayerGameStats" armazena estatísticas para cada jogo que um jogador joga e tem a seguinte aparência:
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);
A saída que eu quero alcançar é assim:
| player_id | team | doubleDoubles | tripleDoubles |
|-----------|---------|---------------|---------------|
| 1 | Nuggets | 4 | 1 |
A única solução que encontrei até agora é tão terrível que me faz vomitar ...; o) ... É assim:
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
... e agora você provavelmente também está vomitando (ou rindo muito) depois de ler isso. Eu nem escrevi tudo o que seria necessário para obter todas as combinações de duplo duplo e omiti a declaração de caso dos duplos triplos porque é ainda mais ridículo.
Existe uma maneira melhor de fazer isso? Com a estrutura da tabela que eu tenho ou com uma nova estrutura da tabela (eu poderia escrever um script para converter a tabela).
Eu posso usar o MySQL 5.5 ou PostgreSQL 9.2.
Aqui está um link para o SqlFiddle com dados de exemplo e minha péssima solução que eu publiquei acima: http://sqlfiddle.com/#!2/af6101/3
Observe que não estou realmente interessado em duplos quádruplos (veja acima), pois eles não ocorrem no jogo que eu jogo até onde eu sei, mas seria uma vantagem se a consulta fosse facilmente expansível sem muita reescrita na conta para quádruplos-duplos.
fonte
CASE
instruções, pois as expressões booleanas avaliam 1 quando verdadeiro e 0 quando falso. Adicionei-o à minha resposta abaixo com um grito para você, pois não é possível postar o bloco de código SQL completo no comentário aqui.CASE
eSUM/COUNT
permite que ele funcione no Postgres também.CASE
normalmente é um pouco mais rápido. Eu adicionei uma demonstração com algumas outras pequenas melhorias.Experimente isso (funcionou para mim no MySQL 5.5):
Ou ainda mais, rasgando descaradamente o código de JChao de sua resposta, mas retirando as
CASE
declarações desnecessárias , já que o boolean expr é avaliado em {1,0} quando {True, False}:Com base nos comentários de que o código acima não será executado no PostgreSQL, pois não gosta de fazer booleano + booleano. Eu ainda não gosto
CASE
. Aqui está uma saída do PostgreSQL (9.3), lançando paraint
:fonte
=
ou>=
como adequado.CAST(... AS int)
( stackoverflow.com/questions/12126991/… ). O MySQL pode fazerCAST(... AS UNSIGNED)
, o que funciona nesta consulta, mas o PostgreSQL não. Não tenho certeza se existe algo comumCAST
que ambos possam fazer pela portabilidade. Pior CASE, pode ser travadoCASE
no final se a portabilidade for primordial.Aqui está outra opinião sobre o problema.
Na minha opinião, você está essencialmente trabalhando com dados dinâmicos para o problema atual; portanto, a primeira coisa a fazer é descompactá-lo. Infelizmente, o PostgreSQL não fornece boas ferramentas para fazer isso; portanto, sem entrar na geração dinâmica de SQL no PL / PgSQL, podemos pelo menos:
Isso coloca os dados em uma forma mais maleável, embora certamente não seja bonito. Aqui, eu suponho que (player_id, seasonday) é suficiente para identificar jogadores de forma exclusiva, ou seja, o ID do jogador é único entre os times. Caso contrário, você precisará incluir outras informações suficientes para fornecer uma chave exclusiva.
Com esses dados não dinâmicos, agora é possível filtrá-los e agregá-los de maneiras úteis, como:
Isso está longe de ser bonito e provavelmente não é tão rápido assim. Porém, é sustentável, exigindo alterações mínimas para lidar com novos tipos de estatísticas, novas colunas etc.
Portanto, é mais um "ei, você pensou" do que uma sugestão séria. O objetivo era modelar o SQL para corresponder à declaração do problema o mais diretamente possível, em vez de torná-lo rápido.
Isso ficou muito mais fácil com o uso de inserções com vários valores e ANSI no SQL orientado ao MySQL. Obrigado; é bom não ver backticks pela primeira vez. Tudo o que tive que mudar foi a geração de chaves sintéticas.
fonte
explain analyze
os planos de consulta (ou MySQL equivalentes) e descobrir o que tudo o que fazem e como :)O que o @Joshua exibe para o MySQL , também funciona no Postgres.
Boolean
valores podem ser convertidosinteger
e adicionados. O elenco precisa ser explícito, no entanto. Cria um código muito curto:SELECT
.Detalhes nesta resposta relacionada.
No entanto,
CASE
embora seja mais detalhado, normalmente é um pouco mais rápido. E mais portátil, se isso importa:SQL Fiddle.
fonte
Usando divisão inteira e conversão binária
fonte
Só quero deixar uma variação da versão do @Craig Ringers aqui que encontrei por acidente, talvez seja útil para alguém no futuro.
Em vez de vários UNION ALL, ele usa unnest e array. Fonte de inspiração: /programming/1128737/unpivot-and-postgresql
SQL Fiddle: http://sqlfiddle.com/#!12/4980b/3
fonte