Oracle在子查询

时间:2015-10-25 03:18:58

标签: oracle subquery

我有3张桌子

SUBJECTS

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

我想得到的是在没有重复的情况下,在每个主要科目下报名参加上午课程的学生人数。例如,每个注册数学的学生 - 简介&数学高级只应在数学科目下计算一次。

如果我单独运行子查询减去select语句和group by语句中的subject_code,我设法得到正确的值但是我不确定如何在它加入时返回正确的值查询。

REPORT

CODE, SUBJECT_NAME, AVERAGE_STUDENT
100 MATHS 2
200 ENGLISH 1

谢谢。

2 个答案:

答案 0 :(得分:0)

您发布的查询包含许多无关紧要的逻辑,这些逻辑似乎并不适合您的明显任务。因此,我忽略了它,并专注于简单地获得“在没有重复的情况下,在每个主要科目下报名参加早班会议的学生人数”。

select major
       , count(*)
from (
    select distinct subj.major
           , ss.id as student_id
    from
          ( select code, 
                  regexp_replace(subject_name, '^([A-Z]+)(.*)', '\1') 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 :(得分:0)

首先是一些推荐:

1)将MAIN_SUBJECT_CODE列添加到表SUBJECTS(已注释)

2)表STUDENTS_SUBJECTS中的列ID是指向表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