8

1 つのチームに関する次のテーブルを返す 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

この表から、最長の連勝と連敗を計算するのを手伝ってくれませんか?

ここで他のいくつかの例を見てきましたが、それらは私のものとまったく同じではないため、それらに従うのに苦労しました. どんな助けでも大歓迎です。ありがとう!

4

7 に答える 7

2

複数のクエリ/参加/グループ化よりも効率的にこれを処理できるように、いくつかのMySQL変数を実装する必要があります。これは、すべてのレコードを1回通過し、もう一度、勝ち/負け(または同点)のタイプごとに最大値を取得します。あなたが提供したデータは1回だけで、日付はゲームの明らかな順序であると想定しています... Points Forはあなたが興味を持っているチームであり、反対のポイントは対戦相手が誰であるかです。そうは言っても、私の「エイリアス」名は「YourResultSingleTeam」になります。

内部クエリは、ゲームのステータスを「W」inまたは「L」ossとして事前に決定します。次に、その値がチームの前のインスタンスと同じであるかどうかを確認します。その場合、既存の勝ち負けカウンターに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

Nikolaが提供するように、「タイ」ゲームを検討したい場合は、@CurStatusをcase/when条件に変更するだけで調整できます。

@CurStatus := case when YR.PointsFor > YR.PointsAgainst then 'W'
                   when YR.PointsFor < YR.PointsAgainst then 'L'
                   else 'T' end as GameResult,
于 2012-05-07T12:53:27.187 に答える
1

解決策はありますが、自己結合が必要であり、テーブルはテーブルではなくクエリであるため、気に入らないと思います。

内部クエリは日付を範囲に変換します。つまり、テーブル内の各日付について、結果が異なる最初の日付、または最後の試合の場合はこの試合の日付を見つけます。このデータは、ストリークを平坦化してカウントするために、異なるストリークの最初の日付で集計されます。外側のクエリは、結果によって極値を見つけます。

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

おそらく面倒なクエリに置き換える必要を回避するために、table1一時テーブルを使用するか、補助テーブルにデータを既に適切な形式にすることができます。Sql fiddleでのライブ テストと、パフォーマンスが向上する可能性のある別のサブクエリ駆動型バージョンがあります。両方を試してみてください。

于 2012-05-07T12:12:17.893 に答える
1

MySQL の最新バージョンには CTE があり、ウィンドウ対応です。

これが解決策です。

最初のステップでは、グループの勝者と敗者に独自の streak_group 番号を割り当てます。

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

出力:

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           |

最終クエリ。連勝数を数えます。

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 |
--------------------|--------------------|-------|------------|
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          |
于 2019-03-12T12:24:54.540 に答える
0

ここで扱っているのは、勝敗の傾向を追跡することです。これは、SQL ではなく、実行中のカウンターを使用した何らかのループで計算する必要があります。SQL クエリは、個々の行、グループ化、並べ替えなどを処理します。そのような問題を解決することを意図していない言語を使用しようとしています。

于 2012-05-07T08:24:32.737 に答える
0

カーソルを作成し、すべての行を読み取り、データを計算する必要があります...最長のストリークを取得するたびに...

物事を簡単にする回避策を提案します。テーブル「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 を持つ行を挿入します

今、あなたはすることができます

  • select max(streakFor) from yourTable where yourConditionsこれにより、「pointsFor」の最長連勝と「pointsAgainst」の最長連敗の両方が得られます。
  • select min(streakFor) from yourTable where yourConditions「pointsAgainst」の場合は最長の連勝を、「pointsFor」の場合は最長の連敗を記録します。
于 2012-05-07T08:26:03.957 に答える
0

みんな助けてくれてありがとう。私は提案されたようにループするために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;
于 2012-05-07T15:32:00.130 に答える