程序需要几个小时才能完成

时间:2014-09-11 13:08:10

标签: sql performance plsql procedure banner

我正在尝试生成一份报告,告诉我每个科目每个学期每个字母的每个成绩的百分比。最终报告将主题代码(如MAT,ENC等)作为行标题,然后将术语和字母等级作为列标题。我现在正在遍历每个主题,然后是每个学期,然后是每个年级,需要2个多小时才能完成。什么是正确/更有效的方法来实现这一目标。如果您有任何疑问,请随时询问。谢谢你的帮助!!

v_subj          varchar2(5);
v_grade         varchar2(5);
v_termloop      varchar2(6);
c_total         number;
c_dfw           number;
c_gradetotal    number;
c_gradedfw      number;
v_output    varchar2(1000);


Cursor Get_Terms is
select distinct ssbsect_term_code from ssbsect
where ssbsect_term_code >= 201230
and ssbsect_term_code not like '%5'
order by 1;

Cursor Get_Subj is
Select distinct ssbsect_subj_code from ssbsect
where ssbsect_term_code >= 201230
and ssbsect_insm_code = 'DL'
and ssbsect_term_code not like '%5'
order by 1;

Cursor Get_Grade is
select distinct msvcrse_grde_code from msvcrse
where msvcrse_grde_code in ('A','B','C','D','F','S','U','W')
order by 1;

Cursor Get_Total is
select count(msvcrse_pidm) from msvcrse
join ssbsect on msvcrse_crn = ssbsect_crn
                           and msvcrse_Term_code = ssbsect_term_code
where msvcrse_term_code = v_termloop
and ssbsect_insm_code = 'DL'
and msvcrse_crse_numb < '3000'
and msvcrse_subj_code = v_subj
and msvcrse_gmod_code <> 'D';

Cursor Get_GradeTotal is
select count(msvcrse_pidm) from msvcrse
join ssbsect on msvcrse_crn = ssbsect_crn
                           and msvcrse_Term_code = ssbsect_term_code
where msvcrse_term_code = v_termloop
and ssbsect_insm_code = 'DL'
and msvcrse_grde_code like '%'||v_grade||'%'
and msvcrse_crse_numb < '3000'
and msvcrse_subj_code = v_subj
and msvcrse_gmod_code <> 'D';


Begin

Open Get_Subj;
    Loop
    Fetch Get_Subj into v_subj;
    Exit when Get_Subj%NOTFOUND;
    v_output := '';

    v_output := v_subj;

    Open Get_Terms;
        Loop
        Fetch Get_Terms into v_termloop;
        Exit when Get_Terms%NOTFOUND;   


        Open Get_Grade;
            Loop
            Fetch Get_Grade into v_grade;
            Exit when Get_grade%NOTFOUND;


            Open Get_Total;
            Fetch Get_Total into c_total;
            Close Get_Total;


            Open Get_GradeTotal;
            Fetch Get_GradeTotal into c_gradetotal;
            Close Get_GradeTotal;

            if c_total = 0 then
                c_total := NULL;
            end if; 

            v_output := v_output ||'|'||nvl(100*(round(c_gradetotal/c_total,3)),0);

            --dbms_output.put_line(v_subj||'|'||v_termloop||'|'||v_insm||'|'||nvl(100*(round(c_dfw/c_total,3)),0));



            End Loop;
        Close Get_Grade;

        End Loop;
    Close Get_Terms;

    dbms_output.put_line(v_output);

1 个答案:

答案 0 :(得分:0)

我改变了你的代码,但结果应该是一样的。

请合并游标get_grade和get_gradetotal,在这段代码中没有任何意义。

