2009-10-09 1 views
5

Dichiarazione SQL davvero difficile che ho qui. Cercando di costruire questa query per circa un'ora. Forse puoi aiutarmi.Query ingannevole SQL

Abbiamo una tabella con 3 colonne: nome giocatore | utente | times_played

La query deve selezionare i primi tre giochi (a seconda del tempo totale giocato) e i primi tre utenti che hanno giocato più volte in questo gioco => 9 righe.

The result is like: 
CounterStrike | Smith 
CounterStrike | Jonny 
Counterstrike | Hans 
WoW   | George 
WoW   | Bob 
Wow   | Frank 
Need For Speed| James 
Need For Speed| Marion 
Need For Speed| Scarlet 

sarebbe molto bello, se potesse aiutare =) Grazie!

+0

Cosa database? MySQL? Server SQL? Oracolo? Postgres? – Asaph

+0

Quale tecnologia? MySQL? Server SQL? Puoi usare una stored procedure? –

+0

@foriamstu domanda migliore: * dovresti * usare una stored procedure? Nella mia esperienza, quasi sempre: "no". Sembra utile in quel momento, torna a morderti durante la manutenzione. –

risposta

13

Aggiornamento:

Come @Steve Kass sottolineato, non ho notato che si voleva solo i primi tre giochi.

Ecco la versione aggiornata:

In SQL Server, Oracle e PostgreSQL 8.4:

SELECT gamename, user 
FROM (
     SELECT r.gamename, user, 
       ROW_NUMBER() OVER (PARTITION BY game ORDER BY times_played DESC) rn, 
     FROM (
       SELECT gamename, ROW_NUMBER() OVER (ORDER BY SUM(times_played) DESC) AS game_rn 
       FROM results 
       GROUP BY 
         gamename 
       ) g 
     JOIN results r 
     ON  r.gamename = g.gamename 
     WHERE game_rn <= 3 
     ) q 
WHERE rn <= 3 
ORDER BY 
     gamename, times_played DESC 

In MySQL:

SELECT ro.gamename, ro.user 
FROM (
     SELECT gamename, SUM(times_played) AS rank 
     FROM results 
     ORDER BY 
       rank DESC 
     LIMIT 3 
     ) rd 
JOIN results ro 
ON  ro.gamename >= rd.gamename 
     AND ro.gamename <= rd.gamename 
     AND 
     (ro.times_played, ro.id) <= 
     (
     SELECT ri.times_played, ri.id 
     FROM results ri 
     WHERE ri.gamename = rd.gamename 
     ORDER BY 
       ri.times_played DESC, ri.id DESC 
     LIMIT 2, 1 
     ) 
ORDER BY 
     gamename, times_played DESC 

Avrete bisogno di un PRIMARY KEY per questa query al lavoro, ammesso che si chiama id.

Questo è spiegato più in dettaglio in questo articolo nel mio blog:

In PostgreSQL 8.3 e sotto:

SELECT gamename, ((ri)[s]).user 
FROM (
     SELECT gamename, ri, generate_series(1, 3) AS s 
     FROM (
       SELECT ro.gamename, 
         ARRAY 
         (
         SELECT ri 
         FROM results ri 
         WHERE ri.gamename = ro.gamename 
         ORDER BY 
           times_played DESC 
         LIMIT 3 
         ) AS ri 
       FROM (
         SELECT gamename, SUM(times_played) AS rank 
         FROM results 
         ORDER BY 
           rank DESC 
         LIMIT 3 
         ) rd 
       ) q 
     ) q2 
ORDER BY 
     gamename, s 
+3

Sembra così semplice quando si risponde :-) –

+0

Suppongo che sia "PARTITION BY" –

+0

Avrei lanciato un ordine per Game e rn per essere sicuro che i risultati siano visualizzati nell'ordine corretto. –

1

non credo Quassnoi notato che hai chiesto i migliori utenti solo per i primi tre giochi (in base al totale times_played). Ecco una query per questo (non testato su dati reali, poiché non sono state fornite istruzioni CREATE TABLE e INSERT). Includo anche i legami, che Quassnoi non ha fatto, solo per mostrarti questa opzione.

with GamesPlays(gamename,totalPlays) as (
    select 
    gamename, sum(times_played) 
    from results 
    group by gamename 
), GamesRanked(gamename,gameRank) as (
    select 
    gamename, 
    rank() over (
     order by totalPlays desc 
    ) 
    from GamesPlays 
), ResultsRanked(gamename,user,userRank) as (
    select 
    gamename, 
    user, 
    rank() over (
     partition by user 
     order by times_played desc 
    ) 
    from results; 
) 
    select 
    G.gamename, R.user 
    from ResultsRanked as R 
    join GamesRanked as G 
    on G.gamename = R.gamename 
    where gameRank <= 3 
    and userRank <= 3 
    order by 
    gameRank,userRank; 
+0

Grazie per averlo indicato. Ci sono "12" di upvotes e nessuno ha fatto un commento simile :) – Quassnoi

+0

Forse quello che pubblichi è così raramente sbagliato che la gente pensa che sia una perdita di tempo da guardare da vicino. :) –

0
DROP TABLE #game_stats 


CREATE TABLE #game_stats (gamename VARCHAR(50),users VARCHAR(50),times_played INT); 

INSERT INTO #game_stats VALUES ('Counter Strike','Kamesh',2); 
INSERT INTO #game_stats VALUES ('Counter Strike','Hely',4); 
INSERT INTO #game_stats VALUES ('Counter Strike','Maitri',1); 
INSERT INTO #game_stats VALUES ('Counter Strike','Laxmi',5); 
INSERT INTO #game_stats VALUES ('WOW','Kamesh',21); 
INSERT INTO #game_stats VALUES ('WOW','laxmi',60); 
INSERT INTO #game_stats VALUES ('WOW','Hely',7); 
INSERT INTO #game_stats VALUES ('NFS','Hely',5); 
INSERT INTO #game_stats VALUES ('NFS','Kamesh',1); 
INSERT INTO #game_stats VALUES ('NFS','Maitri',12); 
INSERT INTO #game_stats VALUES ('NFS','Laxmi',21); 
INSERT INTO #game_stats VALUES ('CODE ZERO','Kamesh',45); 
INSERT INTO #game_stats VALUES ('CODE ZERO','Maitri',52); 
INSERT INTO #game_stats VALUES ('CODE ZERO','Laxmi',21); 
INSERT INTO #game_stats VALUES ('CODE ZERO','Kamesh',41); 
INSERT INTO #game_stats VALUES ('HITMAN','Maitri',142); 
INSERT INTO #game_stats VALUES ('HITMAN','Laxmi',210); 
INSERT INTO #game_stats VALUES ('HITMAN','Kamesh',41); 
INSERT INTO #game_stats VALUES ('HITMAN','Maitri',102); 
INSERT INTO #game_stats VALUES ('HITMAN','Mani',142); 
INSERT INTO #game_stats VALUES ('NFS','Mani',210); 
INSERT INTO #game_stats VALUES ('CODE ZERO','Mani',41); 
INSERT INTO #game_stats VALUES ('WOW','Mani',102); 

select * from #game_stats; 

SELECT RN, 
Gamename, 
Users, 
Times_played 
FROM 
(
    SELECT ROW_NUMBER() OVER (PARTITION BY GS.gamename ORDER BY SUM(GS.times_played) DESC) AS RN, 
     GS.gamename, 
     GS.users, 
     SUM(gs.times_played) as times_played 

FROM #game_stats GS 
WHERE GS.gamename IN (
      SELECT TOP 3 gamename 
          FROM #game_stats 
          GROUP BY gamename 
                   ORDER BY sum(times_played) DESC 
        ) 
GROUP BY GS.gamename,GS.users 
) a 
WHERE RN<=3 
ORDER BY gamename,times_played DESC 
0
SELECT DISTINCT GN,US,GT,UT 
FROM 
(SELECT GN,US,GT,UT, 
     Dense_rank() over(ORDER BY GT DESC) RGT, 
     Dense_rank() over(partition BY GN ORDER BY UT DESC) RUT 
FROM 
    (SELECT gamename GN, 
      users US, 
      times_played TP, 
      sum(times_played) over (partition BY gamename) GT , 
      sum(times_played) over (partition BY gamename,users) UT 
    FROM game_stats)) 
WHERE RGT <4 
AND RUT < 4 
ORDER BY GT DESC, 
     UT DESC 
+0

verificare con questo –