sqlsql-serverloopsvariablescursors

Using cursors in Microsoft SQL Server with a loop


Problem:

Write a script that determines if too few students (less than five) or too many students (greater than 10) are enrolled in each course. To do that, you can use a cursor. This cursor should use a SELECT statement that gets the CourseID and the count of students for each course from the StudentCourses table.

When you loop through the rows in the cursor, the script should display a message like this if there are too few students enrolled in a course:

"Too few students enrolled in course x" where x is the course ID. The script should display a similar message if there are too many students enrolled in a course.

My code so far:

DECLARE Students_Cursor CURSOR FOR 
    SELECT c.CourseID, COUNT(sc.StudentID) 
    FROM Courses c 
    JOIN StudentCourses sc ON c.CourseID = sc.CourseID
    WHERE COUNT(sc.StudentID) < 5  OR COUNT(sc.StudentID) > 10

OPEN Student_Cursor;

FETCH NEXT FROM Students_Cursor

WHILE @@FETCH_STATUS <> -1
BEGIN
    IF 

Solution

  • Using a CURSOR is usually slower than better alternate options. That being said, the first thing you would need to work on is getting the SELECT statement working. I don't think it will work as you have it. If you are using a COUNT, you are aggregating. If you want to filter the results by the aggregate, you can't do that with the WHERE clause. Instead you would need to move it into a HAVING clause. Also, since you are selecting more than the aggregate counts, you need to GROUP BY the CourseID. To continue this route, you would have a SELECT like:

    SELECT c.CourseID, COUNT(sc.StudentID) FROM Courses c JOIN StudentCourses sc
    ON c.CourseID= sc.CourseID
    GROUP BY c.CourseID
    HAVING COUNT(sc.StudentID) < 5  OR COUNT(sc.StudentID) > 10;
    

    Not that it is a bad idea to limit the number of rows you are going to run through in the CURSOR, but if you are going to be checking for the number of students as part of the CURSOR, maybe they are looking for you to do the logic in the CURSOR itself. You could just eliminate the HAVING clause and go through all of the rows in the CURSOR instead.

    Once you get the SELECT straightened out, and you FETCH from the CURSOR, you want to pull the items you SELECT into variables you can then use to generate your messages. Therefore, you want to DECLARE them earlier, and then pull the CURSOR values into them. Something like

    FETCH NEXT FROM Students_Cursor INTO @CourseID, @StudentCount;
    WHILE @@FETCH_STATUS <> -1
    

    Then you can do your IF/THEN conditions on the @StudentCount, and use @CourseID in the message. Just make sure that after that, you FETCH NEXT FROM into the variables again inside of the BEGIN/END block, then of course CLOSE and DEALLOCATE the CURSOR.