PHP/MySQL - 取得连胜
PHP/MySQL - Get Winning Streak
我正在尝试展示用户连胜记录,但我正在努力思考如何编写它 - 甚至是概念。
这是一个例子(从最新到最旧)db:
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”来表示连胜记录,因为用户在 id 3 上输了时出现中断
当前连胜的可能解决方案:找到玩家获胜的所有比赛,但前提是之后没有失败:
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 */
)
我理解你的问题是一个间隙和孤岛问题,你想将 "adjacent" 行组合在一起。
这是一种使用行号之间的差异来定义组的方法(这需要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
| win_id | no_wins | start_id | end_id |
| ------ | ------- | -------- | ------ |
| 123 | 2 | 1 | 2 |
这将显示用户 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 |
db<>fiddle here
我正在尝试展示用户连胜记录,但我正在努力思考如何编写它 - 甚至是概念。
这是一个例子(从最新到最旧)db:
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”来表示连胜记录,因为用户在 id 3 上输了时出现中断
当前连胜的可能解决方案:找到玩家获胜的所有比赛,但前提是之后没有失败:
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 */
)
我理解你的问题是一个间隙和孤岛问题,你想将 "adjacent" 行组合在一起。
这是一种使用行号之间的差异来定义组的方法(这需要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
| win_id | no_wins | start_id | end_id |
| ------ | ------- | -------- | ------ |
| 123 | 2 | 1 | 2 |
这将显示用户 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 |
db<>fiddle here