Supponiamo di avere un gioco che può essere giocato da 2, 3 o 4 giocatori. Traccio un gioco del genere nel mio database (MySQL 5.1) in tre tabelle, riportate di seguito. Spero che i campi sono auto-esplicativo:Left-join dello stesso tavolo più volte
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);
[I due volte cingolati nella tabella giochi sono l'ora di inizio e di fine]
Ecco alcuni dati fittizi per popolare le tabelle:
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);
Ora, ho bisogno di produrre un report nel seguente formato:
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]
Cioè, un rapporto che mostra tutti i giocatori che hanno giocato una partita nella stessa fila. Ho anche bisogno i loro punteggi e alcune altre informazioni dalla tabella degli utenti, ma che è la fase 2. :-)
ho iniziato con questo:
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
Questo mi ha tutti i giochi in cui sono stati occupati tutti i quattro posti dà (cioè, solo l'ID di gioco 3 nei dati fittizi sopra). Ma questo è solo un sottoinsieme dei dati di cui ho bisogno.
Questo è il mio secondo tentativo:
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
Questo mi dà 14 righe con i dati fittizi di cui sopra. Ho cercato di eliminare una fonte di errore ancorando UG1 alla voce per il giocatore più basso-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
Ora sono fino a 9 righe, ma ho ancora un sacco di dati spuri. Riesco a vedere il problema - che per esempio nel gioco 3, con ug1 ancorato all'utente 102, ci sono ancora tre giocatori ai quali si può ancorare ug2. E così via. Ma non riesco a capire un modo per risolvere questo enigma: come posso ottenere in definitiva una query che produrrà 4 righe con i giocatori nell'ordine e nel numero corretti?
Questo mi sembra dovrebbe essere un problema risolto in altri contesti. Apprezzerò tutto l'aiuto qui.
Io vi consiglio vivamente a * non * mix ',' e 'JOIN' sintassi. Basta usare 'JOIN', non è 20 anni non aggiornato ... – MatBailie