Oracle 计算子查询中的不同记录

Oracle count distinct record within subquery

我有 3 张桌子

主题

CODE, SUBJECT_NAME      , SESSION
 100, MATHS             , AM
 101, MATHS - INTRO     , AM
 102, MATHS - ADVANCED  , AM
 200, ENGLISH           , AM
 201, ENGLISH - INTRO   , AM
 202, ENGLISH - BEGINNER, AM
 203, ENGLISH - ADVANCED, AM

STUDENTS_SUBJECTS

ID, SUBJECT_CODE
 2, 101
 2, 102
 1, 201
 1, 203
 3, 101
 3, 102

学生

ID,PARENT_ID, STUDENT_NAME, CLASS_LEADER, INACTIVE, EXPERT
1 , 2       , ELSA        , no          , N       , N
2 , 4       , STEVE       , no          , N       , N
3 , 5       , MIKE        , no          , N       , N

我的查询是这样的

SELECT    t1.CODE,  
          t1.SUBJECT_NAME,
          SUM (CASE WHEN  ( (t2.CLASS_LEADER = 'no' 
                               OR t2.CLASS_LEADER IS NULL) 
                       AND t2.EXPERT IS NULL) 
              THEN 1  ELSE 0 END) AS "Average Student"
FROM subjects t1
LEFT OUTER JOIN ( 
              select a.STUDENT_ID, a.PARENT_ID, a.STUDENT_NAME,  
                          a.CLASS_LEADER, c.SUBJECT_CODE, a.INACTIVE, a.EXPERT
               FROM students a
               INNER JOIN  students_subjects c  
                     ON (a.STUDENT_ID = c.ID ) 
                where (INACTIVE is null)
                GROUP BY a.STUDENT_ID, a.PARENT_ID, a.STUDENT_NAME, a.CLASS_LEADER, c.SUBJECT_CODE, a.INACTIVE, a.EXPERT
) t2
ON substr(trim(t2.SUBJECT_CODE),1,2)= substr(trim(t1.CODE),1,2)
WHERE (t1.SESSION='AM') 
GROUP BY t1.CODE, T1.SUBJECT_NAME
ORDER BY T1.CODE

我想得到的是class每个主科的上午班报名没有重复的学生人数。例如,每个报名参加 Maths - Intro & Maths Advanced 的学生只能在 Maths 科目下计算一次。

如果我 运行 子查询分别减去 select 语句中的 subject_code 并按语句分组,我设法获得了正确的值但是我不确定如何 return 加入查询时的正确值。

报告

CODE, SUBJECT_NAME, AVERAGE_STUDENT
100 MATHS 2
200 ENGLISH 1

谢谢。

您发布的查询包含很多无关的逻辑,这些逻辑似乎与您的明显任务无关。所以我忽略它并专注于简单地获取 "the number of students who signed up for the class for morning session under each major subject without the duplicates".

select major
       , count(*)
from (
    select distinct subj.major
           , ss.id as student_id
    from
          ( select code, 
                  regexp_replace(subject_name, '^([A-Z]+)(.*)', '') major ,
             from subjects
             where session = 'AM'
           ) subj
           join student_subjects ss
                 on ss.subject_code = subj.code
    )
group by major
order by major
/ 

SUBJECTS 上的子查询使用正则表达式函数提取主题名称的前导元素作为主要元素。它适用于已发布的示例数据,但对于更复杂的名称可能会失败。不需要正则表达式:适当的数据模型会将主要主题与其子公司分开。

先推荐一下:

1) 将列 MAIN_SUBJECT_CODE 添加到 table 主题(如前所述)

2) table STUDENTS_SUBJECTS 中的列 ID 是指向 table STUDENT 的外键,因此更好的名称是 STUDENT_ID

3) 使用独特的机制来存储布尔值不要混合使用 'no' 和 'N'

首先查询所有学生订阅

请注意,我添加了缺失的列 main_subject_code 并调整了平均学生定义以获得一些结果。

 SELECT    su.CODE,  
           substr(trim(su.CODE),1,2)||'0' main_subject_code,
           su.SUBJECT_NAME,
           st.STUDENT_NAME,
           CASE WHEN  ( (st.CLASS_LEADER = 'no' 
                                OR st.CLASS_LEADER IS NULL) 
                        AND st.EXPERT = 'N' /*IS NULL*/) 
               THEN 1  ELSE 0 END AS "Average Student"
 FROM subjects su
 INNER JOIN students_subjects ss
 ON  su.code = ss.SUBJECT_CODE
 INNER JOIN STUDENTS st
 ON ss.ID  /* STUDENT_ID */ = st.ID 
 ;

 CODE MAIN_SUBJECT_CODE SUBJECT_NAME              STUDENT_NAME              Average Student

   101 100               MATHS - INTRO             MIKE                                    1 
   101 100               MATHS - INTRO             STEVE                                   1 
   102 100               MATHS - ADVANCED          MIKE                                    1 
   102 100               MATHS - ADVANCED          STEVE                                   1 
   201 200               ENGLISH - INTRO           ELSA                                    1 
   203 200               ENGLISH - ADVANCED        ELSA                                    1 

剩下的很简单 - 在主要主题上分组并添加它的标题

 with subsr as (
 SELECT    su.CODE,  
           substr(trim(su.CODE),1,2)||'0' main_subject_code,
           su.SUBJECT_NAME,
           st.STUDENT_NAME,
           CASE WHEN  ( (st.CLASS_LEADER = 'no' 
                                OR st.CLASS_LEADER IS NULL) 
                        AND st.EXPERT = 'N' /*IS NULL*/) 
               THEN 1  ELSE 0 END AS "Average Student"
 FROM subjects su
 INNER JOIN students_subjects ss
 ON  su.code = ss.SUBJECT_CODE
 INNER JOIN STUDENTS st
 ON ss.ID  /* STUDENT_ID */ = st.ID 
 )
 select 
   main_subject_code,
   (select SUBJECT_NAME from SUBJECTS where CODE = main_subject_code) main_subject_name,
   sum("Average Student") "Average Student"
 from  subsr
 group by main_subject_code
 order by main_subject_code;


 MAIN_SUBJECT_CODE MAIN_SUBJECT_NAME         Average Student
 ----------------- ------------------------- ---------------
 100               MATHS                                   4 
 200               ENGLISH                                 2