Reputation: 53
Really tricky SQL statement I have here. Trying to build this query for about hour. Maybe You can help me.
We have a table with 3 columns: gamename | user | times_played
The query should select top three games (depending total times_played) and top three user who has played most times in this game => 9 rows.
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
Would be very nice, if you could help me =) Thanks!
Upvotes: 5
Views: 2464
Reputation: 1
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
Upvotes: 0
Reputation: 1
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
Upvotes: 0
Reputation: 425491
Update:
As @Steve Kass
pointed out, I didn't notice that you only wanted the first three games.
Here's the updated version:
In SQL Server
, Oracle
and 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
You will need a PRIMARY KEY
for this query to work, assuming it is called id
.
This is explained in more detail in this article in my blog:
In PostgreSQL 8.3
and below:
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
Upvotes: 13
Reputation: 7184
I don't think Quassnoi noticed that you asked for the top users only for the top three games (based on total times_played). Here's a query for that (not tested on real data, since no CREATE TABLE and INSERT statements were given). I also include ties, which Quassnoi didn't, just to show you that option.
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;
Upvotes: 1