Good day community. I'm having a hard time trying to figure out a way to achieve the results I try to get. As im not very skilled with SQL queries, I start to lose my mind. What I'm trying to do is to find the highest and lowest grade on a particular test, but I also wish to get the ID or the row number (they are matching) of the rows where the MAX() and MIN() were found.
The table "Results" looks like this:
ResultID|Test_UK|Test_US|TestUK_Scr|TestUS_Scr|TestTakenOn
1 1 3 85 14 2018-11-22 00:00:00.000
2 3 1 41 94 2018-11-23 00:00:00.000
3 2 4 71 54 2018-11-24 00:00:00.000
4 4 2 51 52 2018-12-25 00:00:00.000
5 6 3 74 69 2018-12-01 00:00:00.000
6 3 6 83 57 2018-12-02 00:00:00.000
7 7 4 91 98 2018-12-03 00:00:00.000
8 4 7 88 22 2018-12-04 00:00:00.000
9 5 8 41 76 2018-12-08 00:00:00.000
10 8 5 37 64 2018-12-09 00:00:00.000
The results I get when I run my query...
TestID|TopScore|LowScore|LastDateTestTaken
1 94 85 2018-11-23 00:00:00.000
2 71 52 2018-11-25 00:00:00.000
3 83 14 2018-12-02 00:00:00.000
4 98 51 2018-12-04 00:00:00.000
5 64 41 2018-12-09 00:00:00.000
6 74 57 2018-12-02 00:00:00.000
7 91 22 2018-12-04 00:00:00.000
8 76 37 2018-12-09 00:00:00.000
This is the queries I'm working on.
This query returns the results mentioned above
WITH
-- Combine the results of UK and US tests
Combined_Results_Both_Tests AS(
select ResultID as resultID, Test_UK as TestID, Test_UK_Scr as TestScore, TestTakenOn as TestDate from Results
union all
select ResultID as resultID, Test_US as TestID, Test_US_Scr as TestScore, TestTakenOn as TestDate from Results),
--Gets TOP and WORST results of the tests, LastDateTaken (Needs to add ResultID!)
Get_Best_and_Worst_Results_And_LastTestDate AS(
SELECT TestID ,max(TestScore) AS TopScore ,min(TestScore) AS LowScore ,max(TestDate) AS LastDateTestTaken
FROM Combined_Results_Both_Tests
GROUP BY TestID)
--Final query execution
SELECT * FROM Get_Best_and_Worst_Results_And_LastTestDate
I've tried to achieve my desired results with something like this, which doesn't work and is also very inefficient. What I mean that it doesn't work, it is filled with dublicates, whenever the match is found on US and UK tests.
--Gets ReslutID of Min and Max values
Get_ResultID_Of_Results AS(
SELECT * FROM Get_Best_and_Worst_Results_And_LastTestDate A
CROSS APPLY
(SELECT ResultID FROM Results res
WHERE (A.TestID = res.Test_UK AND A.TopScore = res.Test_UK_Scr) OR
(A.TestID = res.Test_US AND A.TopScore = res.Test_UK_Scr) OR
(A.TestID = res.Test_UK AND A.LowScore = res.Test_UK_Scr) OR
(A.TestID = res.Test_US AND A.LowScore = res.Test_UK_Scr) OR
(A.TestID = res.Test_UK AND A.TopScore = res.Test_US_Scr) OR
(A.TestID = res.Test_US AND A.TopScore = res.Test_US_Scr) OR
(A.TestID = res.Test_UK AND A.LowScore = res.Test_US_Scr) OR
(A.TestID = res.Test_US AND A.LowScore = res.Test_US_Scr)) D)
SELECT * FROM Get_ResultID_Of_Results
This is the results I'm trying to achieve (extra columns that would state where Max value and Min value was found) that would state the ResultID from Results table. Also, the row numbers match the ResultIDs in the table.
TestID|TopScore|LowScore|LastDateTestTaken |MaxValueLocID|MinValueLocID|
1 94 85 2018-11-23 00:00:00.000 2 1
2 71 52 2018-11-25 00:00:00.000 3 4
3 83 14 2018-12-02 00:00:00.000 6 1
4 98 51 2018-12-04 00:00:00.000 7 4
5 64 41 2018-12-09 00:00:00.000 10 9
6 74 57 2018-12-02 00:00:00.000 5 6
7 91 22 2018-12-04 00:00:00.000 7 8
8 76 37 2018-12-09 00:00:00.000 9 10
Asking for any help with the solution, theoretical or even practical. Thank you!
If I follow correctly, you want to unpivot the data and aggregate:
select v.testid, max(v.score), min(v.score) max(v.TestTakenOn)
from results r cross apply
(values (Test_UK, TestUK_Scr, TestTakenOn),
(Test_US, TestUS_Scr, TestTakenOn)
) v(testid, score, TestTakenOn)
group by v.testid;
Then you can modify this using window functions:
select v.testid, max(v.score), min(v.score) max(v.TestTakenOn),
max(case when seqnum_desc = 1 then resultid end) as resultid_max,
max(case when seqnum_asc = 1 then resultid end) as resultid_min
from (select r.resultid, v.*,
row_number() over (partition by v.testid order by v.score asc) as seqnum_asc,
row_number() over (partition by v.testid order by v.score desc) as seqnum_desc
from results r cross apply
(values (Test_UK, TestUK_Scr, TestTakenOn),
(Test_US, TestUS_Scr, TestTakenOn)
) v(testid, score, TestTakenOn)
) v
group by v.testid;