while循环控制空数据集情况(Oracle PLSQL)

Controlling the empty dataset situation in while loop ( Oracle PLSQL )

我做了这个循环:

                LOOP -- arranging loop
                
                select  num_aula, tipo_aula -- dataset A
                into    na, ta
                from ( 
                        select num_aula,tipo_aula,abs(capienza-occ.score) -- dataset B 
                        from aula
                        join( 
                                select num_aula, tipo_aula -- dataset C
                                from aula
                                where tipo_aula = get_tipo_aula(occ.Nome_modulo,i)
                                minus
                                select num_aula, tipo_aula -- dataset D
                                from occr_lezione
                                where Nome_sede = occ.Nome_sede
                                and to_char(Data_fine_occr_lezione,'hh24mi') > to_char(occ.Data_inizio_occr_lezione,'hh24mi')
                                and to_char(Data_inizio_occr_lezione,'hh24mi') < to_char(occ.Data_fine_occr_lezione,'hh24mi')
                                and to_char(Data_inizio_occr_lezione,'dd-mm-yyyy') = to_char(occ.Data_inizio_occr_lezione,'dd-mm-yyyy')) 
                                using(num_aula,tipo_aula)
                                order by y, num_aula
                     ) where rownum=1;
                i := i+1;
                EXIT WHEN (na IS NOT NULL OR i > 2);
                END LOOP; -- arranging loop end
        i:=0;

其中数据集B是C和Dselect离子相差得到的table,数据集A是它的最小值。

现在数据集 B 可以为空,因此数据集 A 必须 select 编辑为空 table,这当然会导致空 selection。

因为这不是acceptable 在我的代码中,我做了一个循环,每次发生这种情况时都应该迭代。为了减少这种情况发生的次数,我将其中一个内部参数绑定到一个函数,它会根据 i 计数器给出不同的结果。

问题是每次数据集 B 结果为空时,编码此循环的过程都会停止给我这个错误:

ERROR at line 1:
ORA-01403: no data found
ORA-06512: at "ADMIN.ASS_AULE", line 45
ORA-06512: at line 1

我该如何解决这个问题?如何强制程序在循环结束之前不放弃?

所以,这是完整的功能,我尝试在底部添加异常处理程序,如您所见:

CREATE OR REPLACE PROCEDURE pprova
AS
CURSOR c1 is
select  occr_lezione.*, 
        Cont_iscr_occr_lezione( Codice_corso, 
                                Nome_modulo,
                                Data_inizio_ed_modulo, 
                                Giorno_lezione, 
                                Ora_inizio_lezione, 
                                Data_inizio_occr_lezione
                              ) score
from occr_lezione
where trunc(Data_inizio_occr_lezione) >= trunc(next_day(sysdate,'lunedi'))
and   trunc(Data_inizio_occr_lezione) <= trunc(next_day(sysdate,'venerdi'))
and   sem_check(sysdate,Data_inizio_ed_modulo) = 1
and  year_check(Data_inizio_ed_modulo,sysdate) = 1
order by score ;
occ c1%ROWTYPE;
na  NUMBER;
ta  VARCHAR2(20);
sc  NUMBER;
i   NUMBER;
BEGIN
i := 0;
--
OPEN c1;
LOOP
            FETCH c1 INTO occ;
            EXIT WHEN c1%NOTFOUND;          
            IF occ.num_aula IS NULL AND occ.tipo_aula IS NULL
            THEN
                    LOOP -- arranging loop
                    -- dataset A
                    select  num_aula, tipo_aula
                    into    na, ta
                    from ( 
                            -- dataset B
                            select num_aula,tipo_aula,abs(capienza-occ.score) y
                            from aula
                            join(
                                    select num_aula, tipo_aula
                                    from aula
                                    where tipo_aula = get_tipo_aula(occ.Nome_modulo,i)
                                    minus
                                    select num_aula, tipo_aula
                                    from occr_lezione
                                    where Nome_sede = occ.Nome_sede
                                    and to_char(Data_fine_occr_lezione,'hh24mi') > to_char(occ.Data_inizio_occr_lezione,'hh24mi')
                                    and to_char(Data_inizio_occr_lezione,'hh24mi') < to_char(occ.Data_fine_occr_lezione,'hh24mi')
                                    and to_char(Data_inizio_occr_lezione,'dd-mm-yyyy') = to_char(occ.Data_inizio_occr_lezione,'dd-mm-yyyy')) 
                                    using(num_aula,tipo_aula)
                                    order by y, num_aula
                         ) where rownum=1;
                    EXIT WHEN (na IS NOT NULL OR i > 2);
                    END LOOP; -- arranging loop end
            i:=0;
            UPDATE  occr_lezione
                SET     Num_aula  = na,
                        Tipo_aula = ta
                WHERE   Codice_corso   = occ.Codice_corso
                AND     Nome_modulo    = occ.Nome_modulo
                AND     Giorno_lezione = occ.Giorno_lezione
                AND     Ora_inizio_lezione = occ.Ora_inizio_lezione
                AND     Data_inizio_occr_lezione = occ.Data_inizio_occr_lezione;
            END IF;
