Pesquisar este blog

quarta-feira, 20 de janeiro de 2010

Vou ter que ensinar o Firebird a fazer aritmética

Bem, vou iniciar este post depois de muita depuração. Em nosso ERP PoliGestor, realizamos um cálculo para encontrar o lucro bruto para os produtos cadastrados. Acontece que no Delphi a expressão resulta em um valor diferente que a mesma expressão computada via SQL.

Eis a expressão no código fonte:
Lucro:= TruncFloat((ADO_EstoquePRC_VENDA.AsCurrency -                                                           ADO_EstoquePRC_CUSTO.AsCurrency) / ADO_EstoquePRC_CUSTO.AsCurrency * 100, 9);

A mesma expressão em um formato mais legível é:
vLucro:= trunc(((prc_venda - prc_custo) / prc_custo) * 100, 9);

  Resultado no Delphi usando o tipo REAL para vLucro: 80,375180375

Esta expressão é truncada para 9 casas para ter uma precisão boa em nosso sistema. Então qual é o problema ? Se executarmos esta mesma expressão no servidor RDBMS Firebird, o resultado é 80.370000000 em uma stored procedure (codificando vLucro com tipo NUMERIC(12, 9)) ou 80.37 quando executado via SQL.

A instrução SQL é a seguinte:
select ((200 - 110.88)/110.88)*100 from rdb$database

Resultado: 80.37
Versão do Firebird: 2.5

SOLUÇÂO

A solução encontrada foi ensinar o Firebird a fazer a aritmética, promovendo um número da expressão, como segue:

select ((cast(200 as numeric(12, 9)) -  110.88)/110.88)*100 from rdb$database

Resultado: 80,375180375


Esta solução funcionou mas me deixou preocupado com os demais cálculos realizados pelo sistema. Sabemos que o Firebird realiza cálculos com precisão diferente de outros bancos e de outras linguagens de programação e isso pode acarretar problemas em arredondamentos e cálculos de porcentagens.

CONCLUSÂO

Sabe-se que cada RDBMS usa um esquema diferente para promover seus tipos. A conversão implícita (automática), nem sempre é o que queremos. No ORACLE, por exemplo, é recomendado usar to_number para fazer as conversões. Depois de fazer a promoção de uma parte da expressão para NUMERIC(12, 9) o cálculo ficou correto porque foi informado ao Firebird que os cálculos devem ser entre números com tipos NUMERIC(12, 9).

É isso ai, até mais!

Nenhum comentário:

Postar um comentário