PHP / MySQL - Get Winning Streak - PullRequest
       9

PHP / MySQL - Get Winning Streak

1 голос
/ 06 апреля 2020

Я пытаюсь отобразить серию выигрышей для пользователя, но я изо всех сил пытаюсь понять, как бы я это написал - даже концепцию.

Вот пример (от самого нового до самого старого) БД:

id | win_id| loss_id| player id
1  |  123  | 999    | 123
2  |  123  | 999    | 123
3  |  999  | 123    | 123
4  |  123  | 999    | 123

То, что я хочу отобразить, - это победная серия для player_id: 123 - так, для выигрышной полосы должно появиться «2», потому что произошел перерыв, когда пользователь проиграл с идентификатором 3

Ответы [ 3 ]

1 голос
/ 06 апреля 2020

Я понимаю ваш вопрос как проблему пробелов и островов, когда вы хотите сгруппировать «смежные» строки.

Вот подход, использующий разницу между номерами строк для определения групп (для этого требуется MySQL 8,0); затем мы можем агрегировать по выигрышным полосам, сортировать по длине по убыванию и сохранять только верхнюю полосу:

select win_id, count(*) no_wins, min(id) start_id, max(id) end_id
from (
    select 
        t.*,
        row_number() over(partition by player_id order by id) rn1,
        row_number() over(partition by player_id, win_id order by id) rn2
    from mytable t
    where player_id = 123
) t
where win_id = 123
group by win_id, rn1 - rn2
order by no_wins desc
limit 1

Демонстрация на DB Fiddle :

| win_id | no_wins | start_id | end_id |
| ------ | ------- | -------- | ------ |
| 123    | 2       | 1        | 2      |
1 голос
/ 06 апреля 2020

Это показало бы самые высокие полосы выигрыша для пользователя. 123 Это работает с mysql 5.x

. Я добавил некоторые данные, чтобы показать, что он делает

CREATE TABLE wintable (
  `id` INTEGER,
  `win_id` INTEGER,
  `loss_id` INTEGER,
  `player id` INTEGER
);

INSERT INTO wintable
  (`id`, `win_id`, `loss_id`, `player id`)
VALUES
  ('1', '123', '999', '123'),
  ('2', '123', '999', '123'),
    ('3', '123', '777', '123'),
  ('4', '123', '777', '123'),
  ('5', '999', '123', '123'),
  ('6', '123', '999', '123'),
    ('7', '123', '999', '123'),
  ('8', '123', '999', '123'),
    ('9', '123', '777', '123'),
  ('10', '123', '777', '123'),
  ('11', '123', '999', '123'),
  ('12', '123', '999', '123'),
    ('13', '123', '777', '123'),
  ('14', '123', '777', '123'),
  ('15', '999', '123', '123');
✓

✓
SELECT 
    id,
    IF(`loss_id` <> 123,
        @num:=@num + 1,
        @num:=0) winstreek
FROM
    (SELECT 
        *
    FROM
        wintable
    WHERE
        `player id` = 123
    ORDER BY `id`) t1,
    (SELECT @num:=0) a
id | winstreek
-: | --------:
 1 |         1
 2 |         2
 3 |         3
 4 |         4
 5 |         0
 6 |         1
 7 |         2
 8 |         3
 9 |         4
10 |         5
11 |         6
12 |         7
13 |         8
14 |         9
15 |         0
SELECT MAX(winstreek) winstreek
FROM 
(SELECT 
    id,
    IF(`loss_id` <> 123,
        @num:=@num + 1,
        @num:=0) winstreek
FROM
    (SELECT 
        *
    FROM
        wintable
    WHERE
        `player id` = 123
    ORDER BY `id`) t1,
    (SELECT @num:=0) a) b;
| winstreek |
| --------: |
|         9 |

дБ <> скрипка здесь

1 голос
/ 06 апреля 2020

Возможное решение для текущей серии побед: найти все матчи, в которых игрок выиграл, но только если поражение не произойдет позже:

SELECT COUNT(t.id)
  FROM table t
 WHERE t.player_id = 123
   AND t.win_id = 123 /* player 123 won */
   AND NOT EXISTS(SELECT * 
                    FROM table t2
                   WHERE t2.player_id = 123
                     AND t2.win_id <> 123 /* player 123 lost */
                 AND t2.id > t.id /* lost occur after the win we look at */
              )   
...