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 

现在,这可能会给出一个错误的最大连续点数,例如,在一个分数上,这个人有 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 回答