[firebase-br] Truncar valor Firebird 2.0
Eduardo Jedliczka
edujed em gmail.com
Qua Jul 20 08:16:34 -03 2011
O problema deste método é que um double precision TEM valores com mais
de 3 casas decimais. (Mesmo que num select ele comumente exiba apenas
3 casas após a vírgula)
Quem duvidar, faça um teste:
select 15 / cast(7 as double precision)from rdb$database
e depois:
select 15 / cast(7 as double precision)*100000000000 from rdb$database
.....
Portanto, mesmo que visualmente o valor seja um hipotético 1234.456,
ele poderia estar armazenado na memória com uma "pequena" variação, do
tipo:
select cast (12345.4567891234567 as double precision) from rdb$database
portanto fazer um :
select CAST( *valor do tipo double* /10*10 AS NUMERIC(18,2)) from rdb$database
verá que retornou 1234.46, sendo que o esperado seria 1234.45
Então se alguém sugerir...
select CAST(CAST( *valor do tipo double* as Numeric(18,3))/10*10 AS
NUMERIC(18,2)) from rdb$database
também irá apresentar o problema, pois será feito o arredondamento
"para cima" nativo do tipo numeric.
Claro que quando realizamos um select com uma constante numérica, o
firebird estará trabalhando com um "Numeric", não com um "Double".
Portanto, para "entender" o problema do Hélio, é preciso usar um cast
no valor para convertê-lo para double.
Portanto, não vejo muitas saídas:
1ª) UDF
2º) procedure do Daniel (eu não cheguei a testar ela, mas "confio" na fonte)
3º) Usar um IIF (se não me engano existe no FB 2.0) e ver se o valor
com cast é "maior" do que o valor double... como este
select iif( cast(cast(* valor do tipo double * as numeric(15,2)) as
double precision) > * valor do tipo double *, -0.01, 0.00) + cast(*
valor do tipo double * as numeric(15,2)) as valor_truncado from
rdb$database
==========================
Eduardo Jedliczka
Apucarana - Pr
==========================
2011/7/19 Fernando Gutierres <fernando em onclicksistemas.com.br>:
> Como o amigo anteriormente disse, basta dividir por 10 e multiplicar por 10.
> Faça o teste
>
> select CAST(3777.725/10*10 AS NUMERIC(18,2)) from rdb$database
>
> 2011/7/19 Tecnobyte Informática <temp2 em tecnobyte.com.br>:
>> Boa tarde
>>
>> Escrevi um procedimento que talvez resolva seu problema:
>>
>> SET TERM ^ ;
>>
>> CREATE OR ALTER PROCEDURE SP_Trunc(FloatValue DOUBLE PRECISION, Decimals
>> SMALLINT)
>> RETURNS(Result DOUBLE PRECISION) AS
>> DECLARE VARIABLE StrValue VARCHAR(50);
>> DECLARE VARIABLE StrInt VARCHAR(50);
>> DECLARE VARIABLE StrFrac VARCHAR(50);
>> DECLARE VARIABLE AfterSep SMALLINT;
>> DECLARE VARIABLE DecCount SMALLINT;
>> BEGIN
>> IF (FloatValue IS NULL) THEN
>> Result = NULL;
>> ELSE
>> BEGIN
>> StrValue = FloatValue;
>> StrInt = '';
>> StrFrac = '';
>> AfterSep = 0;
>> DecCount = 0;
>> WHILE (StrValue <> '') DO
>> BEGIN
>> IF (SUBSTRING(StrValue FROM 1 FOR 1) = '.') THEN
>> AfterSep = 1;
>> ELSE
>> BEGIN
>> IF (AfterSep = 0) THEN
>> StrInt = StrInt || SUBSTRING(StrValue FROM 1 FOR 1);
>> ELSE IF (DecCount >= Decimals) THEN
>> BREAK;
>> ELSE
>> BEGIN
>> StrFrac = StrFrac || SUBSTRING(StrValue FROM 1 FOR 1);
>> DecCount = DecCount + 1;
>> END
>> END
>> StrValue = SUBSTRING(StrValue FROM 2 FOR 50);
>> SUSPEND;
>> END
>> Result = StrInt || '.' || StrFrac;
>> END
>> SUSPEND;
>> END^
>>
>> SELECT * FROM SP_Trunc(1.666, 2); /* Result: 1.66 */
>>
>>
>> Atenciosamente.
>>
>> Daniel P. Guimarães
>> Tecnobyte Informática
>> www.tecnobyte.com.br
Mais detalhes sobre a lista de discussão lista