The "having" command is executed after the COUNT(DISTINCT "student_id"), you should use subqueries to build the result that you want step by step.
Something like
-- create
CREATE TABLE ROOM_STUDENT (
room_id INTEGER,
student_id INTEGER,
age INTEGER
);
-- insert
INSERT INTO ROOM_STUDENT VALUES (1, 10001, 22);
INSERT INTO ROOM_STUDENT VALUES (1, 10002, 23);
INSERT INTO ROOM_STUDENT VALUES (1, 10003, 23);
INSERT INTO ROOM_STUDENT VALUES (2, 10001, 22);
INSERT INTO ROOM_STUDENT VALUES (2, 10002, 23);
INSERT INTO ROOM_STUDENT VALUES (3, 10002, 23);
INSERT INTO ROOM_STUDENT VALUES (3, 10003, 24);
with sub as (
SELECT student_id, count(*) as count_rooms FROM ROOM_STUDENT WHERE age > 22 group by student_id
)
select count(*) as count_students from sub where count_rooms > 2;
You can see it running here https://onecompiler.com/postgresql/3y28krk5u
Here is a link teaching more about the "with" command in SQL https://modern-sql.com/feature/with#:~:text=Syntax&text=The%20syntax%20after%20the%20keyword,query%E2%80%94again%20in%20parentheses.