Simplify SQL query that utilizes GROUP BY and HAVING BY and uses aggregation
SELECT Rating.rID, Rating.mID 
FROM Rating
GROUP BY Rating.rID, Rating.mID
HAVING count(*) &gt; 1;



This returns all ratings where the same person reviewed the same movie more than once, but that's not what we want.  We want all the ratings where the same person reviewed the same movie twice, giving it a higher rating the second time.    

SELECT DISTINCT S2.rID, S2.mID
FROM Rating S1 INNER JOIN Rating S2 ON S1.rID = S2.rID AND S1.mID = S2.mID
WHERE S1.ratingDate &gt; S2.ratingDate AND S1.stars &gt; S2.stars;


Now let's look at your step 2:


SELECT Movie.mID, Movie.title, Movie.year, Movie.director, Rating.rID,
       Rating.stars, Rating.ratingDate, Reviewer.name 
FROM Movie, Rating, Reviewer
WHERE Movie.mID = Rating.mID and Rating.rID = Reviewer.rID;



Why do we need so many columns?  The assignment is to return the movie title and reviewer name, so let's just do that:

SELECT Movie.title, Reviewer.name 
FROM Movie
  INNER JOIN Rating S ON Movie.mID = S.mID
  INNER JOIN Reviewer ON S.rID = Reviewer.rID;


So we can finish with a new step 3:

SELECT Movie.title, Reviewer.name 
FROM Movie
  INNER JOIN (
    SELECT DISTINCT S2.rID, S2.mID
    FROM Rating S1 INNER JOIN Rating S2 ON S1.rID = S2.rID AND S1.mID = S2.mID
    WHERE S1.ratingDate &gt; S2.ratingDate AND S1.stars &gt; S2.stars
             ) S ON Movie.mID = S.mID
  INNER JOIN Reviewer ON S.rID = Reviewer.rID;


This uses a single subselect to replace Rating from step 2 with a new version that only includes those Reviewer/Movie pairs where the second rating was higher than the first.