Я играю в баскетбольную игру, которая позволяет выводить статистику в виде файла базы данных, чтобы можно было рассчитать статистику, которая не реализована в игре. До сих пор у меня не было проблем с вычислением статистики, которую я хотел, но теперь я столкнулся с проблемой: подсчитать количество двойных и / или тройных удвоений, сделанных игроком за сезон, из его игровой статистики.
Определение двойного двойного и тройного двойного следующее:
Пятислойный:
Дабл-дабл определяется как исполнение, в котором игрок накапливает в игре двузначное число в двух из пяти статистических категорий - очки, отдачи, передачи, перехваты и заблокированные удары.
Трипл-дабл:
Тройной дабл определяется как исполнение, в котором игрок накапливает в игре двузначное число в трех из пяти статистических категорий - очки, отскоки, передачи, перехваты и заблокированные удары.
Четырехместный-двойной (добавлено для уточнения)
Четверной дубль определяется как исполнение, в котором игрок накапливает двузначное число в четырех из пяти статистических категорий - очки, отдачи, передачи, перехваты и заблокированные удары - в игре.
Таблица «PlayerGameStats» хранит статистику для каждой игры, в которую играет игрок, и выглядит следующим образом:
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);
Результат, который я хочу получить, выглядит следующим образом:
| player_id | team | doubleDoubles | tripleDoubles |
|-----------|---------|---------------|---------------|
| 1 | Nuggets | 4 | 1 |
Единственное решение, которое я нашел до сих пор, так ужасно, что меня тошнит ...; о) ... Это выглядит так:
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
... и теперь вы, вероятно, тоже рвете (или сильно смеетесь) после прочтения этого. Я даже не выписал все, что нужно для получения всех двойных двойных комбинаций, и пропустил оператор case для тройных двойных комбинаций, потому что это еще более нелепо.
Есть лучший способ это сделать? Либо со структурой таблицы, которая у меня есть, либо с новой структурой таблицы (я мог бы написать скрипт для преобразования таблицы).
Я могу использовать MySQL 5.5 или PostgreSQL 9.2.
Вот ссылка на SqlFiddle с примерами данных и моим ужасным решением, которое я разместил выше: http://sqlfiddle.com/#!2/af6101/3
Обратите внимание, что меня не очень интересуют четверные-двойные числа (см. Выше), поскольку они не встречаются в игре, в которую я играю, насколько я знаю, но было бы плюсом, если запрос легко расширяется без особой перезаписи в аккаунт. для четырехместных.
CASE
операторы, так как логические выражения оцениваются в 1, когда истина, и в 0, когда ложь. Я добавил его к своему ответу ниже с приветом, так как не могу опубликовать полный блок кода SQL в комментарии здесь.CASE
иSUM/COUNT
позволяет работать на Postgres.CASE
как правило, немного быстрее. Я добавил демо с несколькими другими незначительными улучшениями.Попробуйте это (работал для меня на MySQL 5.5):
Или даже короче, откровенно срывая код JChao из его ответа, но удаляя ненужные
CASE
утверждения, так как логическое выражение expr оценивается в {1,0}, когда {True, False}:Судя по комментариям, приведенный выше код не будет работать в PostgreSQL, так как не любит делать boolean + boolean. Я до сих пор не люблю
CASE
. Вот выход на PostgreSQL (9.3), приведя кint
:источник
=
или>=
как хотите .CAST(... AS int)
( stackoverflow.com/questions/12126991/… ). MySQL может сделатьCAST(... AS UNSIGNED)
, что работает в этом запросе, но PostgreSQL не может. Не уверен, что есть что-то общее,CAST
что оба могут сделать для переносимости. В худшем случае,CASE
в конце концов , может возникнуть проблема, если переносимость имеет первостепенное значение.Вот еще один взгляд на проблему.
По моему мнению, вы по сути работаете с сводными данными для текущей проблемы, поэтому первое, что нужно сделать, - это отменить ее. К сожалению, PostgreSQL не предоставляет хороших инструментов для этого, поэтому, не вдаваясь в динамическую генерацию SQL в PL / PgSQL, мы можем по крайней мере сделать следующее:
Это помещает данные в более податливую форму, хотя это, конечно, не красиво. Здесь я предполагаю, что (player_id, seasonday) достаточно для однозначной идентификации игроков, т.е. идентификатор игрока уникален для разных команд. Если это не так, вам нужно будет включить достаточно информации для предоставления уникального ключа.
С этими неискаженными данными теперь можно фильтровать и агрегировать их полезными способами, такими как:
Это далеко не красиво, и, вероятно, не так быстро. Тем не менее, его можно обслуживать, требуя минимальных изменений для обработки новых типов статистики, новых столбцов и т. Д.
Так что это скорее «эй, ты думал», чем серьезное предложение? Цель состояла в том, чтобы смоделировать SQL так, чтобы он максимально точно соответствовал формулировке задачи, а не делал это быстро.
Это стало намного проще благодаря использованию правильных многозначных вставок и цитирования ANSI в MySQL-ориентированном SQL. Спасибо; приятно не видеть галочки на этот раз. Все, что мне пришлось изменить, - это генерация синтетического ключа.
источник
explain analyze
запросите планы (или эквивалент MySQL) и выясните, что они все делают и как :)То, что @Joshua отображает для MySQL , работает и в Postgres.
Boolean
значения могут быть приведеныinteger
и сложены. Приведение должно быть явным, хотя. Делает для очень короткого кода:SELECT
.Подробности в этом связанном ответе.
Тем не менее,
CASE
хотя и более многословно, как правило, немного быстрее. И более портативный, если это имеет значение:SQL Fiddle.
источник
Использование целочисленного деления и двоичного приведения
источник
Просто хочу оставить вариант версии @Craig Ringers здесь, который я нашел случайно, возможно, он пригодится кому-то в будущем.
Вместо нескольких UNION ALL он использует unnest и array. Источник для вдохновения: /programming/1128737/unpivot-and-postgresql
SQL Fiddle: http://sqlfiddle.com/#!12/4980b/3
источник