Reputation: 27286
I have two tables:
subject
which holds a list of subjects and their creditsexams
which shows which subjects the students failed or succeeded in the examsI am trying to get a list of total credits earned for every student. Problem is if a student failed in all subjects he doesn't show up cause he's filtered out in the WHERE
clause before the GROUP BY
.
Here's the SQL:
CREATE TABLE IF NOT EXISTS subject (
name VARCHAR(50) NOT NULL,
credits INT NOT NULL
);
ALTER TABLE subject ADD PRIMARY KEY (name);
INSERT INTO subject(name, credits) VALUES('ALGEBRA', 100);
INSERT INTO subject(name, credits) VALUES('FRENCH' , 10);
CREATE TABLE IF NOT EXISTS exam (
student VARCHAR(50) NOT NULL,
subject VARCHAR(50) NOT NULL,
success BOOLEAN NOT NULL);
ALTER TABLE exam ADD PRIMARY KEY (student, subject);
ALTER TABLE exam ADD CONSTRAINT exam_2_subject FOREIGN KEY (subject) REFERENCES subject(name);
INSERT INTO exam(student, subject, success) VALUES('Bob', 'ALGEBRA', true);
INSERT INTO exam(student, subject, success) VALUES('Bob', 'FRENCH', false);
INSERT INTO exam(student, subject, success) VALUES('Mike', 'ALGEBRA', false);
INSERT INTO exam(student, subject, success) VALUES('Mike', 'FRENCH', false);
CREATE VIEW student_credits AS
SELECT a.student, SUM(b.credits) AS total_credits FROM
exam a INNER JOIN
subject b ON b.name = a.subject
WHERE a.success IS TRUE
GROUP BY a.student;
View student_credits
only shows:
student total_credits
--------------------------
Bob 100
What's an idiomatic way to fix view student_credits
to also include Mike
who failed all subjects?
Upvotes: 0
Views: 60
Reputation: 547
Try this
CREATE VIEW student_credits AS
SELECT a.student, SUM(CASE WHEN a.success then b.credits
else 0 end) AS total_credits FROM
exam a INNER JOIN
subject b ON b.name = a.subject
GROUP BY a.student;
Upvotes: 2
Reputation: 39457
select
a.student,
sum( (case when a.success then 1 else 0 end) * (b.credits) )
as total_credits
from
exam a
inner join subject b on a.subject = b.name
group by a.student;
Unfortunately seems there's no simpler way to convert boolean to int in PostgreSQL.
Upvotes: 0
Reputation: 27286
I did:
CREATE VIEW student_credits AS
SELECT a.student, SUM(b.credits) AS total_credits FROM
exam a INNER JOIN
subject b ON b.name = a.subject
WHERE a.success IS TRUE
GROUP BY a.student
UNION
SELECT DISTINCT STUDENT, 0 AS total_credits FROM exam a
WHERE NOT EXISTS (SELECT 1 FROM exam b WHERE b.student=a.student AND success IS TRUE);
But I think that's ugly. Plus this is just an SSCCE, the real case would be more complicated.
Upvotes: 0