未达到PL / SQL异常,函数无法返回

时间:2016-09-23 07:49:23

标签: sql oracle plsql

我有一个PL / SQL函数,遇到no_data_found时它似乎没有达到异常。我已经查看并试图将我的select语句添加到它自己的开始块中,但我总是得到语法错误。我需要在哪里放置例外?谢谢

create or replace FUNCTION is_artikl_eligible_for_zamjena (
--input vars
inSifraArtikla IN A_ZAMJENA_ARTIKLI.SIFRA_ARTIKLA%type, 
inDatumPocetak IN VARCHAR2, 
inSkladiste IN A_ZAMJENA.SKL%type,
inProdavaonice IN A_ZAMJENA.POPIS_PROD%type
)
RETURN NUMBER
is 
existingSifraArtikla A_ZAMJENA_ARTIKLI.SIFRA_ARTIKLA%type;
existingBrojZamjene A_ZAMJENA.BROJ_ZAMJENE%type;
existingDatumKraj A_ZAMJENA.DATUM_KRAJ%type;
existingSkladiste A_ZAMJENA.SKL%type;
existingProdavaonice A_ZAMJENA.POPIS_PROD%type;
BEGIN

  dbms_output.enable();
  --check if there is sifra_artikla in a_zamjena_artikli where     a_zamjena.datumKraj != null or a_zamjena.datumKraj > sysdate
  for i IN (
  SELECT azam.BROJ_ZAMJENE, azam.DATUM_KRAJ, azam.SKL, azam.POPIS_PROD, azamAr.SIFRA_ARTIKLA
  FROM A_ZAMJENA azam JOIN A_ZAMJENA_ARTIKLI azamAr 
  ON  azam.BROJ_ZAMJENE = azamAr.BROJ_ZAMJENE
  WHERE azamAr.SIFRA_ARTIKLA = inSifraArtikla
  )

LOOP
existingBrojZamjene :=i.BROJ_ZAMJENE; 
--existingDatumKraj := TO_CHAR(COALESCE(i.DATUM_KRAJ,'21-01-25 00:00'));
existingDatumKraj := i.DATUM_KRAJ;
existingSkladiste := COALESCE(i.SKL, '0');
existingProdavaonice := COALESCE(i.POPIS_PROD, 0);
existingSifraArtikla := i.SIFRA_ARTIKLA;

  if existingDatumKraj IS NOT NULL AND existingDatumKraj < (sysdate -1) then --level 0
      dbms_output.put_line('Datum kraj postojeće zamjene nije null ali je završio');
      return 1;

     else
     if (existingDatumKraj IS NULL) OR (existingDatumKraj > sysdate) then --level 1
      dbms_output.put_line('Zamjene imaju preklapajuće datume, provjeravam da li su na istim skladištima ili prodavaonicama');

         if existingSkladiste != inSkladiste OR existingProdavaonice != inProdavaonice then -- level 2
          dbms_output.put_line('Zamjene imaju preklapajuće datume ali nisu na istim skladištima ili prodavaonicama');
           return 1;

         else -- level 2
         return 0;  
        end if; --level 2
     else --else za datum kraj, level 1
     dbms_output.put_line('Zamjene nemaju preklapajuće datume');
     return 1;

    end if; --level 1
  end if; --level 0
  END LOOP;

EXCEPTION WHEN NO_DATA_FOUND THEN 
dbms_output.put_line('nema retka');

RETURN 1;

END;

2 个答案:

答案 0 :(得分:2)

未经测试,但我可能会使用局部变量来检查我的游标循环是否找到了任何行,并在最后检查。 (它可能是布尔值或计数器或其他东西。我在下面使用了一个计数器。)

create or replace function is_artikl_eligible_for_zamjena
    ( insifraartikla in a_zamjena_artikli.sifra_artikla%type
    , indatumpocetak in varchar2
    , inskladiste    in a_zamjena.skl%type
    , inprodavaonice in a_zamjena.popis_prod%type )
    return number
is
    rows_found pls_integer := 0;
