Search code examples
sqlcountcross-join

Is there a way in oracle sql to get a count with cross join?


I need to take a list of majors and a list of letter grades and I need to get the number of courses completed within the major associated with the letter grade. So if i have:

Major
Mechanical Engineer
Electrical Engineer
Civil Engineer
Chemical Engineer 
...

Grade
A
B
C
...

Student
100 - Alice - Mechanical Engineer
101 - Tom - Mechanical Engineer
102 - Rex - Mechanical Engineer
103 - Bob - Mechanical Engineer
104 - John - Civil Engineer 
105 - Alex - Electrical Engineer

Course
001 - Solid Mechanics - 100 - A
002 - Thermodynamics - 100 - A
003 - Heat Transfer - 100 - A 
004 - Heat Transfer - 101 - A
005 - Gadgetry - 100 - A
006 - Gadgetry - 101 - A
007 - Gadgetry - 102 - A
008 - Dynamics - 102 - A
009 - Gadgetry - 101 - C
010 - Heat Transfer - 102 - C
011 - Fluid Mechanics - 100 - B 
012 - Materials - 102 -B 
013 - Intro to EE - 105 - B
014 - Embedded Systems - 105 - B
015 - Analog Circuits - 105 - B
... 

I need an output of:

Mechanical Engineer - A - 8
Mechanical Engineer - B - 2
Mechanical Engineer - C - 2
Electrical Engineer - A - 0
Electrical Engineer - B - 3
...

There is another table with students that says which major each student is in, and a course table with which student took what course (some students can take no courses) and what grade they received from that course.

So far I have:

SELECT major_name, grade, COUNT(grade_code) OVER (PARTITION BY major_name)
FROM Major CROSS JOIN ((grade LEFT JOIN course USING (grade_code)) RIGHT JOIN student USING (st_id))
ORDER BY major_name, grade;

But the count is not working (getting the same incorrect count for each major), essentially the total count of the letter grade from the course table.

Mechanical Engineer - A - 10
Mechanical Engineer - B - 10
Mechanical Engineer - C - 10
Electrical Engineer - A - 10
...

Solution

  • There is no need for CROSS JOIN or an aggregate COUNT...OVER() window function. Simply join the main tables ( student and course) and then the lookup tables (major and grade). Then, aggregate for count. Because major links to student which is not in FROM clause, replace USING for the traditional ON by corresponding aliases:

    SELECT m.major_name, 
           g.grade, 
           count(*) as major_grade_count
    FROM course c
    LEFT JOIN student s USING (st_id)
    LEFT JOIN grade g USING (grade_code)
    LEFT JOIN major m ON g.major_code = m.major_code      -- ADJUST FIELD HERE
    GROUP BY  m.major_name, 
              g.grade;