行の2つ以上の列が特定の値を超えている場所をカウントする[バスケットボール、ダブルダブル、トリプルダブル]


20

統計情報をデータベースファイルとして出力できるバスケットボールゲームをプレイしているので、ゲームに実装されていない統計情報を計算できます。これまでのところ、必要な統計を計算するのに何の問題もありませんでしたが、今では問題に直面しています:プレーヤーがシーズン中に作ったダブルダブルまたはトリプルダブルの数をゲーム統計からカウントすることです。

double doubleとtriple doubleの定義は次のとおりです。

ダブルダブル:

ダブルダブルとは、プレイヤーがゲーム内で5つの統計カテゴリー(ポイント、リバウンド、アシスト、スチール、ブロックショット)のうち2つに合計2桁の数字を累積するパフォーマンスとして定義されます。

トリプルダブル:

トリプルダブルとは、プレイヤーがゲーム内で5つの統計カテゴリー(ポイント、リバウンド、アシスト、スチール、ブロックショット)のうち3つに合計2桁の数字を累積するパフォーマンスとして定義されます。

Quadruple-double(明確にするために追加)

4倍ダブルは、プレーヤーがゲームで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 |

私がこれまでに見つけた唯一の解決策は、ひどいことです。

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/3

私が知っている限り、私はプレイしているゲームでは発生しないので、私は4倍ダブル(上記参照)にはあまり興味がないことに注意してください。 4倍ダブルの場合。

回答:


10

これが最善の方法かどうかわからない。最初に、統計情報が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

こんにちは、解決策をありがとうございます。私は本当にそれが好き。私が望んでいることを正確に実行し、多くの記述をすることなく、Quadruple-doubleとQuintuple-doublesを含めるように簡単に拡張できます。今のところこれを受け入れられる答えにします。:)
ケス14年

私はあなたのコードが好きですが、あなたはそれをさらに短くするためにそれをハックすることができます。CASEブール式はtrueの場合は1、falseの場合は0と評価されるため、ステートメントを使用する必要はありません。ここにコメントで完全なSQLコードブロックを投稿することはできないので、私はそれを以下の答えに追加しました。
ジョシュアフーバー14年

ジョシュアありがとう。それを完全に見落とし、はるかに良く見えます。
SQLChao 14年

1
@JoshuaHuber正しいですが、クエリはMySQLでのみ機能します。使用するCASESUM/COUNT、同様のPostgresの仕事にそれを可能にします。
ypercubeᵀᴹ

@ypercube:実際には、ブール値を加算することはPostgresでも機能します。明示的にキャストするだけです。しかしCASE、通常は少し高速です。いくつかのマイナーな改良を加えたデモを追加しました。
アーウィンブランドステッター

7

これを試してください(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

@ypercube、良い点と感謝。上記の質問に対するコメントとして、その正確な説明をたずねただけでした。セマンティクス。私は、ホッケーの4つの目標はまだ「ハットトリックを引く」と考えられていますが、ボウリングで4回連続して打つことは「七面鳥」とは見なされず、むしろ「クワッド」と考えられます。私は各ゲームのセマンティクスの専門家ではありません。あなたが決定を下し、=または>=適切に選択します。
ジョシュアフーバー14年

ソリューションをありがとう。私が望むことを明確に行います。また、提供したJChaoの短縮バージョンも気に入っています。
ケス14年

1
ブール値の追加はPostgreSQLでは機能しませんが、注意してください。
クレイグリンガー14年

@CraigRinger-それを指摘してくれてありがとう。一般的なSQL、特にPostgreSQlに関しては、まだ耳が緑ですので、これは貴重な情報です。:)
ケス14年

1
@CraigRingerいいけど、MySQLがサポートしているとは思わないCAST(... AS int)stackoverflow.com/questions/12126991/…)。MySQLはCAST(... AS UNSIGNED)このクエリで機能しますが、PostgreSQLは機能しません。CAST両方が移植性のためにできる共通点があるかどうかはわかりません。最悪のCASE場合、移植性が最優先の場合、最終的には動かなくなる可能性があります。
ジョシュアフーバー14年

6

問題の別の見解を次に示します。

私が考えているように、あなたは本質的に現在の問題のピボットされたデータで作業しているので、最初にすることはそれをアンピボットすることです。残念ながら、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を高速化するのではなく、できる限り直接問題文に対応するようにモデル化することでした。


これは、MySQL指向のSQLで適切な多値挿入とANSIクォートを使用することにより、非常に簡単になりました。ありがとうございました; バックティックを一度も見ないのはいいことです。変更しなければならなかったのは、合成キーの生成だけでした。


これは私が念頭に置いていたものの一種です。
コリン 'ハート14年

1
このソリューションを投稿していただきありがとうございます。上記の@ Colin'tHartが示唆したように、このような問題を実装する際に問題がありました(以前はそのようなことをしたことはありませんが、将来計算する可能性のある他の統計には非常に役立ちそうです)。目的の出力を達成する方法がいくつあるかは興味深いです。今日、明確に多くのことを学びました。
ケス

1
詳細についてexplain analyzeは、クエリプラン(またはMySQLの同等物)で、それらがすべて何をどのように行うかを理解してください:)
クレイグリンガー14年

@CraigRinger-ありがとう。いいアドバイス。実際、これまでに提供されたすべてのソリューションでそれを行いました(SqlFiddlesの「実行計画の表示」を使用しました)。しかし、出力を読むときは、「すべてが何をするのか、どのように行うのか」という部分に取り組む必要があります。= O
ケス14年

6

@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;

ただし、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;

SQLフィドル。



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

1

偶然見つけた@Craig Ringersバージョンのバリエーションをここに残したいだけです。おそらく将来的に誰かに役立つでしょう。

複数のUNION ALLの代わりに、unnestと配列を使用します。インスピレーションのソース: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/3

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.