【发布时间】:2011-12-19 16:41:18
【问题描述】:
假设我有一个可以由 2、3 或 4 名玩家玩的游戏。我在我的数据库(MySQL 5.1)中的三个表中跟踪这样的游戏,如下所示。我希望这些字段是不言自明的:
create table users (id int, login char(8));
create table games (id int, stime datetime, etime datetime);
create table users_games (uid int, gid int, score int);
[比赛表中跟踪的两个时间是开始和结束时间]
这里有一些用于填充表格的虚拟数据:
insert into games values
(1, '2011-12-01 10:00:00', '2011-12-01 13:00:00'),
(2, '2011-12-02 11:00:00', '2011-12-01 14:00:00'),
(3, '2011-12-03 12:00:00', '2011-12-01 15:00:00'),
(4, '2011-12-04 13:00:00', '2011-12-01 16:00:00');
insert into users_games values
(101, 1, 10),
(102, 1, 11),
(101, 2, 12),
(103, 2, 13),
(104, 2, 14),
(102, 3, 15),
(103, 3, 16),
(104, 3, 17),
(105, 3, 18),
(102, 4, 19),
(104, 4, 20),
(105, 4, 21);
现在,我需要生成以下格式的报告:
gid p1 p2 p3 p4 started ended
1 101 102 [g1] [g1]
2 101 103 104 [g2] [g2]
3 102 103 104 105 [g3] [g3]
4 102 104 105 [g4] [g4]
也就是说,一份报告显示了在同一行中玩过游戏的所有玩家。我还需要他们的分数和用户表中的一些其他信息,但那是第 2 阶段。:-)
我是从这个开始的:
select g.id, g.stime, g.etime, ug1.uid, ug2.uid, ug3.uid, ug4.uid
from games g, users_games ug1, users_games ug2, users_games ug3, users_games ug4
where
g.id = ug1.gid and
ug1.gid = ug2.gid and
ug1.uid < ug2.uid and
ug2.gid = ug3.gid and
ug2.uid < ug3.uid and
ug3.gid = ug4.gid and
ug3.uid < ug4.uid
这给了我所有四个座位都被占用的游戏(即上述虚拟数据中只有游戏 ID 3)。但这只是我需要的数据的一个子集。
这是我的第二次尝试:
select g.id, g.stime, g.etime, ug1.uid, ug2.uid,
ifnull(ug3.uid, ''), ifnull(ug4.uid, '')
from ( games g, users_games ug1, users_games ug2 )
left join users_games ug3 on ug2.gid = ug3.gid and ug2.uid < ug3.uid
left join users_games ug4 on ug3.gid = ug4.gid and ug3.uid < ug4.uid
where
g.id = ug1.gid and
ug1.gid = ug2.gid and
ug1.uid < ug2.uid
这给了我 14 行上面的虚拟数据。我试图通过将 ug1 锚定到最低 UID 播放器的条目来消除一个错误来源:
select g.id, g.stime, g.etime, ug1.uid, ug2.uid,
ifnull(ug3.uid, ''), ifnull(ug4.uid, '')
from
( games g, users_games ug1, users_games ug2,
(select gid as g, min(uid) as u from users_games group by g) as xx
)
left join users_games ug3 on ug2.gid = ug3.gid and ug2.uid < ug3.uid
left join users_games ug4 on ug3.gid = ug4.gid and ug3.uid < ug4.uid
where
g.id = xx.g and
ug1.uid = xx.u and
g.id = ug1.gid and
ug1.gid = ug2.gid and
ug1.uid < ug2.uid
现在我减少到 9 行,但我仍然有很多虚假数据。我可以看到问题 - 例如在游戏 3 中,ug1 锚定到用户 102,仍然有 ug2 可以锚定到的三个玩家。等等。但是我想不出解决这个难题的方法——我如何最终实现一个查询,以正确的顺序和数量输出 4 行的玩家?
在我看来,这在其他情况下应该是一个已解决的问题。在这里感谢所有帮助。
【问题讨论】:
-
我强烈建议您不要混合使用
,和JOIN语法。就用JOIN吧,没过20年...