It's a little tricky to do ranks in Access. You basically have to join/or select from the tables twice; once to get the GPA per student and then again to see how many students have a better GPA per GROUP. When you do this, you can see where the student ranks and then select them if they're in the top 5. Doing it like this, instead of just saying TOP 5 ORDER BY GPA DESC - allows you to get the top 5 PER GROUP in a single query, instead of running the same query several times, substituing each group as you do.
I'm pretty confident 1 and 2 will work. Number 3 was a little trickier, because I'm not sure what top 40% means. Does it mean you rank each student by GPA and then just take the top 40% of those (so 4 students if each group has 10) - OR - Does it mean, find the average GPA and take all students who scored in the top 40%?? I ran it based on the first one (I think), but you're mileage may very with it.
Good Luck!
1)
SELECT Name, Group, GPA
FROM (
SELECT Student.Name, Student.Group, GPA.GPA, (SELECT COUNT(*) FROM GPA GPA2 INNER JOIN Student Student2 ON GPA2.Name = Student2.Name WHERE GPA2.GPA > GPA.GPA and Student.Group = Student2.Group)+1 AS Ranked
FROM GPA INNER JOIN Student ON GPA.Name = Student.Name
) as RankedGPA
Where Ranked <= 5
Order By Group, GPA Desc
2)
SELECT Name, Group, GPA, Type
FROM (
SELECT Student.Name, Student.Group, GPA.GPA, (SELECT COUNT(*) FROM GPA GPA2 INNER JOIN Student Student2 ON GPA2.Name = Student2.Name WHERE GPA2.GPA > GPA.GPA and Student.Group = Student2.Group)+1 AS Ranked, 'Top' as Type
FROM GPA INNER JOIN Student ON GPA.Name = Student.Name
) as RankedGPA
Where Ranked <= 5
Order By Group, GPA Desc
UNION ALL
SELECT Name, Group, GPA, Type
FROM (
SELECT Student.Name, Student.Group, GPA.GPA, (SELECT COUNT(*) FROM GPA GPA2 INNER JOIN Student Student2 ON GPA2.Name = Student2.Name WHERE GPA2.GPA < GPA.GPA and Student.Group = Student2.Group)+1 AS Ranked, 'Bottom' as Type
FROM GPA INNER JOIN Student ON GPA.Name = Student.Name
) as RankedGPA
Where Ranked <= 5
Order By Group,Type, GPA Desc
3)
SELECT Name, Group, GPA
FROM (
SELECT Student.Name, Student.Group, GPA.GPA, (SELECT COUNT(*) FROM GPA GPA2 INNER JOIN Student Student2 ON GPA2.Name = Student2.Name WHERE GPA2.GPA > GPA.GPA and Student.Group = Student2.Group)+1 AS Ranked
FROM GPA INNER JOIN Student ON GPA.Name = Student.Name
) as RankedGPA
Where Ranked <= (Select Count(*) *.40 FROM Student Student3 Where Student3.Group = RankedGPA.Group)
ORDER BY Group, GPA Desc