DECLARE
  c_total      NUMBER;
  v_output     VARCHAR2 ( 1000 );


  CURSOR get_subj  IS
      SELECT DISTINCT ssbsect_subj_code
        FROM ssbsect
       WHERE ssbsect_term_code >= 201230
         AND ssbsect_insm_code = 'DL'
         AND ssbsect_term_code NOT LIKE '%5'
    ORDER BY 1;

  CURSOR get_terms  IS
      SELECT DISTINCT ssbsect_term_code
        FROM ssbsect
       WHERE ssbsect_term_code >= 201230
         AND ssbsect_term_code NOT LIKE '%5'
    ORDER BY 1;

  CURSOR get_total ( lci_termloop IN ssbsect.msvcrse_term_code%TYPE
                   , lci_subj     IN msvcrse.msvcrse_subj_code%TYPE ) IS
    SELECT COUNT ( msvcrse_pidm )
      FROM msvcrse
           JOIN ssbsect
             ON msvcrse_crn = ssbsect_crn
            AND msvcrse_term_code = ssbsect_term_code
     WHERE msvcrse_term_code = lci_termloop
       AND ssbsect_insm_code = 'DL'
       AND msvcrse_crse_numb < '3000'
       AND msvcrse_subj_code = lci_subj
       AND msvcrse_gmod_code <> 'D';

  CURSOR get_grade  IS
      SELECT DISTINCT msvcrse_grde_code
        FROM msvcrse
       WHERE msvcrse_grde_code IN ('A', 'B', 'C', 'D', 'F', 'S', 'U', 'W')
    ORDER BY 1;

  CURSOR get_gradetotal ( lci_termloop IN ssbsect.msvcrse_term_code%TYPE
                        , lci_grade    IN msvcrse.msvcrse_grde_code%TYPE
                        , lci_subj     IN msvcrse.msvcrse_subj_code%TYPE ) IS
    SELECT COUNT ( msvcrse_pidm ) AS msvcrse_pidm
      FROM msvcrse
           JOIN ssbsect
             ON msvcrse_crn = ssbsect_crn
            AND msvcrse_term_code = ssbsect_term_code
     WHERE msvcrse_term_code = lci_termloop
       AND ssbsect_insm_code = 'DL'
       AND msvcrse_grde_code LIKE '%' || lci_grade || '%'
       AND msvcrse_crse_numb < '3000'
       AND msvcrse_subj_code = lci_subj
       AND msvcrse_gmod_code <> 'D';
BEGIN

  FOR rec_subj IN get_subj LOOP
    v_output := rec_subj.ssbsect_subj_code;

    FOR rec_term IN get_terms LOOP

      OPEN get_total ( lci_termloop => rec_term.ssbsect_term_code
                     , lci_subj     => rec_subj.ssbsect_subj_code );
      FETCH get_total INTO c_total;
      CLOSE get_total;

      FOR rec_grade IN get_grade LOOP
        <<grade_total>>
        FOR rec_gradetotal IN get_gradetotal ( lci_termloop => rec_term.ssbsect_term_code
                                             , lci_grade    => rec_grade.msvcrse_grde_code
                                             , lci_subj     => v_output ) LOOP
          IF c_total = 0 THEN
            c_total := NULL;
            v_output := v_output || '|';
            CONTINUE grade_total; -- <-- AVOID WORK
          END IF;

          v_output := v_output || '|' || NVL ( 100 * ( ROUND ( rec_gradetotal.msvcrse_pidm / c_total, 3 ) ), 0 ); -- <-- PLEASE MAKE THIS CODE BETTER
          --dbms_output.put_line(rec_subj.ssbsect_subj_code||'|'||rec_term.ssbsect_term_code||'|'||v_insm||'|'||nvl(100*(round(c_dfw/c_total,3)),0));
        END LOOP grade_total;
      END LOOP;
    END LOOP;

    --DBMS_OUTPUT.put_line ( rec_subj.ssbsect_subj_code );
  END LOOP;

END;

我在没有编译的情况下更改了所有代码,请确保在游标中使用了类型。

我猜50%的改进,但你需要测试。

让我知道您是否有任何疑问,请在SQL中使用表别名,并注意循环。

谢谢。