Mysql 一队连胜

Mysql 一队连胜,mysql,sql,Mysql,Sql,我有一个SQL查询,返回关于单个团队的下表: date gameid pointsfor pointsagainst 2011-03-20 15 1 10 2011-03-27 17 7 3 2011-04-03 23 6 5 2011-04-10 30 5 4 2011-04-17

我有一个SQL查询,返回关于单个团队的下表:

date         gameid     pointsfor     pointsagainst

2011-03-20   15         1             10
2011-03-27   17         7             3
2011-04-03   23         6             5
2011-04-10   30         5             4
2011-04-17   35         4             8
2011-05-01   38         8             1
2011-05-08   43         3             7
2011-05-15   48         6             2
2011-05-22   56         10            2
2011-05-29   59         4             5
2011-06-05   65         2             3
2011-06-19   71         5             6
2011-06-19   74         12            2
2011-06-19   77         5             2
2011-06-19   80         5             4
从这张表中,谁能帮我计算一下最长的连胜和连胜是多少


我在这里看了一些其他的例子,但是很难理解它们,因为它们和我的不太一样。任何帮助都将不胜感激。谢谢

您在这里处理的是跟踪胜负趋势,这需要使用某种运行计数器的循环来计算,而不是SQL。SQL查询处理单个行、分组、排序等;您正在尝试使用一种不用于解决此类问题的语言。

您必须创建一个光标,读取所有行,计算数据。。。每次你想获得最长的连胜

我建议采取一种变通办法,使事情变得更容易。 您可以在表中为streakFor添加一列。每次插入一行时:

//pseudo code
if pointsFor > pointsAgainst
    if last_streakFor > 0 
        then streakFor++ 
        else streakFor = 1

else
    if last_streakFor > 0 
        then streakFor = -1 
        else streakFor--
last_streakFor是最后插入的行中的streakFor 然后插入带有列streakFor的行

现在你可以

从表格中选择maxstreakFor,在该表格中,您的条件将为pointsFor提供最长的连胜记录和pointsAgainst提供最长的连败记录 从您的表格中选择Minstreak,在该表格中,您的条件将为您提供最长的积分连胜和最长的积分连败
有一个解决方案,但我认为您不会喜欢它,因为它需要一个自连接,并且您的表不是表而是查询

内部查询将日期转换为范围,即它将为表中的每个日期查找具有不同结果的第一个日期,或者,对于最后一个游戏,查找此游戏的日期。该数据将按不同条纹的第一个日期进行聚合,以展平和计数条纹;外部查询然后按结果查找极值

select case Outcome 
            when -1 then 'Losses'
            when 1 then 'Wins'
            else 'Undecided'
        end Title
      , max(Streak) Streak
from
(
  select min(date) date, date_to, Outcome, count(*) Streak
  from
  (
    select t1.date, 
           sign (t1.pointsfor - t1.pointsagainst) Outcome, 
           ifnull (min(t2.date), t1.date) date_to
     from table1 t1
     left join table1 t2
       on t1.date < t2.date
      and sign (t1.pointsfor - t1.pointsagainst) 
       <> sign (t2.pointsfor - t2.pointsagainst)
    group by t1.date, sign (t1.pointsfor - t1.pointsagainst)
  ) a
  group by date_to, Outcome
) a
group by Outcome
为了避免用可能很麻烦的查询替换表1,您可以使用临时表,或者在辅助表中以适当的格式保存数据。
在上有一个实时测试,以及另一个子查询驱动的版本,可能会执行得更好。您应该同时尝试这两个版本。

您必须实现一些MySQL变量,以帮助比多个查询/加入/分组更有效地处理此问题。这有一个单一的通过所有记录,然后再次获得最大每种类型的赢/输或平局。我假设你提供的数据是一次性的,日期是比赛的明显顺序。。。得分对象是你感兴趣的球队,得分对象是对手。也就是说,我的别名将是YourResultingleTeam

内部查询将预先确定游戏状态为赢或输。然后,查看该值是否与团队的上一个实例相同。如果是,则在现有赢/输计数器中添加1。如果不是,则将计数器设置回1。然后,将当前游戏的状态保留回LastStatus值,以便与下一个游戏进行比较

完成后,这是一个简单的游戏结果,max按游戏结果状态分组

