1

我有一个包含以下表格的数据库:

student(sid, name,address)

course(cid,type,department)

takes(sid,cid,score)

我需要解决的问题是找到学生,这样,对于他们所修的每门课程,他们在课程上的分数都高于任何其他修过同一门课程的学生。

我知道在这种情况下我必须进行自我加入,但仍然对如何解决此类查询感到困惑!

4

4 回答 4

1
SELECT
    s.sid,
    s.name
FROM student s
WHERE NOT EXISTS (
    SELECT *
    FROM takes t1
    JOIN takes t2 ON (t1.cid = t2.cid AND t1.sid <> t2.sid AND t2.score > t1.score)
    WHERE t1.sid = s.sid
);

我们正在选择所有学生,我们找不到他们选修的任何其他人得分更高的课程。

Sqlfiddle

于 2013-11-15T09:19:09.190 回答
0

试试这个:

SELECT s.* 
FROM student s
INNER JOIN (
  SELECT t1.*
  FROM takes t1
    LEFT JOIN takes t2
      ON (t1.cid = t2.cid AND t1.score < t2.score)
  WHERE t2.cid IS NULL
  ) b ON b.sid = s.sid

sqlfiddle demo

您可以在 fiddle 中看到,如果两个用户的分数相同即为最佳,则两者都将被重新使用。

你在表中找到得分最高的行takes,然后加入Student

(我开始使用这种方式根据 Bill karwin 的答案从表格中获取最大值您可以查看他对该答案的详细解释,了解其工作原理)。

于 2013-11-15T09:33:13.220 回答
0

SQB的回答完美解决了你的问题。我只是给你另一种方法。根据表的大小和可用的索引,它可以对性能产生很大影响。

我选择每门课程的最高分数,并加入所有课程。然后我将学生参加的所有课程的数量与他/她获得最高分的课程数量进行比较。因此,表格被完整地阅读了两次,结果以某种方式粘合在一起然后过滤。这可以(但不是必须)比必须在需要中找到的每条记录搜索更高等级的学生更快。

select *
from students
where sid in
(
  select takes.sid
  from takes
  left outer join (select cid, max(score) as score from takes group by cid) max_scores 
  on (max_scores.cid=takes.cid and max_scores.score=takes.score)
  group by takes.sid
  having count(takes.cid) = count(max_scores.cid)
);
于 2013-11-15T16:10:43.037 回答
0

如果要求是“对于每门课程,找到获得最高分的学生”,那么可以使用以下查询来完成:

WITH ranked_scores AS (
  SELECT sid,
         cid,
         score,
         DENSE_RANK() OVER ( PARTITION BY cid ORDER BY score DESC ) AS "rank"
  FROM   takes
)
SELECT s.sid, s.name, r.cid, r.score
FROM   student s
       INNER JOIN
       ranked_scores r
       ON ( r.sid = s.sid )
WHERE  r."rank" = 1;

SQLFIDDLE

如果要求是“找到在所有课程中获得该课程最高分的学生”,那么你可以使用这个:

WITH ranked_scores AS (
  SELECT sid,
         cid,
         score,
         DENSE_RANK() OVER ( PARTITION BY cid ORDER BY score DESC ) AS "rank"
  FROM   takes
)
SELECT s.sid,
       s.name
FROM   student s
WHERE  EXISTS ( SELECT 1
                FROM   ranked_scores r
                WHERE  r.sid = s.sid
                GROUP BY r.sid
                HAVING MAX( r."rank" ) = 1 );

SQLFIDDLE

于 2013-11-15T16:33:47.763 回答