HAVING和GROUP BY的SQL难度

时间:2016-03-30 18:23:15

标签: sql oracle

我正在使用这样的表:

T_EARNED_DEGREES
================
STUDENT_ID   TERM_ID   DEGREE
      1000       400       BS
      1001       400       BS
      1002       400       BS
      1002       400       BS
      1003       500       BS
      1003       500       MS
      1000       600       MS

如何为同一学期获得两个(或更多)学位的学生编写一个选择所有列和行的查询?

我想我需要使用COUNTHAVING运算符,可能还需GROUP BY,但除此之外,我已经迷失了。我尝试了一些非常基本的东西:

SELECT    STUDENT_ID,
          TERM_ID
FROM      T_EARNED_DEGREES
GROUP BY  STUDENT_ID,
          TERM_ID
HAVING    COUNT(DEGREE) > 1

这种(有点)有效,给出了这些结果:

STUDENT_ID   TERM_ID
      1002       400
      1003       500

学生1000被排除在外,因为学位是以单独的条件获得的,学生1001被排除在外,因为只获得了一个学位。

但是,我希望得到这些结果,因为我想看到所有的行和列:

STUDENT_ID   TERM_ID   DEGREE
      1002       400       BS
      1002       400       BS
      1003       500       BS
      1003       500       MS

但是当我将DEGREE列添加到SELECTGROUP BY语句时,只返回一个结果:

STUDENT_ID   TERM_ID   DEGREE
      1002       400       BS

我想这是因为学生1003的学位不同(BS和MS),所以没有组合在一起。

我怎样才能得到我想要的东西?同样,我想选择所有行和列值,而不仅仅是学生和术语。 (当然,我的真实架构要广泛得多;这是一个高度简化的例子。)

2 个答案:

答案 0 :(得分:3)

select * from t_earned_degrees 
where student_id in ( 
SELECT    STUDENT_ID
FROM      T_EARNED_DEGREES
GROUP BY  STUDENT_ID,
          TERM_ID
HAVING    COUNT(DEGREE) > 1)

答案 1 :(得分:3)

您可以使用窗口COUNT

WITH cte AS (
  SELECT *, COUNT(*) OVER(PARTITION BY STUDENT_ID, TERM_ID) AS rn
  FROM T_EARNED_DEGREES
)
SELECT STUDENT_ID,TERM_ID,DEGREE
FROM cte
WHERE rn > 1;

LiveDemo

输出:

╔════════════╦═════════╦════════╗
║ STUDENT_ID ║ TERM_ID ║ DEGREE ║
╠════════════╬═════════╬════════╣
║       1002 ║     400 ║ BS     ║
║       1002 ║     400 ║ BS     ║
║       1003 ║     500 ║ BS     ║
║       1003 ║     500 ║ MS     ║
╚════════════╩═════════╩════════╝

没有cte甚至更短:

SELECT STUDENT_ID,TERM_ID,DEGREE
FROM (SELECT *, COUNT(*) OVER(PARTITION BY STUDENT_ID, TERM_ID) AS rn 
      FROM T_EARNED_DEGREES)
WHERE rn > 1