select
      StreakSet.GameResult,
      MAX( StreakSet.WinLossStreak ) as MaxStreak
   from
      ( select YR.Date,
               @CurStatus := if( YR.PointsFor > YR.PointsAgainst, 'W', 'L' ) as GameResult,
               @WinLossSeq := if( @CurStatus = @LastStatus, @WinLossSeq +1, 1 ) as WinLossStreak,
               @LastStatus := @CurStatus as carryOverForNextRecord
            from 
               YourResultSingleTeam YR,
               ( select @CurStatus := '',
                        @LastStatus := '',
                        @WinLossSeq := 0 ) sqlvars
            order by
               YR.Date ) StreakSet
   group by
      StreakSet.GameResult

尼古拉提供的,如果你想考虑TIG游戏,我们可以通过只将@ CurSturn改为CASE(条件为

)来进行调整。
@CurStatus := case when YR.PointsFor > YR.PointsAgainst then 'W'
                   when YR.PointsFor < YR.PointsAgainst then 'L'
                   else 'T' end as GameResult,

MySQL没有CTE或窗口功能,例如SUM OVER、ROW_NUMBER OVER等,但它有一个补偿因子。变数

使用以下命令:

select 
   min(date) as start_date,
   max(date) as end_date,
   count(date) as streak,
   group_concat(gameid) as gameid_list
from
( 
  select *,      
    IF(
        pointsfor > pointsagainst 
        and 
        @pointsfor > @pointsagainst, 
           @gn, @gn := @gn + 1)                
    as group_number,

    @date as old_date, @gameid as old_gameid, 
    @pointsfor as old_pointsfor,
    @pointsagainst as old_pointsagainst,

    @date := date, @gameid := gameid, 
    @pointsfor := pointsfor, @pointsagainst := pointsagainst      
  from tbl
  cross join 
  (
    select 
      @date := CAST(null as date) as xa,
      @gameid := null + 0 as xb, -- why CAST(NULL AS INT) doesn't work?
      @pointsfor := null + 0 as xc, @pointsagainst := null + 0 as xd, @gn := 0
  ) x
  order by date
) as y
group by group_number
order by streak desc;
输出:

START_DATE                    END_DATE                      STREAK  GAMEID_LIST
March, 27 2011 08:00:00-0700  April, 10 2011 08:00:00-0700  3       17,23,30
June, 19 2011 08:00:00-0700   June, 19 2011 08:00:00-0700   3       74,77,80
May, 15 2011 08:00:00-0700    May, 22 2011 08:00:00-0700    2       48,56
March, 20 2011 08:00:00-0700  March, 20 2011 08:00:00-0700  1       15
April, 17 2011 08:00:00-0700  April, 17 2011 08:00:00-0700  1       35
May, 01 2011 08:00:00-0700    May, 01 2011 08:00:00-0700    1       38
May, 08 2011 08:00:00-0700    May, 08 2011 08:00:00-0700    1       43
May, 29 2011 08:00:00-0700    May, 29 2011 08:00:00-0700    1       59
June, 05 2011 08:00:00-0700   June, 05 2011 08:00:00-0700   1       65
June, 19 2011 08:00:00-0700   June, 19 2011 08:00:00-0700   1       71
date                |gameid |pointsfor |pointsagainst |is_winner |is_new_group |streak_group |
--------------------|-------|----------|--------------|----------|-------------|-------------|
2011-03-20 15:00:00 |15     |1         |10            |0         |1            |1            |
2011-03-27 15:00:00 |17     |7         |3             |1         |1            |2            |
2011-04-03 15:00:00 |23     |6         |5             |1         |0            |2            |
2011-04-10 15:00:00 |30     |5         |4             |1         |0            |2            |
2011-04-17 15:00:00 |35     |4         |8             |0         |1            |3            |
2011-05-01 15:00:00 |38     |8         |1             |1         |1            |4            |
2011-05-08 15:00:00 |43     |3         |7             |0         |1            |5            |
2011-05-15 15:00:00 |48     |6         |2             |1         |1            |6            |
2011-05-22 15:00:00 |56     |10        |2             |1         |0            |6            |
2011-05-29 15:00:00 |59     |4         |5             |0         |1            |7            |
2011-06-05 15:00:00 |65     |2         |3             |0         |1            |8            |
2011-06-19 15:00:00 |74     |12        |2             |1         |1            |9            |
2011-06-19 15:00:00 |77     |5         |2             |1         |0            |9            |
2011-06-19 15:00:00 |80     |5         |4             |1         |0            |9            |
2011-06-19 15:00:00 |71     |5         |6             |0         |1            |10           |
start_date          |end_date            |streak |gameid_list |
--------------------|--------------------|-------|------------|
2011-03-27 15:00:00 |2011-04-10 15:00:00 |3      |17,23,30    |
2011-06-19 15:00:00 |2011-06-19 15:00:00 |3      |74,77,80    |
2011-05-15 15:00:00 |2011-05-22 15:00:00 |2      |48,56       |
2011-03-20 15:00:00 |2011-03-20 15:00:00 |1      |15          |
2011-04-17 15:00:00 |2011-04-17 15:00:00 |1      |35          |
2011-05-01 15:00:00 |2011-05-01 15:00:00 |1      |38          |
2011-05-08 15:00:00 |2011-05-08 15:00:00 |1      |43          |
2011-05-29 15:00:00 |2011-05-29 15:00:00 |1      |59          |
2011-06-05 15:00:00 |2011-06-05 15:00:00 |1      |65          |
2011-06-19 15:00:00 |2011-06-19 15:00:00 |1      |71          |
现场测试:


