Gram w grę w koszykówkę, która pozwala na generowanie statystyk jako pliku bazy danych, dzięki czemu można obliczyć statystyki, które nie są zaimplementowane w grze. Do tej pory nie miałem problemu z obliczeniem statystyk, które chciałem, ale teraz napotkałem problem: liczenie liczby podwójnych i / lub potrójnych podwójnych wyników gracza w sezonie na podstawie jego statystyk gry.
Definicja podwójnego i potrójnego podwójnego jest następująca:
Podwójny podwójny:
Podwójne podwójne jest zdefiniowane jako występ, w którym gracz gromadzi dwucyfrową liczbę w dwóch z pięciu kategorii statystycznych - punktów, zbiórek, asyst, kradzieży i zablokowanych strzałów - w grze.
Potrójne podwójne:
Potrójny podwójny jest definiowany jako występ, w którym gracz gromadzi dwucyfrową liczbę w trzech z pięciu kategorii statystycznych - punktów, zbiórek, asyst, kradzieży i zablokowanych strzałów - w grze.
Quadruple-double (dodano dla wyjaśnienia)
Poczwórny podwójny jest definiowany jako występ, w którym gracz gromadzi dwucyfrową liczbę w czterech z pięciu kategorii statystycznych - punktów, zbiórek, asyst, kradzieży i zablokowanych strzałów - w grze.
Tabela „PlayerGameStats” przechowuje statystyki dla każdej gry, w którą gra gracz, i wygląda następująco:
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);
Wynik, który chcę osiągnąć, wygląda następująco:
| player_id | team | doubleDoubles | tripleDoubles |
|-----------|---------|---------------|---------------|
| 1 | Nuggets | 4 | 1 |
Jedyne rozwiązanie, jakie do tej pory znalazłem, jest tak okropne, że aż wymiotuję ...; o) ... Wygląda to tak:
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
... a teraz prawdopodobnie też rzygasz (lub mocno się śmiejesz) po przeczytaniu tego. Nie napisałem nawet wszystkiego, co byłoby potrzebne do uzyskania wszystkich podwójnych kombinacji podwójnych, i pominąłem instrukcję case dla potrójnych podwójnych, ponieważ jest to jeszcze bardziej śmieszne.
Czy jest na to lepszy sposób? Albo ze strukturą tabeli, którą mam, albo z nową strukturą tabeli (mógłbym napisać skrypt do konwersji tabeli).
Mogę używać MySQL 5.5 lub PostgreSQL 9.2.
Oto link do SqlFiddle z przykładowymi danymi i moim okropnym rozwiązaniem, które zamieściłem powyżej: http://sqlfiddle.com/#!2/af6101/3
Zauważ, że tak naprawdę nie jestem zainteresowany quadruple-double (patrz wyżej), ponieważ nie występują one w grze, w którą gram, o ile wiem, ale byłby plus, gdyby zapytanie można było łatwo rozbudować bez konieczności przepisywania konta dla poczwórnych podwójnych.
źródło
CASE
instrukcji, ponieważ wyrażenia boolowskie mają wartość 1, gdy ma wartość true, a 0, gdy ma wartość false. Dodałem go do mojej odpowiedzi poniżej, z wykrzyknięciem, ponieważ nie mogę tutaj opublikować pełnego bloku kodu SQL w komentarzu.CASE
iSUM/COUNT
pozwala to również działać na Postgres.CASE
zwykle jest trochę szybszy. Dodałem demo z kilkoma innymi drobnymi ulepszeniami.Wypróbuj to (pracował dla mnie na MySQL 5.5):
Lub nawet krócej, odrywając kod JChao z jego odpowiedzi, ale usuwając niepotrzebne
CASE
instrukcje, ponieważ wyrażenie boolowskie ocenia na {1,0}, gdy {True, False}:Na podstawie komentarzy, że powyższy kod nie będzie działał w PostgreSQL, ponieważ nie lubi robić boolean + boolean. Nadal nie lubię
CASE
. Oto wyjście z PostgreSQL (9.3), przesyłając doint
:źródło
=
lub>=
pasuje.CAST(... AS int)
( stackoverflow.com/questions/12126991/... ). MySQL może zrobićCAST(... AS UNSIGNED)
, co działa w tym zapytaniu, ale PostgreSQL nie. Nie jestem pewien, czy istnieje coś wspólnego wCAST
zakresie przenośności. Najgorszy PRZYPADEK może utknąćCASE
w końcu, jeśli najważniejsza jest przenośność.Oto kolejne spojrzenie na problem.
Tak myślę, że zasadniczo pracujesz z danymi przestawnymi dla bieżącego problemu, więc pierwszą rzeczą do zrobienia jest odwrócenie go. Niestety PostgreSQL nie zapewnia dobrych narzędzi do tego, więc bez wchodzenia w dynamiczne generowanie SQL w PL / PgSQL, możemy przynajmniej:
To sprawia, że dane są bardziej plastyczne, choć z pewnością nie są ładne. Zakładam tutaj, że (player_id, seasonday) jest wystarczający, aby jednoznacznie zidentyfikować graczy, tj. Identyfikator gracza jest unikalny dla różnych drużyn. Jeśli tak nie jest, musisz podać wystarczającą ilość innych informacji, aby podać unikalny klucz.
Dzięki niepodzielnym danym można teraz filtrować i agregować je w użyteczny sposób, na przykład:
Jest to dalekie od ładnego i prawdopodobnie nie jest tak szybkie. Można go jednak utrzymać, wymagając minimalnych zmian w celu obsługi nowych typów statystyk, nowych kolumn itp.
To bardziej „hej, myślałeś o” niż poważna sugestia. Celem było modelowanie kodu SQL tak, aby odpowiadał opisowi problemu tak bezpośrednio, jak to możliwe, a nie przyspieszenie.
Było to znacznie łatwiejsze dzięki zastosowaniu rozsądnych wielowartościowych wstawek i cytowaniu ANSI w SQL zorientowanym na MySQL. Dziękuję Ci; miło jest nie oglądać się za raz. Wszystko, co musiałem zmienić, to syntetyczne generowanie kluczy.
źródło
explain analyze
zaplanuj zapytania (lub odpowiednik MySQL) i dowiedz się, co oni wszyscy robią i jak :)To, co @ Joshua wyświetla dla MySQL , działa również w Postgres.
Boolean
wartości można rzutowaćinteger
i sumować. Obsada musi być jednak wyraźna. Sprawia, że kod jest bardzo krótki:SELECT
.Szczegóły w tej powiązanej odpowiedzi.
Jednak
CASE
- chociaż bardziej szczegółowy - jest zwykle nieco szybszy. I bardziej przenośny, jeśli to powinno mieć znaczenie:SQL Fiddle.
źródło
Korzystanie z dzielenia liczb całkowitych i rzutowania binarnego
źródło
Po prostu chcę zostawić tutaj odmianę wersji @Craig Ringers, którą znalazłem przypadkiem, może przyda się komuś w przyszłości.
Zamiast wielu UNION ALL używa unnest i tablic. Źródło inspiracji: /programming/1128737/unpivot-and-postgresql
SQL Fiddle: http://sqlfiddle.com/#!12/4980b/3
źródło