Reputation: 335
I have developed a game recently and the database is running on MSSQL.
Here is my database structure
Table : Player
PlayerID uniqueIdentifier (PK)
PlayerName nvarchar
Table : GameResult
ID bigint (PK - Auto Increment)
PlayerID uniqueIdentifier (FK)
DateCreated Datetime
Score int
TimeTaken bigint
PuzzleID int
I have done an SQL listing Top 50 players that sort by highest score (DESC) and timetaken (ASC)
WITH ResultSet (PlayerID, Score, TimeTaken) AS(
SELECT DISTINCT(A.[PlayerID]), MAX(A.[Score]),MIN(A.[TimeTaken])
FROM GameResult A
WHERE A.[puzzleID] = @PuzzleID
GROUP BY A.[PlayerID])
SELECT TOP 50 RSP.[PlayerID], RSP.[PlayerName], RSA.[Score], RSA.[TimeTaken]
FROM ResultSet RSA
INNER JOIN Player RSP WITH(NOLOCK) ON RSA.PlayerID = RSP.PlayerID
ORDER By RSA.[Score] DESC, RSA.[timetaken] ASC
However above is applicable for just 1 puzzle.
Question
1) I need to modify the SQL to do a cumulative rank of 3 puzzle ID. For example, Puzzle 1, 2, 3 and it should be sort by highest sum score (DESC), and sum timetaken (ASC)
2) I also need an overall score population for all the possible 1 to 7 puzzle.
3) Each player only allowed to appear on the list once. First played and first to get highest score will be rank 1st.
I tried using CTE with UNION but the SQL statement doesn't work.
I hope gurus here can help me out on this. Much appreciated.
UPDATED WITH NEW SQL
Sql below allowed me to get the result for each puzzle id. I'm not sure if it is 100% but I believe it is correct.
;with ResultSet (PlayerID, maxScore, minTime, playedDate)
AS
(
SELECT TOP 50 PlayerID, MAX(score) as maxScore, MIN(timetaken) as minTime, MIN(datecreated) as playedDate
FROM gameresult
WHERE puzzleID = @PuzzleID
GROUP BY PlayerID
ORDER BY maxScore desc, minTime asc, playedDate asc
)
SELECT RSP.[PlayerID], RSP.[PlayerName], RSA.maxScore, RSA.minTime, RSA.PlayedDate
FROM ResultSet RSA
INNER JOIN Player RSP WITH(NOLOCK)
ON RSA.PlayerID = RSP.PlayerID
ORDER BY
maxScore DESC,
minTime ASC,
playedDate ASC
Upvotes: 0
Views: 605
Reputation: 920
I would first like to point out that I do not believe your original query is correct. If you are looking for the best player for a particular puzzle, would that be the combination of the highest score plus the best time for that puzzle? If yes, using max and min does not guarantee that the max and min come from the same game (or row), which I believe should be a requirement. Instead you should have first determined the best game per player by using a row number windowing function. You can then do the top 50 sort off of that data.
The cumulative metrics should be easier to calculate because you only have to aggregate the sum of their score and the sum of their time and then sort, which means the new query should most likely look something like this:
;with ResultSet (PlayerID, Score, TimeTaken)
AS
(
SELECT TOP 50
A.[PlayerID],
SUM(A.[Score]),
SUM(A.[TimeTaken])
FROM GameResult A
WHERE
A.[puzzleID] in(1,2,3)
GROUP BY
A.PlayerID
ORDER BY
SUM(A.[Score]) DESC,
SUM(A.[TimeTaken]) ASC
)
SELECT RSP.[PlayerID], RSP.[PlayerName], RSA.[Score], RSA.[TimeTaken]
FROM ResultSet RSA
INNER JOIN Player RSP WITH(NOLOCK)
ON RSA.PlayerID = RSP.PlayerID
ORDER BY
Score DESC,
TimeTaken ASC
Based on the new criteria, you will have to do something like this.
;WITH ResultSet (PlayerID, PuzzleId, Score, TimeTaken, seq)
AS
(
SELECT
A.[PlayerID],
A.PuzzleID,
A.[Score],
A.[TimeTaken],
seq = ROW_NUMBER() over(PARTITION BY PlayerID, PuzzleId ORDER BY Score DESC)
FROM GameResult A
WHERE
A.[puzzleID] in(1,2,3)
)
SELECT TOP 50
RSP.[PlayerID],
RSP.[PlayerName],
Score = SUM(RSA.[Score]), --total score
TimeTaken = SUM(RSA.[TimeTaken]) --total time taken
FROM ResultSet RSA
INNER JOIN Player RSP
ON RSA.PlayerID = RSP.PlayerID
WHERE
--this is used to filter the top score for each puzzle per player
seq = 1
GROUP BY
RSP.[PlayerID],
RSP.[PlayerName]
ORDER BY
SUM(RSA.Score) DESC,
SUM(RSA.TimeTaken) ASC
Upvotes: 3