No data_found setting variable to null

时间:2015-07-28 15:36:30

标签: oracle loops plsql while-loop

The following code is setting the variable vBoleto to null when the select above return no rows. Can someone explain why please? Sometimes vBoleto wont return rows from sn_grupo_contestacao, so I need to get the id_boleto_origem from the last vBoleto found in the sn_boleto table.

Here's the full code:

declare
  --20120807
  vContrato  sn_contrato.num_contrato%type := 18111110;
  vCid       sn_contrato.cid_contrato%type := '05509';
  vBoleto    sn_boleto.id_boleto%type := 82452735;
  vOrigem    sn_boleto.id_boleto%type;
  vGrupoCont sn_grupo_contestacao.id_grupo_contestacao%type;
  vParceiro  sn_grupo_contestacao.id_parceiro%type;
  vTot       number := 0;
  vStatus    number := 0;
 begin

    --- esboço ih - contestação com itens de outras cobrancas
    select id_grupo_contestacao, id_parceiro
      into vGrupoCont, vParceiro
      from sn_grupo_contestacao
     where id_boleto = vBoleto
       and fc_situacao_grupo = 'P'
       and num_contrato = vContrato
       and cid_contrato = vCid;

  exception
    when no_data_found then

      while true loop
        begin

          select id_boleto_origem
            into vOrigem
            from sn_boleto
           where id_boleto = vBoleto;

            vBoleto := vOrigem;

        exception
          when no_data_found then
            exit;
        end;
      end loop;

  end;

1 个答案:

答案 0 :(得分:0)

The variable isn't being set to null when no data is found, it's being done on the previous iteration of the loop.

Lets say you have a simple structure:

create table sn_boleto (id_boleto number, id_boleto_origem number);
insert into sn_boleto values (1, null);
insert into sn_boleto values (2, 1);
insert into sn_boleto values (3, 1);
insert into sn_boleto values (82452735, 2);

Your first time around the loop:

select id_boleto_origem
from sn_boleto
where id_boleto = 82452735;

                       ID_BOLETO_ORIGEM
---------------------------------------
                                      2

So you set your vBoleto variable to 2 and repeat:

select id_boleto_origem
from sn_boleto
where id_boleto = 2;

                       ID_BOLETO_ORIGEM
---------------------------------------
                                      1

You set your vBoleto variable to 1 and repeat:

select id_boleto_origem
from sn_boleto
where id_boleto = 1;

                       ID_BOLETO_ORIGEM
---------------------------------------
                                 (null)

You have not got a no_data_found yet, so you still set your vBoleto variable to null; and repeat:

select id_boleto_origem
from sn_boleto
where id_boleto = null;

no rows selected

Now you get no_data_found, but it's too late, you've already set vBoleto to null.

You could avoid this by breaking out of the loop earlier, based on the value you did get rather than waiting for the exception:

      select id_boleto_origem
        into vOrigem
        from sn_boleto
       where id_boleto = vBoleto;

        if vOrigem is null then
          exit;
        end if;

        vBoleto := vOrigem;

Incidentally, your loop is reinventing hierarchical queries; you could replace that with:

...
  exception
    when no_data_found then

      select connect_by_root id_boleto
      into vBoleto
      from sn_boleto
      where id_boleto = vBoleto
      connect by prior id_boleto = id_boleto_origem
      start with id_boleto_origem is null;
  end;