Dúvida em PL/SQL

7 respostas
guj1

Estou há duas semanas tentando criar uma função PL/SQL para verificar se um boleto foi pago em dia ou não e caso o vencimento caia num feriado ou final de semana o vencimento passa para o próximo dia útil, caso tenha sido pago após a data de vencimento.

O problema é basicamente o descrito

Criei duas tabelas BOLETO e CALENDARIO (foi utilizado o mês de novembro em razão dos feriados) Já povoei as duas entidades.

Minha dificuldade é, no oracle não existe o tipo boolean, portanto não tive como eu definir os feriados e os finais de semana como TRUE, eles estão como number com valor 1 para sim e 0 para não, ou seja, 1 é feriado ou final de semana e 0 não é feriado nem final de semana.

Aqui está a função:

create or replace
function
CALCULAR_VL_PAGAMENTO(V_CD_BARRAS in varchar2)
return varchar2 is


--Definição de variáveis.
data_vencimento date;
data_vencimento_antiga date;
data_pagamento date;
data_calendario date;
dia_util date;
feriado number;
final_semana number;
atraso number := 0;
valor_documento number(10,2);
valor_pago number(10,2);
verifica_valor_pago number(10,2);
valor_multa number(10,2);
valor_juros number(10,2);
acrescimo number(10,2);
mensagem varchar2(1000);


begin


--Select para recuperar as colunas das duas tabelas que serão utilizadas no corpo da função.


select dt_vencimento, dt_pagamento, vl_documento, vl_acrescimo, vl_pagamento, dt_calendario, bo_feriado, bo_final_semana
into data_vencimento, data_pagamento, valor_documento, acrescimo, valor_pago, data_calendario, feriado, final_semana
from boleto B inner join calendario C on B.dt_vencimento = C.dt_calendario
where cd_barras = v_cd_barras;


valor_multa := 0.10 * valor_documento;
valor_juros := 0.0033 * valor_documento;




--Se o pagamento for menor ou igual à data de vencimento entra aqui
if data_pagamento <= data_vencimento then
  mensagem := 'pagamento dentro do prazo!'
  ||' data de vencimento: '||to_char(data_vencimento, 'dd-mm-yyyy')
  ||'. data de pagamento: '||to_char(data_pagamento, 'dd-mm-yyyy')
  ||' valor pago: R$ '||to_char(valor_pago)||'.';
  
/*
senão (o pagamento ocorreu após o vencimento) entra aqui e verifica se o vencimento caiu num dia não útil para jogar o vencimento para o próximo dia útil.
*/  


else


  data_vencimento_antiga := data_vencimento; /*Guardando a data de vencimento original*/
    
   /*Aqui se eu usar somente  final_semana = 1 or feriado = 1  não entra no while por isso a rendundância data_pagamento > data_vencimento que  foi a condição para entrar no else. O problema está nessa condição pq ele não está avaliando o feriado nem o final de semana pq no final data de vencimento será igual à data de pagamento.
Eu utilizei um boleto que foi pago em 14-11-2012 e venceu num sábado 10-11-2012.
*/
    while data_pagamento > data_vencimento and final_semana = 1 or feriado = 1 loop
      data_vencimento := data_vencimento + 1;
      atraso := 0;
    end loop;

    /*Aqui é  um teste para testar o while e  tentei o que sei e sempre as datas de pagamento e vencimento saem iguas.*/    
    mensagem := to_char(data_pagamento, 'dd-mm-yyyy')||'  '||to_char(data_vencimento, 'dd-mm-yyyy');
    
end if;
return mensagem;


end;

Muito grato pela atenção de quem responder.

7 Respostas

guj1

Bom dia,

Eu só gostaria de saber porque o while abaixo só itera a data_vencimento uma vez, eu usei a data 10-11-2012, sendo assim, enquanto a data do pagamento for maior que o vencimento final de semana ou feriado ele deveria iterar a até a condição ser falsa, mas ele não está verificando os valores do final de semana e do feriado.

<blockquote>

while data_pagamento > data_vencimento and final_semana = 1 or feriado = 1 loop

data_vencimento := data_vencimento + 1;

atraso := 0;

end loop;

</blockquote>

Alguém poderia me dar uma força?

Eu nunca programei em PL/SQL o professor não explica nada apenas deu ordem para estudarmos (ou seja, ou você se vira ou não passa na matéria), aprendi muito em 3 semanas, mas não foi suficiente para fazer a função funcionar.
furutani

Olá
As variáveis data_pagamento, data_vencimento, final_semana, feriado podem ficar nulas?
Caso possa, você tem que trata-las para funcionar da forma como quer usando nvl(). Em PLSQL é chato tratar nulos, pois nulo não é igual a nulo.

guj1

Não!
Antes sim, mas eu recriei a tabela e deixei como not null.
O tipo eu pus char(1)

Mas mesmo assim, estou com o mesmo resultado, ele continua não avaliando o feriado nem o final de semana.
Alguma dica gente?

Grato pela atenção

E
while data_pagamento > data_vencimento and final_semana = 1 or feriado = 1 loop  
      data_vencimento := data_vencimento + 1;  
      atraso := 0;  
    end loop;

Pelo que imagino, você vai precisar de um cursor. Não é trivial eu explicar direitinho como se usam cursores, mas a pista está dada aqui. Dica: o “while” que você fez não usa cursores, portanto o valor da variável “feriado” não varia :slight_smile:

guj1

Depois que abri o tópico eu percebi que falta algo, li, li , li e desconfiei de que precisava de cursor, estou estudando cursor agora para concluir o trabalho. Entretanto, eu nunca tinha visto PL/SQL na vida, ou seja, estou muito perdido, mas como sempre fui auto-didata acho que consigo mesmo sem explicação nenhuma de ninguém…

Obrigado pela compreensão de quem se deu ao menos o trabalho de ler o tópico.

Grato, encerrando tópico.

fantomas

Na minha opinião isto ocorre por 2 motivos:

  1. A expressão lógica que vc escreveu diz pra fazer exatamente isto mesmo, quando as duas datas ficam iguais o processamento do ciclo é encerrado.
  2. O amigo entanglement apontou o fato de não considerar a leitura da tabela calendario;

Reflexões:

  1. Esta tabela calendario, possui TODOS os dias dos meses / anos não importando se é feriado, final de semana ou não? Se sim, não seria mais interessante você criar uma tabela de feriados (menos registros) e utilizar a função to_char(data,‘d’) (ref http://stackoverflow.com/questions/3450965/determine-if-oracle-date-is-on-a-weekend) para saber se é dia regular ou final de semana?

  2. Se utilizar a estratégia descrita anteriormente talvez você não vá precisar de um cursor.

  3. Se você criar uma função que encapsule todos os detalhes ref. a nova data de vencimento seu código ficaria bem menor e muito mais fácil de entender.

    • Sugestão: Nesta função se a data de pagamento não for final de semana (função pl/sql) e nem feriado (tabela) simplesmente retorne a mesma data, sem alterações.

Estas reflexões poderão causar forte impacto no seu código atual, portanto se você decidir alterar faça um backup antes.

flws

fantomas

Putz não vi que você estava encerrando o tópico kkkkk.

flws

Criado 13 de setembro de 2012
Ultima resposta 19 de set. de 2012
Respostas 7
Participantes 4