Предположим, у меня есть игра, в которую могут играть 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 строки с игроками в правильном порядке и количестве?
Это, по-видимому, должно быть решением проблемы в других контекстах. Полюбуется всякая помощь здесь.
Я настоятельно советую вам * не * mix ',' и 'JOIN'. Просто используйте 'JOIN', это не 20 лет от даты ... – MatBailie