Home > database >  Use listagg to group all students for teacher, course, semster
Use listagg to group all students for teacher, course, semster

Time:07-03

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 JOINs 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

  • Related