根据其他表中的数据更新和更新数据

Update and renew data based on data in other tables

有3个tablestudentcoursetakes如下

CREATE TABLE student
(
     ID         varchar(5), 
     name       varchar(20) NOT NULL, 
     dept_name  varchar(20), 
     tot_cred   numeric(3,0) CHECK (tot_cred >= 0),
     PRIMARY KEY (ID),
     FOREIGN KEY (dept_name) REFERENCES department
        ON DELETE SET NULL
)

CREATE TABLE takes
(
     ID         varchar(5), 
     course_id  varchar(8),
     sec_id     varchar(8), 
     semester   varchar(6),
     year       numeric(4,0),
     grade      varchar(2),
     PRIMARY KEY (ID, course_id, sec_id, semester, year),
     FOREIGN KEY (course_id, sec_id, semester, year) REFERENCES section
        ON DELETE CASCADE,
     FOREIGN KEY (ID) REFERENCES student
        ON DELETE CASCADE
    )

CREATE TABLE course
(
    course_id   varchar(8), 
    title       varchar(50), 
    dept_name   varchar(20),
    credits     numeric(2,0) CHECK (credits > 0),

    PRIMARY KEY (course_id),
    FOREIGN KEY (dept_name) REFERENCES department
        ON DELETE SET NULL
)

tot_cred student table 列数据现在被分配了随机值(不正确),我想执行更新和更新这些数据的查询基于课程的 grade 每个学生都已经上过。对于那些获得 F 成绩的学生将被排除在外,而那些没有参加任何课程的学生将被分配为 0 作为 tot_cred

我想到了两种方法,一种是

UPDATE student 
SET tot_cred = (SELECT SUM(credits)  
                FROM takes, course  
                WHERE takes.course_id = course.course_id 
                  AND student.ID = takes.ID 
                  AND takes.grade <> 'F' 
                  AND takes.grade IS NOT NULL)

这个查询满足了我的所有需求,但是对于那些没有参加任何课程的学生,它确实分配了 NULL 值而不是 0。

第二种是使用case when

UPDATE student
SET tot_cred = (select sum(credits)
    case 
         when sum(credits) IS NOT NULL then sum(credits)
         else 0 end
    FROM takes as t, course as c
    WHERE t.course_id = c.course_id
    AND t.grade<>'F' and t.grade IS NOT NULL
)

但是它给所有学生分配了 0。有什么办法可以达到上面的要求吗?

如果第一个查询满足您的要求,唯一的问题是它 returns NULL 对于没有参加任何课程的学生,那么最简单的解决方案是使用而不是 SUM() 聚合函数函数 TOTAL() 将 return 0 而不是 NULL:

UPDATE student AS s 
SET tot_cred = (
  SELECT TOTAL(c.credits)  
  FROM takes t INNER JOIN course c 
  ON t.course_id = c.course_id 
  WHERE t.ID = s.ID AND t.grade <> 'F' AND t.grade IS NOT NULL
);

同样可以用 COALESCE():

SELECT COALESCE(SUM(credits), 0)... 

此外,使用带有 ON 子句的适当联接和表的别名以提高可读性。