PostgreSQL:避免多次对相同值进行 SUM

use*_*760 1 postgresql aggregate sum

我有一个学生表和一个不同科目的分数表。我想将所有科目的每个学生的 score1 和 score2 相加,然后为每个学生加上奖金。

CREATE TABLE student (
   id serial PRIMARY KEY,
   name text NOT NULL,
   bonus integer NOT NULL,
);

CREATE TABLE score (
  id serial PRIMARY KEY,
  subject text NOT NULL,
  score1 integer NOT NULL,
  score2 integer NOT NULL,
  student_id integer NOT NULL,
  CONSTRAINT s_id FOREIGN KEY (student_id) REFERENCES student (id),
);
Run Code Online (Sandbox Code Playgroud)

连接 score1 和 score2 的查询如下所示:

SELECT st.name, sum(sc.score1 + sc.score2) as total
FROM student st
LEFT JOIN score sc ON sc.student_id = st.id
group by st.name
Run Code Online (Sandbox Code Playgroud)

如果我添加bonus到这个查询 ie sum(sc.score1 + sc.score2 + st.bonus),它会为每个学生重复多次(取决于 student_id 在分数表中出现的次数)。

我是否必须使用子查询,即首先计算 score1 和 score2 的总和,然后将其添加到奖金中(见下文),还是有更好的方法?

SELECT sq.name, sum(sq.bonus+sq.total) FROM
( SELECT st.bonus, st.name, sum(sc.score1 + sc.score2) as total
  FROM student st
  LEFT JOIN score sc ON sc.student_id = st.id
  group by st.name
) AS sq
Run Code Online (Sandbox Code Playgroud)

ype*_*eᵀᴹ 5

您可以使用子查询,但不需要。只是不要求bonus和并将其添加到GROUP BY列表中。
请注意student.id,即使在您的原始查询中,您也必须添加,以防您有 2 个同名的学生。
您可能还需要coalesce()没有任何分数的学生:

SELECT st.name, 
       coalesce(sum(sc.score1),0) + coalesce(sum(sc.score2),0) + st.bonus AS total
FROM student st
LEFT JOIN score sc ON sc.student_id = st.id
GROUP BY st.id, st.name, st.bonus ;
Run Code Online (Sandbox Code Playgroud)

在较新版本的 Postgres 中,您只能通过以下方式使用student组中表的主键:

SELECT st.name, 
       coalesce(sum(sc.score1),0) + coalesce(sum(sc.score2),0) + st.bonus AS total
FROM student st
LEFT JOIN score sc ON sc.student_id = st.id
GROUP BY st.id ;
Run Code Online (Sandbox Code Playgroud)

如果你想要一个子查询,这是一种方法:

SELECT st.name, 
       coalesce(sc.score, 0) + st.bonus AS total
FROM student st
LEFT JOIN 
    ( SELECT student_id, sum(score1) + sum(score2) AS score
      FROM score 
      GROUP BY student_id
    ) AS sc ON sc.student_id = st.id ;
Run Code Online (Sandbox Code Playgroud)

  • 没有任何区别(除非有空值)。 (2认同)