I have a relationship where a teacher -> courses -> enrollmenr-> students. I am trying to use listagg to get all the students first/last names on the same line as the teacher_id and course_id. In addition, I want to add the count of each teacher_id, course_id, semester.
Below is my test CASE, which has the tables, data and a part of the query. I would appreciate any help completing the query. Thanks in advance to all who answer.
CREATE TABLE teachers(teacher_id, first_name, last_name) AS
SELECT 101, 'Keith', 'Stein' FROM dual UNION ALL
SELECT 102, 'Roger', 'Wood' FROM dual UNION ALL
SELECT 103, 'Douglas', 'Kern' FROM dual UNION ALL
SELECT 104, 'Paul', 'Weber' FROM dual UNION ALL
SELECT 105, 'Jeffrey', 'Lebowitz' FROM dual UNION ALL
SELECT 106, 'Carol', 'Seltzer' FROM dual;
CREATE TABLE students(student_id, first_name, last_name) AS
SELECT 1, 'Faith', 'Aaron' FROM dual UNION ALL
SELECT 2, 'Lisa', 'Saladino' FROM dual UNION ALL
SELECT 3, 'Leslee', 'Altman' FROM dual UNION ALL
SELECT 4, 'Patty', 'Kern' FROM dual UNION ALL
SELECT 5, 'Beth', 'Cooper' FROM dual UNION ALL
SELECT 99, 'Jill', 'Coralnick' FROM dual;
CREATE TABLE courses(course_id, course_name, teacher_id, semester) AS
SELECT 1, 'Geometry', 101, '2022-2' FROM DUAL UNION ALL
SELECT 2, 'Trigonometry', 102, '2022-2' FROM DUAL UNION ALL
SELECT 3, 'Calculus', 103, '2022-2' FROM DUAL UNION ALL
SELECT 4, 'Chemistry', 104, '2022-2' FROM DUAL UNION ALL
SELECT 5, 'Biology', 105, '2022-2' FROM DUAL UNION ALL
SELECT 6, 'Physcology', 106, '2022-2' FROM DUAL;
CREATE TABLE enrollment(student_id,course_id) AS
SELECT 1, 1 FROM dual UNION ALL
SELECT 2, 1 FROM dual UNION ALL
SELECT 3, 1 FROM dual UNION ALL
SELECT 4, 1 FROM dual UNION ALL
SELECT 5, 1 FROM dual UNION ALL
SELECT 1, 2 FROM dual UNION ALL
SELECT 2, 2 FROM dual UNION ALL
SELECT 3, 2 FROM dual UNION ALL
SELECT 4, 2 FROM dual UNION ALL
SELECT 5, 2 FROM dual UNION ALL
SELECT 1, 3 FROM dual UNION ALL
SELECT 2, 3 FROM dual UNION ALL
SELECT 3, 3 FROM dual UNION ALL
SELECT 4, 3 FROM dual UNION ALL
SELECT 5, 3 FROM dual UNION ALL
SELECT 99, 3 FROM dual;
/* list all teachers, courses, student count, all students for teacher_id, course_id, semester
*/
SELECT
t.teacher_id
, t.first_name
, t.last_name
, c.course_id
, c.course_name
, c.semester
FROM teachers t
LEFT JOIN courses c
ON t.teacher_id = c.teacher_id
ORDER BY teacher_id;
TEACHER_ID FIRST_NAME LAST_NAME COURSE_ID COURSE_NAME SEMESTER
101 Keith Stein 1 Geometry 2022-2
102 Roger Wood 2 Trigonometry 2022-2
103 Douglas Kern 3 Calculus 2022-2
104 Paul Weber 4 Chemistry 2022-2
105 Jeffrey Lebowitz 5 Biology 2022-2
106 Carol Seltzer 6 Physcology 2022-2
CodePudding user response:
You can use a correlated sub-query:
SELECT t.teacher_id
, t.first_name
, t.last_name
, c.course_id
, c.course_name
, c.semester
, (
SELECT LISTAGG(s.last_name || ', ' || s.first_name, '; ')
WITHIN GROUP (ORDER BY s.last_name, s.first_name)
FROM enrollment e
INNER JOIN students s
ON (e.student_id = s.student_id)
WHERE e.course_id = c.course_id
) AS students
FROM teachers t
LEFT JOIN courses c
ON t.teacher_id = c.teacher_id
ORDER BY
teacher_id;
Which, for the sample data, outputs:
TEACHER_ID FIRST_NAME LAST_NAME COURSE_ID COURSE_NAME SEMESTER STUDENTS 101 Keith Stein 1 Geometry 2022-2 Aaron, Faith; Altman, Leslee; Cooper, Beth; Kern, Patty; Saladino, Lisa 102 Roger Wood 2 Trigonometry 2022-2 Aaron, Faith; Altman, Leslee; Cooper, Beth; Kern, Patty; Saladino, Lisa 103 Douglas Kern 3 Calculus 2022-2 Aaron, Faith; Altman, Leslee; Cooper, Beth; Coralnick, Jill; Kern, Patty; Saladino, Lisa 104 Paul Weber 4 Chemistry 2022-2 null 105 Jeffrey Lebowitz 5 Biology 2022-2 null 106 Carol Seltzer 6 Physcology 2022-2 null
Or you can use JOIN
s and aggregate:
SELECT t.teacher_id
, MAX(t.first_name) AS first_name
, MAX(t.last_name) AS last_name
, c.course_id
, MAX(c.course_name) AS course_name
, MAX(c.semester) AS semester
, LISTAGG(
NVL2(s.student_id, s.last_name || ', ' || s.first_name, NULL),
'; '
) WITHIN GROUP (ORDER BY s.last_name, s.first_name) AS students
, COUNT(s.student_id) AS num_students
FROM teachers t
LEFT OUTER JOIN courses c
ON t.teacher_id = c.teacher_id
LEFT OUTER JOIN (
enrollment e
INNER JOIN students s
ON (e.student_id = s.student_id)
)
ON (e.course_id = c.course_id)
GROUP BY
t.teacher_id,
c.course_id
ORDER BY
t.teacher_id,
c.course_id;
db<>fiddle here