END LOOP; -- fine loop di fetching
EXCEPTION
WHEN no_data_found
THEN
IF i < 2
THEN NULL; -- Do nothing
ELSE RAISE_APPLICATION_ERROR (-20016,'non esistono combinazioni valide');
END IF;
END;
/

但是每次上面所说的数据集为空时,它都会跳过整个 select - 更新部分。

如果我在关注你的问题,听起来你想要捕获 no_data_found 异常

LOOP
  BEGIN
    <<your SELECT INTO>>
  EXCEPTION
    WHEN no_data_found
    THEN
      NULL; -- Do nothing
  END;

  i := i + 1;
  ...
END LOOP;

这假定您希望在 SELECT 语句 returns 没有数据时递增 i。如果你想让你的一些逻辑只在SELECT语句returns一行时执行,你可以把它放在BEGINEXCEPTION关键字之间。

不知道您要解决的问题,当我看到带有 rownum = 1 谓词的 SELECT INTO 时,我总是很担心。如果你的查询 returns 多行,你为什么要选择任意一行数据来填充你的局部变量?我很难想出很多有意义的案例。如果你想选择一个特定的行,明确地编码(即使用适当的 MAXMIN 聚合函数,使用分析函数 rank 对行进行排名并选择一个,等等.)

因为我已经 post 编辑了完整的代码,所以我也会 post 解决方案 :

CREATE OR REPLACE PROCEDURE pprova
AS
CURSOR c1 is
select  occr_lezione.*, 
        Cont_iscr_occr_lezione( Codice_corso, 
                                Nome_modulo,
                                Data_inizio_ed_modulo, 
                                Giorno_lezione, 
                                Ora_inizio_lezione, 
                                Data_inizio_occr_lezione
                              ) score
from occr_lezione
where trunc(Data_inizio_occr_lezione) >= trunc(next_day(sysdate,'lunedi'))
and   trunc(Data_inizio_occr_lezione) <= trunc(next_day(sysdate,'venerdi'))
and   sem_check(sysdate,Data_inizio_ed_modulo) = 1
and  year_check(Data_inizio_ed_modulo,sysdate) = 1
order by score ;
occ c1%ROWTYPE;
na  NUMBER;
ta  VARCHAR2(20);
sc  NUMBER;
i   NUMBER;
BEGIN
i := 0;
--
OPEN c1;
LOOP
            FETCH c1 INTO occ;
            EXIT WHEN c1%NOTFOUND;          
            IF occ.num_aula IS NULL AND occ.tipo_aula IS NULL
            THEN
            BEGIN
                    LOOP -- arranging loop
                    -- dataset A
                    select  num_aula, tipo_aula
                    into    na, ta
                    from ( 
                            -- dataset B
                            select num_aula,tipo_aula,abs(capienza-occ.score) y
                            from aula
                            join(
                                    select num_aula, tipo_aula
                                    from aula
                                    where tipo_aula = get_tipo_aula(occ.Nome_modulo,i)
                                    minus
                                    select num_aula, tipo_aula
                                    from occr_lezione
                                    where Nome_sede = occ.Nome_sede
                                    and to_char(Data_fine_occr_lezione,'hh24mi') > to_char(occ.Data_inizio_occr_lezione,'hh24mi')
                                    and to_char(Data_inizio_occr_lezione,'hh24mi') < to_char(occ.Data_fine_occr_lezione,'hh24mi')
                                    and to_char(Data_inizio_occr_lezione,'dd-mm-yyyy') = to_char(occ.Data_inizio_occr_lezione,'dd-mm-yyyy')) 
                                    using(num_aula,tipo_aula)
                                    order by y, num_aula
                         ) where rownum=1;
                    EXIT WHEN (na IS NOT NULL OR i > 2);
                    END LOOP; -- arranging loop end
                    EXCEPTION
                    WHEN no_data_found
                    THEN
                    IF i < 2
                    THEN NULL; -- Do nothing
                    ELSE RAISE_APPLICATION_ERROR (-20016,'non esistono combinazioni valide');
                    END IF;
                    i:=0;
                    END;
            UPDATE  occr_lezione
                SET     Num_aula  = na,
                        Tipo_aula = ta
                WHERE   Codice_corso   = occ.Codice_corso
                AND     Nome_modulo    = occ.Nome_modulo
                AND     Giorno_lezione = occ.Giorno_lezione
                AND     Ora_inizio_lezione = occ.Ora_inizio_lezione
                AND     Data_inizio_occr_lezione = occ.Data_inizio_occr_lezione;
            END IF;
END LOOP; -- fine loop di fetching
END;
/

正如 Justin 所指出的,异常范围由它所在的开始 - 结束代码块定义。这非常有趣,因为这意味着您实际上可以将代码分成块并为每个不同的异常处理程序定义.考虑到这一点,我只是将我的循环放在一个开始 - 结束块中并在其中声明处理程序。