begin
    dbms_output.enable();

    -- check if there is sifra_artikla in a_zamjena_artikli where a_zamjena.datumKraj != null or a_zamjena.datumKraj > sysdate
    for i in (
        select azam.broj_zamjene
             , azam.datum_kraj
             , coalesce(azam.skl,'0') as skl
             , coalesce(azam.popis_prod,0) as popis_prod
             , azamar.sifra_artikla
        from   a_zamjena azam
               join   a_zamjena_artikli azamar
               on     azamar.broj_zamjene = azam.broj_zamjene
        where  azamar.sifra_artikla = insifraartikla
    )    
    loop
        rows_found := rows_found +1;

        if i.datum_kraj < sysdate - 1 then
            --level 0
            dbms_output.put_line('Datum kraj postojeće zamjene nije null ali je završio');
            return 1;

        else
            if i.datum_kraj is null or i.datum_kraj > sysdate then
                --level 1
                dbms_output.put_line('Zamjene imaju preklapajuće datume, provjeravam da li su na istim skladištima ili prodavaonicama');

                if i.skl != inskladiste or i.popis_prod != inprodavaonice then
                    -- level 2
                    dbms_output.put_line('Zamjene imaju preklapajuće datume ali nisu na istim skladištima ili prodavaonicama');
                    return 1;

                else
                    -- level 2
                    return 0;
                end if; --level 2
            else
                --else za datum kraj, level 1
                dbms_output.put_line('Zamjene nemaju preklapajuće datume');
                return 1;

            end if; --level 1
        end if; --level 0
    end loop;

    if rows_found = 0 then
        raise no_data_found;
    end;
exception
    when no_data_found then
        dbms_output.put_line('nema retka');

        return 1;

end;

我不确定提出no_data_found例外是一种特别好的做法。事实上,我也不热衷于循环中的return。如果您只是在循环期间分配要返回局部变量的值,并且最后检查它,处理它没有值的情况,那么问题就会消失。

使用局部变量和单个返回点而不是操作异常处理程序,它看起来像这样:

create or replace function is_artikl_eligible_for_zamjena
    ( insifraartikla in a_zamjena_artikli.sifra_artikla%type
    , indatumpocetak in varchar2
    , inskladiste    in a_zamjena.skl%type
    , inprodavaonice in a_zamjena.popis_prod%type )
    return number
is
    l_result number;
begin
    dbms_output.enable();

    -- check if there is sifra_artikla in a_zamjena_artikli where a_zamjena.datumKraj != null or a_zamjena.datumKraj > sysdate
    for i in (
        select azam.broj_zamjene
             , azam.datum_kraj
             , coalesce(azam.skl,'0') as skl
             , coalesce(azam.popis_prod,0) as popis_prod
             , azamar.sifra_artikla
        from   a_zamjena azam
               join   a_zamjena_artikli azamar
               on     azam.broj_zamjene = azamar.broj_zamjene
        where  azamar.sifra_artikla = insifraartikla
    )    
    loop
        if i.datum_kraj < sysdate - 1 then
            --level 0
            dbms_output.put_line('Datum kraj postojeće zamjene nije null ali je završio');
            l_result := 1;

        else
            if i.datum_kraj is null or i.datum_kraj > sysdate then
                --level 1
                dbms_output.put_line('Zamjene imaju preklapajuće datume, provjeravam da li su na istim skladištima ili prodavaonicama');

                if i.skl != inskladiste or i.popis_prod != inprodavaonice then
                    -- level 2
                    dbms_output.put_line('Zamjene imaju preklapajuće datume ali nisu na istim skladištima ili prodavaonicama');
                    l_result := 1;

                else
                    -- level 2
                    l_result := 0;
                end if; --level 2
            else
                --else za datum kraj, level 1
                dbms_output.put_line('Zamjene nemaju preklapajuće datume');
                l_result := 1;

            end if; --level 1
        end if; --level 0
    end loop;

    if l_result is then
        dbms_output.put_line('nema retka');
        l_result := 1;
    end;

    return l_result;
end;

我不确定dbms_output.put_line来电正在做什么,但这是另一个问题。

答案 1 :(得分:1)

您无法使用for循环引发NO_DATA_FOUND异常。您可以使用goto语句进行insatance。见下面的例子。

DECLARE
   v_attr char(88);
CURSOR  SELECT_USERS IS
 SELECT id 
 FROM USER_TABLE
 WHERE USERTYPE = 'X';
BEGIN
    FOR user_rec IN SELECT_USERS 
     LOOP    
        BEGIN
            SELECT attr 
            INTO v_attr 
            FROM ATTRIBUTE_TABLE
            WHERE user_id = user_rec.id;            
         EXCEPTION
            WHEN NO_DATA_FOUND THEN
               -- user does not have attribute, continue loop to next record.
               goto end_loop; ---Adding a label
         END;

        <<end_loop>> --Label
        null;         
    END LOOP;
END;