注意,在我的SQLFIDLE解决方案中,它有两个查询。1.模拟在顶部。2.下面是最后一个问题

谢谢大家的帮助。我最终按照建议使用php进行循环。如果有人想知道,这是我的代码:

$streakSQL = "SELECT date, gameid, pointsfor, pointsagainst FROM result WHERE teamid = ".$_GET['teamid']." AND bye = 0 AND COMPLETED = 1 AND seasonid > 7 AND roundwd = 0 AND (pointsfor != 0 OR pointsagainst != 0)";
            $streak = mysql_query($streakSQL);

            $winstreak = 0;
            $maxwinstreak = 0;
            $losestreak = 0;
            $maxlosestreak = 0;
            while($streakRow = mysql_fetch_array($streak))
            {
                //calculate winning streak
                if($streakRow['pointsfor'] > $streakRow['pointsagainst'])
                { 
                    $winstreak++; 
                    if($winstreak > $maxwinstreak)
                    {
                        $maxwinstreak = $winstreak;
                    }
                }
                else{ $winstreak = 0; }
                //calculate losing streak
                if($streakRow['pointsfor'] < $streakRow['pointsagainst'])
                { 
                    $losestreak++; 
                    if($losestreak > $maxlosestreak)
                    {
                        $maxlosestreak = $losestreak;
                    }
                }
                else{ $losestreak = 0; }
            }
            echo "Biggest Winning Streak: ".$maxwinstreak;
            echo "<br />Biggest Losing Streak: ".$maxlosestreak;

最新版本的MySQL具有CTE,并支持窗口功能

这里有一个解决方案

第一步,通过给他们分配自己的连胜组号码来分组输赢:

with t as 
(
    select
        *,      
        pointsfor - pointsagainst > 0 is_winner,
        case when pointsfor - pointsagainst > 0 
            and lag(pointsfor) over(order by date, pointsfor - pointsagainst desc) 
                - lag(pointsagainst) over(order by date, pointsfor - pointsagainst desc) > 0 
        then
            0
        else
            1
        end as is_new_group
    from tbl
)
select *, sum(is_new_group) over(order by date, pointsfor - pointsagainst desc) as streak_group
from t
输出:

