統計をデータベースファイルとして出力できるバスケットボールゲームをプレイしているため、ゲームに実装されていない統計を計算することができます。これまでのところ、必要な統計を計算するのに問題はありませんでしたが、今度は問題が発生しました。シーズン中にプレーヤーが作成したダブルダブルまたはトリプルダブルの数をゲームの統計からカウントすることです。
ダブルダブルとトリプルダブルの定義は次のとおりです。
Double-double:
ダブルダブルとは、プレーヤーがゲーム内の5つの統計カテゴリ(ポイント、リバウンド、アシスト、スチール、ブロックされたショット)の2つに合計2桁の数字を蓄積するパフォーマンスのことです。
トリプルダブル:
トリプルダブルとは、プレーヤーがゲーム内の5つの統計カテゴリ(ポイント、リバウンド、アシスト、スチール、ブロックショット)の3つに合計2桁の数字を蓄積するパフォーマンスのことです。
Quadruple-double(説明のために追加)
Quadruple-doubleは、プレーヤーがゲーム内の5つの統計的カテゴリー(ポイント、リバウンド、アシスト、スチール、ブロックされたショット)の4つで合計2桁の数字を累積するパフォーマンスとして定義されます。
「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 |
これまでに見つけた唯一の解決策はひどいもので、私を吐き気にさせます...; o)...次のようになります。
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
...そして、あなたはおそらくこれを読んだ後、おそらくあなたはまた、つまんでいる(または激しく笑っている)。私はすべてのdouble doubleの組み合わせを取得するために必要なすべてを書き出さず、トリプルdoubleのcaseステートメントをさらにばかげているので省略しました。
これを行うより良い方法はありますか?私が持っているテーブル構造または新しいテーブル構造のどちらかを使用します(テーブルを変換するスクリプトを作成できます)。
MySQL 5.5またはPostgreSQL 9.2を使用できます。
ここに、サンプルデータと上に投稿した私のひどい解決策を含むSqlFiddleへのリンクがあります。 http://sqlfiddle.com/#!2/af6101/
私が知っている限り、私がプレイするゲームでは4重ダブル(上記を参照)は発生しないので、私は本当に興味がないことに注意してください。 quadruple-doublesの場合。
これが最善の方法かどうかはわかりません。最初に、統計が2桁かどうかを確認するために選択を行い、2桁の場合は1を割り当てました。これらすべてを合計して、ゲームごとの2桁の合計数を調べます。そこから、すべてのダブルとトリプルを合計します。動作するようです
select a.player_id,
a.team,
sum(case when a.doubles = 2 then 1 else 0 end) as doubleDoubles,
sum(case when a.doubles = 3 then 1 else 0 end) as tripleDoubles
from
(select *,
(case when points > 9 then 1 else 0 end) +
(case when rebounds > 9 then 1 else 0 end) +
(case when assists > 9 then 1 else 0 end) +
(case when steals > 9 then 1 else 0 end) +
(case when blocks > 9 then 1 else 0 end) as Doubles
from PlayerGameStats) a
group by a.player_id, a.team
これを試してください(MySQL 5.5で私のために働いた):
SELECT
player_id,
team,
SUM(
( (points >= 10)
+ (rebounds >= 10)
+ (assists >= 10)
+ (steals >= 10)
+ (blocks >= 10)
) = 2
) double_doubles,
SUM(
( (points >= 10)
+ (rebounds >= 10)
+ (assists >= 10)
+ (steals >= 10)
+ (blocks >= 10)
) = 3
) triple_doubles
FROM PlayerGameStats
GROUP BY player_id, team
またはさらに短く、JChaoのコードを露骨に引きはがして、不要なCASE
ステートメントを取り除くことにより、ブール値exprは{True、False}のときに{1,0}と評価されるため、
select a.player_id,
a.team,
sum(a.doubles = 2) as doubleDoubles,
sum(a.doubles = 3) as tripleDoubles
from
(select *,
(points > 9) +
(rebounds > 9) +
(assists > 9) +
(steals > 9) +
(blocks > 9) as Doubles
from PlayerGameStats) a
group by a.player_id, a.team
上記のコードは、ブール値+ブール値を実行したくないため、PostgreSQLでは実行されないというコメントに基づいています。私はまだCASE
が好きではありません。以下は、PostgreSQL(9.3)でint
にキャストする方法です。
select a.player_id,
a.team,
sum((a.doubles = 2)::int) as doubleDoubles,
sum((a.doubles = 3)::int) as tripleDoubles
from
(select *,
(points > 9)::int +
(rebounds > 9)::int +
(assists > 9)::int +
(steals > 9)::int +
(blocks > 9)::int as Doubles
from PlayerGameStats) a
group by a.player_id, a.team
これが問題の別の見方です。
私の考えでは、あなたは基本的に現在の問題のピボットされたデータを操作しているので、最初に行うべきことはアンピボットすることです。残念なことに、PostgreSQLはそれを行うための素晴らしいツールを提供していません。そのため、PL/PgSQLで動的SQLを生成することなく、少なくとも次のことができます。
SELECT player_id, seasonday, 'points' AS scoretype, points AS score FROM playergamestats
UNION ALL
SELECT player_id, seasonday, 'rebounds' AS scoretype, rebounds FROM playergamestats
UNION ALL
SELECT player_id, seasonday, 'assists' AS scoretype, assists FROM playergamestats
UNION ALL
SELECT player_id, seasonday, 'steals' AS scoretype, steals FROM playergamestats
UNION ALL
SELECT player_id, seasonday, 'blocks' AS scoretype, blocks FROM playergamestats
これはデータをより順応性のある形式にしますが、確かにきれいではありません。ここでは、(player_id、seasonday)は、プレーヤーを一意に識別するのに十分であると想定しています。つまり、プレーヤーIDはチーム全体で一意です。そうでない場合は、一意のキーを提供するのに十分な他の情報を含める必要があります。
このピボットされていないデータを使用すると、次のような便利な方法でデータをフィルタリングおよび集計することができます。
SELECT
player_id,
count(CASE WHEN doubles = 2 THEN 1 END) AS doubledoubles,
count(CASE WHEN doubles = 3 THEN 1 END) AS tripledoubles
FROM (
SELECT
player_id, seasonday, count(*) AS doubles
FROM
(
SELECT player_id, seasonday, 'points' AS scoretype, points AS score FROM playergamestats
UNION ALL
SELECT player_id, seasonday, 'rebounds' AS scoretype, rebounds FROM playergamestats
UNION ALL
SELECT player_id, seasonday, 'assists' AS scoretype, assists FROM playergamestats
UNION ALL
SELECT player_id, seasonday, 'steals' AS scoretype, steals FROM playergamestats
UNION ALL
SELECT player_id, seasonday, 'blocks' AS scoretype, blocks FROM playergamestats
) stats
WHERE score >= 10
GROUP BY player_id, seasonday
) doublestats
GROUP BY player_id;
これはきれいとはほど遠く、おそらくそれほど速くありません。ただし、保守は可能であり、新しいタイプの統計、新しい列などを処理するために最小限の変更が必要です。
ですから、真剣な提案というよりは、「ちょっと、あなたは考えましたか」というよりもです。目的は、SQLを高速化するのではなく、問題のステートメントにできるだけ直接対応するようにSQLをモデル化することでした。
これは、MySQL指向のSQLで適切な多値挿入とANSIクォートを使用することにより、非常に簡単になりました。ありがとうございました;バックティックを一度も見ないのはいいことです。変更しなければならないのは、合成キーの生成だけでした。
何 @ JoshuaはMySQLに対して表示されます は、Postgresでも機能します。 Boolean
の値はinteger
にキャストして加算できます。ただし、キャストは明示的である必要があります。非常に短いコードになります:
SELECT player_id, team
, count(doubles = 2 OR NULL) AS doubledoubles
, count(doubles = 3 OR NULL) AS tripledoubles
FROM (
SELECT player_id, team,
(points > 9)::int +
(rebounds > 9)::int +
(assists > 9)::int +
(steals > 9)::int +
(blocks > 9)::int AS doubles
FROM playergamestats
) a
GROUP BY 1, 2;
SELECT
のdoubleをカウントする短い方法を利用します。ただし、CASE
-より冗長ですが、通常は少し高速です。そして、もしそれが重要であるなら、よりポータブルです:
SELECT player_id, team
, count(doubles = 2 OR NULL) AS doubledoubles
, count(doubles = 3 OR NULL) AS tripledoubles
FROM (
SELECT player_id, team,
CASE WHEN points > 9 THEN 1 ELSE 0 END +
CASE WHEN rebounds > 9 THEN 1 ELSE 0 END +
CASE WHEN assists > 9 THEN 1 ELSE 0 END +
CASE WHEN steals > 9 THEN 1 ELSE 0 END +
CASE WHEN blocks > 9 THEN 1 ELSE 0 END AS doubles
FROM playergamestats
) a
GROUP BY 1, 2;
整数除算とバイナリキャストの使用
SELECT player_id
, team
, SUM(CASE WHEN Doubles = 2 THEN 1 ELSE 0 END) DoubleDouble
, SUM(CASE WHEN Doubles = 3 THEN 1 ELSE 0 END) TripleDouble
FROM (SELECT player_id
, team
, (BINARY (points DIV 10) > 0)
+ (BINARY (rebounds DIV 10) > 0)
+ (BINARY (assists DIV 10) > 0)
+ (BINARY (steals DIV 10) > 0)
+ (BINARY (blocks DIV 10) > 0)
AS Doubles
FROM PlayerGameStats) d
GROUP BY player_id, team
偶然見つけた@Craig Ringersバージョンのバリエーションをここに残したいだけなのですが、将来の誰かに役立つかもしれません。
複数のUNION ALLではなく、ネストと配列を使用します。インスピレーションのソース: https://stackoverflow.com/questions/1128737/unpivot-and-postgresql
SELECT
player_id,
count(CASE WHEN doubles = 2 THEN 1 END) AS doubledoubles,
count(CASE WHEN doubles = 3 THEN 1 END) AS tripledoubles
FROM (
SELECT
player_id, seasonday, count(*) AS doubles
FROM
(
SELECT
player_id,
seasonday,
unnest(array['Points', 'Rebounds', 'Assists', 'Steals', 'Blocks']) AS scoretype,
unnest(array[Points, Rebounds, Assists, Steals, Blocks]) AS score
FROM PlayerGameStats
) stats
WHERE score >= 10
GROUP BY player_id, seasonday
) doublestats
GROUP BY player_id;
SQLフィドル: http://sqlfiddle.com/#!12/4980b/