0

プレイヤーが勝ち続ける限り、連勝をカウントするクエリ生成テーブルがあります。プレイヤーがプラスのスコアを獲得すると、ストリークは 1 ずつ上昇し、マイナスのスコアを獲得すると、ストリークは 0 に戻ります。表は次のようになります。

+--------+------------------+--------+--------+
| player |    timestamp     | points | streak |
+--------+------------------+--------+--------+
| John   | 22/11/2012 23:01 |     -2 |      0 |
| John   | 22/11/2012 23:02 |      3 |      1 |
| John   | 22/11/2012 23:04 |      5 |      2 |
| John   | 22/11/2012 23:05 |     -2 |      0 |
| John   | 22/11/2012 23:18 |     15 |      1 |
| John   | 23/11/2012 23:20 |      5 |      2 |
| Chris  | 27/11/2012 22:12 |     20 |      1 |
| Chris  | 27/11/2012 22:14 |    -12 |      0 |
| Chris  | 27/11/2012 22:17 |      4 |      1 |
| Chris  | 27/11/2012 22:18 |     -4 |      0 |
| Chris  | 27/11/2012 22:20 |     10 |      1 |
| Chris  | 27/11/2012 22:21 |     20 |      2 |
| Chris  | 27/11/2012 22:22 |     90 |      3 |
+--------+------------------+--------+--------+

もちろん、簡単に取得できる最大の連続記録を取得したいと思いますが、その特定の連続記録でプレーヤーが獲得したポイントも含めたいと思います。したがって、上記の例の場合、結果は次のようになります。

+--------+--------+-----------+
| player | points | maxstreak |
+--------+--------+-----------+
| John   |     20 |         2 |
| Chris  |    120 |         3 |
+--------+--------+-----------+

どうすればこれを達成できるかについてのアイデアはありますか?前もって感謝します!

4

2 に答える 2

1

実際にこれを試す機会はありませんでしたが、mySQL 変数を使用して動作する必要があります...

最初に、最も内側のクエリはスコア テーブルからクエリを実行し、プレーヤーとタイムスタンプの順にデータを強制します。そこから、MySQL 変数で順次処理する必要があります。最初に...処理中の新しいレコードごとに、別の「プレーヤー」(実際には名前ではなくIDに基づいている必要があります)を使用している場合、ストリーク、ポイント、maxStreak、maxStreakPointsをゼロにリセットしています。最後のユーザーを処理しようとしている人に設定します。

その直後、連勝状況や点数などをチェック中…

すべてを表にまとめたら、OUTERMOST クエリを使用して、プレーヤーごとに、最高の最大連勝数 / 最大連勝ポイント数を取得します。

SELECT
      Final.Player,
      MAX( Final.MaxStreak ) MaxStreak,
      MAX( Final.MaxStreakPoints ) MaxStreakPoints 
   FROM 
      ( 
        SELECT 
              PreOrd.Player,
              PreOrd.TimeStamp,
              PreOrd.Points,
              @nStreak       := case when PreOrd.Points < 0 then 0
                                     when PreOrd.Player = @cLastPlayer then @nStreak +1
                                     else 1 end  Streak,                              

              @nStreakPoints := case when @nStreak = 1 then PreOrd.Points
                                     when @nStreak > 1 then @nStreakPoints + PreOrd.Points
                                     else 0 end  StreakPoints,

              @nMaxStreak    := case when PreOrd.Player != @cLastPlayer then @nStreak
                                     when @nStreak > @nMaxStreak then @nStreak
                                     else @nMaxStreak end MaxStreak,

              @nMaxStreakPoints := case when PreOrd.Player != @cLastPlayer then @nStreakPoints
                                        when @nStreak >= @nMaxStreak and @nStreakPoints > @nMaxStreakPoints then @nStreakPoints
                                        else @nMaxStreakPoints end MaxStreakPoints,

              @cLastPlayer := PreOrd.Player PlayerChange
         FROM 
              ( select
                      S.Player,
                      S.TimeStamp,
                      S.Points
                   from 
                      Scores2 S
                   ORDER BY 
                      S.Player,
                      S.TimeStamp,
                      S.`index` ) PreOrd,
              ( select
                      @nStreak := 0,
                      @nStreakPoints := 0,
                      @nMaxStreak := 0,
                      @nMaxStreakPoints := 0,
                      @cLastPlayer := '~' ) SQLVars
      ) as Final
   group by 
      Final.Player 

さて、これは偽の最大連勝ポイントを与える可能性があります。たとえば、1 つのスコアでその人が 90 ポイントを獲得し、10 ポイントの場合は 1、10 ポイントの場合は 2、10 ポイントの場合は 3、合計 30 の連勝になります。けれど... :)

index提供されたデータから利用可能にした列 を追加すると、次のようになりますここに画像の説明を入力

SQL Fiddle 私のソリューションを表示しています...

于 2012-12-04T18:17:48.347 に答える
0

ストリークを計算するときに追加情報を保存することをお勧めします。たとえば、ストリークが始まったときのタイム スタンプを保存できます。

あまり深刻ではない推奨事項は、ウィンドウ関数をサポートする別のデータベースに切り替えることです。これははるかに簡単です。

アプローチは、ストリークがいつ始まったかを見つけ、その時間から最大ストリークまでのすべてを合計することです。これを行うには、相関サブクエリを使用します。

select t.*,
       (select max(timestamp) from t t2 where t2.timestamp <= t.timestamp and t2.player = t.player and t2.streak = 0
       ) as StreakStartTimeStamp
from t
where t.timeStamp = (select max(streak) from t t2 where t.player = t2.player)

ここで、このクエリをサブクエリとして埋め込み、適切な時間を追加できるようにします。

select t.player,
       sum(s.points)
from t join
     (select t.*,
             (select max(timestamp) from t t2 where t2.timestamp <= t.timestamp and t2.player = t.player and t2.streak = 0
             ) as StreakStartTimeStamp
      from t
      where t.streak = (select max(streak) from t t2 where t.player = t2.player)
     ) s
     on t.player = s.player
group by t.player

このクエリはまだテストしていないため、構文エラーがある可能性があります。ただし、このアプローチは機能するはずです。パフォーマンス上の理由から、テーブル、ストリーク、およびタイムスタンプにインデックスを付けたい場合があります。

于 2012-12-04T17:09:26.737 に答える