如何在不写select的情况下进行分组

时间:2018-09-26 08:33:55

标签: sql oracle group-by

我正在尝试在oracle中编写一个SQL脚本,该脚本按不同列对数据进行分组。

让我们看下面的示例:

class_name  year student_id  grade   exam-id
---------   ---- ---------   -----   ------- 
A           2012  3         90      1
A           2012  4         80      1
A           2012  5         70      1
A           2013  3         90      1
A           2013  4         100     2
A           2013  5         70      1
A           2014  3         90      1
A           2014  4         100     2
A           2014  5         75      3
A           2015  3         85      4
A           2015  4         95      4
A           2015  5         80      4
A           2016  3         85      4
A           2016  4         90      5
A           2016  5         90      5

上表显示名为“ A”的班级,该班级每年有3名学生以及特定考试的成绩。每年都有一次新考试,如果学生决定参加考试,则表中将填入新的考试ID,否则(即学生未参加考试)表将再次被旧考试填入-id(和旧等级)

现在,我想显示每年实际参加考试的学生人数。

所以结果应该像这样:

class_name  year  num_of_students_took_the_exam
---------   ----  -----------------------------
A           2012   3
A           2013   1
A           2014   1
A           2015   3
A           2016   2

我知道如何使用select和group-by以及select和group-by结果。但这似乎太复杂了。

select class_name, year, count(year)
from
  (select 
     class_name, min(year) as year, student_id, grade, min(exam-id) 
   from 
     my_table
   Where 
     class_name = 'A'
   group by
     class_name, student_id, grade)
group by
  class_name, year

是否有任何简单的sql脚本返回相同的结果?

谢谢

4 个答案:

答案 0 :(得分:3)

可以稍微简化当前查询,但不能删除嵌套的聚合:

select class_name, year, count(*)
from
  (select 
     class_name, min(year) as year, student_id, exam_id
   from 
     my_table
   Where 
     class_name = 'A'
   group by
     class_name, student_id, exam_id) -- don't group by grade, there might be two different exams with the same grade
group by
  class_name, year

用LAG(或ROW_NUMBER)重写可能不是更简单/更有效

答案 1 :(得分:0)

你能做...

select distinct class_name, year, count (distinct class_name+'-'+min(year)+'-'+student_id+'-'+exam_id) as cnt
from my_table
where class_name = 'A'

答案 2 :(得分:0)

您可以将row_number()函数与class_name, year, student_id, exam_id分组一起使用(主要逻辑取决于student_idexam_id的分组),如以下:

  select class_name, year, 
         count(rn) as num_of_students_took_the_exam
    from
  (  
    select class_name, year,exam_id,student_id, 
           row_number() over (partition by student_id, exam_id order by year ) as rn
      from Exams 
     group by class_name, year, student_id, exam_id   
     order by class_name, year, student_id, exam_id
  )
  where rn = 1
  group by class_name, year;

SQL Fiddle Demo

答案 3 :(得分:0)

您应该列出哪些年份参加了哪些考试。就您而言,您使用的是序列号。如果这是您的数据的真正结构,那么您可以:

select year, count(*)
from example e
where year - exam_id = 2012
group by year;

在实践中,这样的查询不会使用魔术数学。而是这样的:

select e.year, count(*)
from example e join
     exams ee
     on e.exam_id = ee.exam_id
where e.year = ee.year
group by e.year;