Mysql 一队连胜
我有一个SQL查询,返回关于单个团队的下表: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
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,但效率肯定更高: