2009-10-09 16 views
5

Sentencia SQL muy difícil que tengo aquí. Intentando construir esta consulta por aproximadamente una hora. Quizás me puedas ayudar.Tricky SQL query

Tenemos una tabla con 3 columnas: gamename | usuario | times_played

La consulta debe seleccionar los tres mejores juegos (dependiendo del total de veces jugadas) y los tres primeros usuarios que jugaron la mayoría de las veces en este juego => 9 filas.

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 

sería muy agradable, si usted me podría ayudar =) Gracias!

+0

Qué base de datos? MySQL? ¿Servidor SQL? ¿Oráculo? Postgres? – Asaph

+0

¿Qué tecnología? MySQL? ¿Servidor SQL? ¿Puedes usar un procedimiento almacenado? –

+0

@foriamstu mejor pregunta: * ¿debería * usar un procedimiento almacenado? En mi experiencia, casi siempre: 'no'. Parece útil en el momento, vuelve para morderte en mantenimiento. –

Respuesta

13

Actualización:

Como @Steve Kass señalado, no me di cuenta de que sólo quería los tres primeros juegos.

Aquí está la versión actualizada:

En SQL Server, Oracle y 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 

En 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 

necesitará un PRIMARY KEY para esta consulta al trabajo, suponiendo que se llama id.

Esto se explica con más detalle en este artículo en mi blog:

En PostgreSQL 8.3 y abajo:

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

Parece tan fácil cuando lo respondes :-) –

+0

Supongo que es "PARTITION BY" –

+0

Me gustaría hacer un pedido por Juego y rn para asegurarse de que los resultados se muestran en el orden correcto. –

1

no creo que se dio cuenta de Quassnoi solicitaste los usuarios principales solo para los tres juegos principales (según el total de veces reproducidas). Aquí hay una consulta para eso (no probada en datos reales, ya que no se dieron las instrucciones CREATE TABLE e INSERT). También incluyo corbatas, lo que Quassnoi no hizo, solo para mostrarte esa opción.

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

Gracias por señalar eso. Hay votaciones ascendentes de '12' y ninguna hecha más que un comentario simulado :) – Quassnoi

+0

Tal vez lo que publicas rara vez está mal que la gente piense que es una pérdida de tiempo mirar de cerca. :) –

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

consulte con este –