3

I have a table like below:

id     homeTeam    awayTeam   homeScore    awayScore
1         t1          t2          3            2
2         t3          t7          0            1
.          .           .          .            .
.          .           .          .            .
.          .           .          .            .

which is a Soccer match results from a loocal league. I wanna get "longest win streak", "longest lose streak" and ........ with just a query. I looked around and found the oracle version, but I couldn't find out how to do this? PS: I have mysql database. thanks in advance

Andriy M
  • 76,112
  • 17
  • 94
  • 154
Ehphan
  • 537
  • 3
  • 7
  • 19
  • 1
    Can you post the Oracle query you found? It might help to have that and translate it to MySQL, although it will probably be hard, since MySQL doesn't have the analytical capabilities of Oracle. – GolezTrol Nov 17 '13 at 08:50
  • 1
    Post the oracle query.. – Joke_Sense10 Nov 17 '13 at 08:55
  • http://stackoverflow.com/questions/16862517/find-the-maximum-consecutive-years-for-each-ids-in-a-tableoracle-sql – Ehphan Nov 17 '13 at 09:11
  • http://stackoverflow.com/questions/18978212/grouping-and-counting – Ehphan Nov 17 '13 at 09:12
  • A streak is an uninterrupted list of wins or loses, right? What defines the sort order? The table looks like it only has 'id' to sort by, but an id (surrogate key) should not be used for sorting. – GolezTrol Nov 17 '13 at 09:27
  • no it also has a held_date column and some other columns, but to make it short, I removed them from question. – Ehphan Nov 17 '13 at 09:38
  • I think the surrogate key will be fine for illustrative purposes – Strawberry Nov 17 '13 at 11:47
  • Can teams draw? And if so, would a draw end a streak. – Strawberry Nov 17 '13 at 13:26
  • ofcourse, and if they do depending on streak type (longest unbeated or longest win) it can end streak or not!!! – Ehphan Nov 17 '13 at 14:00
  • 1
    Add the `gaps-and-islands` tag. You may want look through [existing MySQL "gaps and islands" questions](http://stackoverflow.com/questions/tagged/gaps-and-islands+mysql) too. – Andriy M Nov 17 '13 at 14:18

1 Answers1

5

Here's one way, but I've got a feeling you're not going to like it...

Consider the following data DDL's...

CREATE TABLE results
(id     INT NOT NULL AUTO_INCREMENT PRIMARY KEY
,homeTeam    INT NOT NULL
,awayTeam    INT NOT NULL
,homeScore    INT NOT NULL
,awayScore INT NOT NULL
);

INSERT INTO results VALUES
(1,1,2,3,2),
(2,3,4,0,1),
(3,2,1,2,0),
(4,4,3,1,0),
(5,3,2,1,2),
(6,2,3,0,2),
(7,1,4,4,1),
(8,4,1,1,2),
(9,1,3,3,0),
(10,3,1,1,0),
(11,4,2,1,0),
(12,2,4,1,2);

From here, we can obtain an intermediate result as follows...

SELECT x.*, COUNT(*) rank
  FROM
     ( SELECT id,hometeam team, CASE WHEN homescore > awayscore THEN 'w' ELSE 'l' END result FROM results 
       UNION
       SELECT id,awayteam, CASE WHEN awayscore > homescore THEN 'w' ELSE 'l' END result FROM results
     ) x
  JOIN 
     ( SELECT id,hometeam team, CASE WHEN homescore > awayscore THEN 'w' ELSE 'l' END result FROM results 
       UNION
       SELECT id,awayteam, CASE WHEN awayscore > homescore THEN 'w' ELSE 'l' END result FROM results
     ) y
    ON y.team = x.team
   AND y.id <= x.id
 GROUP
    BY x.id
     , x.team
 ORDER
    BY team, rank;

+----+------+--------+------+
| id | team | result | rank |
+----+------+--------+------+
|  1 |    1 | w      |    1 |
|  3 |    1 | l      |    2 |
|  7 |    1 | w      |    3 |
|  8 |    1 | w      |    4 |
|  9 |    1 | w      |    5 |
| 10 |    1 | l      |    6 |
|  1 |    2 | l      |    1 |
|  3 |    2 | w      |    2 |
|  5 |    2 | w      |    3 |
|  6 |    2 | l      |    4 |
| 11 |    2 | l      |    5 |
| 12 |    2 | l      |    6 |
|  2 |    3 | l      |    1 |
|  4 |    3 | l      |    2 |
|  5 |    3 | l      |    3 |
|  6 |    3 | w      |    4 |
|  9 |    3 | l      |    5 |
| 10 |    3 | w      |    6 |
|  2 |    4 | w      |    1 |
|  4 |    4 | w      |    2 |
|  7 |    4 | l      |    3 |
|  8 |    4 | l      |    4 |
| 11 |    4 | w      |    5 |
| 12 |    4 | w      |    6 |
+----+------+--------+------+

By inspection, we can see that team 1 has the longest winning streak (3 consecutive 'w's). You can set up a couple of @vars to track this or, if you're slightly masochistic (like me) you can do something slower, longer, and more complicated...

SELECT a.team
     , MIN(c.rank) - a.rank + 1 streak
  FROM (SELECT x.*, COUNT(*) rank
  FROM
     ( SELECT id,hometeam team, CASE WHEN homescore > awayscore THEN 'w' ELSE 'l' END result FROM results 
       UNION
       SELECT id,awayteam, CASE WHEN awayscore > homescore THEN 'w' ELSE 'l' END result FROM results
     ) x
  JOIN 
     ( SELECT id,hometeam team, CASE WHEN homescore > awayscore THEN 'w' ELSE 'l' END result FROM results 
       UNION
       SELECT id,awayteam, CASE WHEN awayscore > homescore THEN 'w' ELSE 'l' END result FROM results
     ) y
    ON y.team = x.team
   AND y.id <= x.id
 GROUP
    BY x.id
     , x.team
     ) a
  LEFT 
  JOIN (SELECT x.*, COUNT(*) rank
  FROM
     ( SELECT id,hometeam team, CASE WHEN homescore > awayscore THEN 'w' ELSE 'l' END result FROM results 
       UNION
       SELECT id,awayteam, CASE WHEN awayscore > homescore THEN 'w' ELSE 'l' END result FROM results
     ) x
  JOIN 
     ( SELECT id,hometeam team, CASE WHEN homescore > awayscore THEN 'w' ELSE 'l' END result FROM results 
       UNION
       SELECT id,awayteam, CASE WHEN awayscore > homescore THEN 'w' ELSE 'l' END result FROM results
     ) y
    ON y.team = x.team
   AND y.id <= x.id
 GROUP
    BY x.id
     , x.team
     ) b 
    ON b.team = a.team
   AND b.rank = a.rank - 1 
   AND b.result = a.result
  LEFT 
  JOIN (SELECT x.*, COUNT(*) rank
  FROM
     ( SELECT id,hometeam team, CASE WHEN homescore > awayscore THEN 'w' ELSE 'l' END result FROM results 
       UNION
       SELECT id,awayteam, CASE WHEN awayscore > homescore THEN 'w' ELSE 'l' END result FROM results
     ) x
  JOIN 
     ( SELECT id,hometeam team, CASE WHEN homescore > awayscore THEN 'w' ELSE 'l' END result FROM results 
       UNION
       SELECT id,awayteam, CASE WHEN awayscore > homescore THEN 'w' ELSE 'l' END result FROM results
     ) y
    ON y.team = x.team
   AND y.id <= x.id
 GROUP
    BY x.id
     , x.team
     ) c 
    ON c.team = a.team
   AND c.rank >= a.rank 
   AND c.result = a.result
  LEFT 
  JOIN (SELECT x.*, COUNT(*) rank
  FROM
     ( SELECT id,hometeam team, CASE WHEN homescore > awayscore THEN 'w' ELSE 'l' END result FROM results 
       UNION
       SELECT id,awayteam, CASE WHEN awayscore > homescore THEN 'w' ELSE 'l' END result FROM results
     ) x
  JOIN 
     ( SELECT id,hometeam team, CASE WHEN homescore > awayscore THEN 'w' ELSE 'l' END result FROM results 
       UNION
       SELECT id,awayteam, CASE WHEN awayscore > homescore THEN 'w' ELSE 'l' END result FROM results
     ) y
    ON y.team = x.team
   AND y.id <= x.id
 GROUP
    BY x.id
     , x.team
     ) d 
    ON d.team = a.team
   AND d.rank = c.rank + 1 
   AND d.result = a.result
 WHERE a.result = 'w'
   AND b.id IS NULL
   AND c.id IS NOT NULL
   AND d.id IS NULL
 GROUP 
    BY a.team
     , a.rank
 ORDER 
    BY streak DESC 
 LIMIT 1; 

 +------+--------+
 | team | streak |
 +------+--------+
 |    1 |      3 |
 +------+--------+

Note that this doesn't account for individual match ties (a modest change to the repeated subquery), nor if two teams have longest winning streaks of equal length (requiring a JOIN of everything here back on itself!).

Strawberry
  • 33,750
  • 13
  • 40
  • 57
  • Well you were right, I didn't liked it much, specially beacause it doesn't support draws, but it'll do for now. Thank you!!! It was helpful. – Ehphan Nov 18 '13 at 07:10