START_DATE                    END_DATE                      STREAK  GAMEID_LIST
March, 27 2011 08:00:00-0700  April, 10 2011 08:00:00-0700  3       17,23,30
June, 19 2011 08:00:00-0700   June, 19 2011 08:00:00-0700   3       74,77,80
May, 15 2011 08:00:00-0700    May, 22 2011 08:00:00-0700    2       48,56
March, 20 2011 08:00:00-0700  March, 20 2011 08:00:00-0700  1       15
April, 17 2011 08:00:00-0700  April, 17 2011 08:00:00-0700  1       35
May, 01 2011 08:00:00-0700    May, 01 2011 08:00:00-0700    1       38
May, 08 2011 08:00:00-0700    May, 08 2011 08:00:00-0700    1       43
May, 29 2011 08:00:00-0700    May, 29 2011 08:00:00-0700    1       59
June, 05 2011 08:00:00-0700   June, 05 2011 08:00:00-0700   1       65
June, 19 2011 08:00:00-0700   June, 19 2011 08:00:00-0700   1       71
date                |gameid |pointsfor |pointsagainst |is_winner |is_new_group |streak_group |
--------------------|-------|----------|--------------|----------|-------------|-------------|
2011-03-20 15:00:00 |15     |1         |10            |0         |1            |1            |
2011-03-27 15:00:00 |17     |7         |3             |1         |1            |2            |
2011-04-03 15:00:00 |23     |6         |5             |1         |0            |2            |
2011-04-10 15:00:00 |30     |5         |4             |1         |0            |2            |
2011-04-17 15:00:00 |35     |4         |8             |0         |1            |3            |
2011-05-01 15:00:00 |38     |8         |1             |1         |1            |4            |
2011-05-08 15:00:00 |43     |3         |7             |0         |1            |5            |
2011-05-15 15:00:00 |48     |6         |2             |1         |1            |6            |
2011-05-22 15:00:00 |56     |10        |2             |1         |0            |6            |
2011-05-29 15:00:00 |59     |4         |5             |0         |1            |7            |
2011-06-05 15:00:00 |65     |2         |3             |0         |1            |8            |
2011-06-19 15:00:00 |74     |12        |2             |1         |1            |9            |
2011-06-19 15:00:00 |77     |5         |2             |1         |0            |9            |
2011-06-19 15:00:00 |80     |5         |4             |1         |0            |9            |
2011-06-19 15:00:00 |71     |5         |6             |0         |1            |10           |
start_date          |end_date            |streak |gameid_list |
--------------------|--------------------|-------|------------|
2011-03-27 15:00:00 |2011-04-10 15:00:00 |3      |17,23,30    |
2011-06-19 15:00:00 |2011-06-19 15:00:00 |3      |74,77,80    |
2011-05-15 15:00:00 |2011-05-22 15:00:00 |2      |48,56       |
2011-03-20 15:00:00 |2011-03-20 15:00:00 |1      |15          |
2011-04-17 15:00:00 |2011-04-17 15:00:00 |1      |35          |
2011-05-01 15:00:00 |2011-05-01 15:00:00 |1      |38          |
2011-05-08 15:00:00 |2011-05-08 15:00:00 |1      |43          |
2011-05-29 15:00:00 |2011-05-29 15:00:00 |1      |59          |
2011-06-05 15:00:00 |2011-06-05 15:00:00 |1      |65          |
2011-06-19 15:00:00 |2011-06-19 15:00:00 |1      |71          |
最后一个问题。计算连续获胜的次数:

with t as 
(
    select
        *,      
        pointsfor - pointsagainst > 0 is_winner,
        case when pointsfor - pointsagainst > 0 
            and lag(pointsfor) over(order by date, pointsfor - pointsagainst desc) 
                - lag(pointsagainst) over(order by date, pointsfor - pointsagainst desc) > 0 
        then
            0
        else
            1
        end as is_new_group
    from tbl
)
, streak_grouping as
(
    select
        *, sum(is_new_group) over(order by date, pointsfor - pointsagainst desc) as streak_group
    from t
)
select 
    min(date) as start_date,
    max(date) as end_date,
    count(*) as streak,
    group_concat(gameid order by gameid) as gameid_list
from streak_grouping
group by streak_group
order by streak desc, start_date
输出:

START_DATE                    END_DATE                      STREAK  GAMEID_LIST
March, 27 2011 08:00:00-0700  April, 10 2011 08:00:00-0700  3       17,23,30
June, 19 2011 08:00:00-0700   June, 19 2011 08:00:00-0700   3       74,77,80
May, 15 2011 08:00:00-0700    May, 22 2011 08:00:00-0700    2       48,56
March, 20 2011 08:00:00-0700  March, 20 2011 08:00:00-0700  1       15
April, 17 2011 08:00:00-0700  April, 17 2011 08:00:00-0700  1       35
May, 01 2011 08:00:00-0700    May, 01 2011 08:00:00-0700    1       38
May, 08 2011 08:00:00-0700    May, 08 2011 08:00:00-0700    1       43
May, 29 2011 08:00:00-0700    May, 29 2011 08:00:00-0700    1       59
June, 05 2011 08:00:00-0700   June, 05 2011 08:00:00-0700   1       65
June, 19 2011 08:00:00-0700   June, 19 2011 08:00:00-0700   1       71
date                |gameid |pointsfor |pointsagainst |is_winner |is_new_group |streak_group |
--------------------|-------|----------|--------------|----------|-------------|-------------|
2011-03-20 15:00:00 |15     |1         |10            |0         |1            |1            |
2011-03-27 15:00:00 |17     |7         |3             |1         |1            |2            |
2011-04-03 15:00:00 |23     |6         |5             |1         |0            |2            |
2011-04-10 15:00:00 |30     |5         |4             |1         |0            |2            |
2011-04-17 15:00:00 |35     |4         |8             |0         |1            |3            |
2011-05-01 15:00:00 |38     |8         |1             |1         |1            |4            |
2011-05-08 15:00:00 |43     |3         |7             |0         |1            |5            |
2011-05-15 15:00:00 |48     |6         |2             |1         |1            |6            |
2011-05-22 15:00:00 |56     |10        |2             |1         |0            |6            |
2011-05-29 15:00:00 |59     |4         |5             |0         |1            |7            |
2011-06-05 15:00:00 |65     |2         |3             |0         |1            |8            |
2011-06-19 15:00:00 |74     |12        |2             |1         |1            |9            |
2011-06-19 15:00:00 |77     |5         |2             |1         |0            |9            |
2011-06-19 15:00:00 |80     |5         |4             |1         |0            |9            |
2011-06-19 15:00:00 |71     |5         |6             |0         |1            |10           |
start_date          |end_date            |streak |gameid_list |
--------------------|--------------------|-------|------------|
2011-03-27 15:00:00 |2011-04-10 15:00:00 |3      |17,23,30    |
2011-06-19 15:00:00 |2011-06-19 15:00:00 |3      |74,77,80    |
2011-05-15 15:00:00 |2011-05-22 15:00:00 |2      |48,56       |
2011-03-20 15:00:00 |2011-03-20 15:00:00 |1      |15          |
2011-04-17 15:00:00 |2011-04-17 15:00:00 |1      |35          |
2011-05-01 15:00:00 |2011-05-01 15:00:00 |1      |38          |
2011-05-08 15:00:00 |2011-05-08 15:00:00 |1      |43          |
2011-05-29 15:00:00 |2011-05-29 15:00:00 |1      |59          |
2011-06-05 15:00:00 |2011-06-05 15:00:00 |1      |65          |
2011-06-19 15:00:00 |2011-06-19 15:00:00 |1      |71          |

