Dúvida em PL/SQL

7 respostas
G

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

G

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.
F

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.

G

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:

G

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.

F

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

F

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