你能提供模式和数据吗?模式非常复杂,所以我认为我当前的select查询返回了上面显示的所有必需数据。有没有其他有用的数据?我期望的输出是:-这个特定团队拥有的最长连胜记录,例如,这个团队在gameid=17、23和30时获胜,所以三个连胜记录是最长连胜记录-我不介意这些是单独的问题,我想+9999@johntotetwoo发表评论ツ我想要的输出最初只是一些非常基本的东西,比如:`winstreak 6',但现在我看到了你的查询Michael,我真的很喜欢它给出了日期和游戏列表。哦,天哪,我想这就是DBA保证工作安全的方式。@Len,尊敬的,查询确实有效。。。然而,对于MySQL来说,这很难理解。。。对自身进行连接将实现重复处理,比较1到???,然后2到???,然后3到???,等等。。。完成后,再次选择group by,只需对max streak执行另一个group by
总的来说,有些问题不适合基于集合的方法@MichaelBuen是的,我知道。这正是我们有窗口函数的原因,特别是Oracle中的滞后和超前。我不使用MySql,但在四个小时内我必须像其他人那样回答问题,所以我提供了纯SQL解决方案。但感谢您的关注。只是一个温和的提醒:-此查询不完全适合生产;若表中有1000行,查询将遍历行500500次。就像Adam Machanic解释的那样,不再跑步了。符合ANSI SQL 2008的数据库现在同样能够解决这个问题,这可以通过CTE和窗口函数组合来解决。请参阅此问题的另一个示例:以防您仍然想知道为什么CASTNULL作为INT不起作用:。我无法获取它:D无论如何,它可以在其他数据库上工作,例如。可悲的是,我不能。幸运的是,有一个解决办法:简单地说,MySQL中的CAST和CONVERT函数接受的类型名与用于声明变量和列的类型名稍有不同。对我来说,这似乎完全违反直觉,但事实似乎就是这样。嗨,Michahel,我正在我的查询浏览器中运行你的查询,遇到了一个问题。由于某些原因,当我运行一次时,它会返回不正确的数据,但如果我再次单击“运行”,它会返回正确的数据。你知道为什么会这样吗?再次感谢!另外,如果有问题,我已经用返回表的查询替换了tbl:选择日期、gameid、pointsfor、pointsagainst FROM result,其中teamid=6,bye=0,COMPLETED=1,seasonid>7,roundwd=0,pointsfor!=0或点SAGAINST!=0和游戏类型!='友好的“按日期ASC订购”作为帮助德拉普的tblThanks。不幸的是,当我使用您的查询时,结果表总是显示为:L 1 W 1我唯一更改的是用我的查询替换YourResultingleTeam,该查询返回我在问题中指定的表。选择日期、gameid、pointsfor、pointsagainst FROM result,其中teamid=6,bye=0,COMPLETED=1,seasonid>7,roundwd=0,pointsfor!=0或点SAGAINST!=0和游戏类型!='友好的订单日期ASC为您我做错什么了吗?再次感谢@格雷姆·考贝勒,我的错。。忘记WinLossStream上IF的+1。。。虽然我之前有I+1,但效率肯定更高: