Stored Procedure e function ROUNDABNT para SQL Firebird
Fala galera do Show Delphi, tudo beleza?
Este dias estava tendo problemas com o uma nota de consumidor emitida e os dados salvos.
Percebi que tinha um caso em que o valor total do item era 1,365.
Para a NFC-e ia 1,36 e para o banco 1,37.
As configurações era para arredondar.
Ai estudando percebi que o arredondamento interno utilizado era conforme a ABNT e neste caso 1,345 fica 1,34.
Exemplo
de 0 a 4 na segunda casa, 5 na terceira arredonda para baixo,
5 a 9 na segunda casa, 5 arredonda para cima.
Como meu procedimento estava no banco, precisei uma forma de fazer este arredondamento via SQL.
E no caso estava utilizando o Firebird.
Para minha sorte encontrei uma function para firebird 3.0 e uma stored procedure para firebird 2.5.
Então vamos ao código!
FUNCTION – PARA FIREBIRD 3.0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
| CREATE OR ALTER FUNCTION ROUNDABNT (
AVALOR DOUBLE PRECISION,
ADECIMAIS SMALLINT)
RETURNS DOUBLE PRECISION
AS
DECLARE variable cDecimais VARCHAR(100);
DECLARE variable vlrstr VARCHAR(100);
DECLARE variable nSubsequente SMALLINT;
DECLARE variable posponto SMALLINT;
BEGIN
vlrstr = CAST(AVALOR AS VARCHAR(100));
posponto = POSITION('.',vlrstr);
cDecimais = SUBSTRING(vlrstr FROM posponto+1 FOR CHAR_LENGTH(vlrstr));
nSubsequente = ADECIMAIS+1;
IF (:ADECIMAIS < 1) THEN
RETURN TRUNC(AVALOR);
ELSE
IF (CHAR_LENGTH(cDecimais) <= :ADECIMAIS) THEN
RETURN AVALOR;
ELSE
BEGIN
IF ((CAST(SUBSTRING(cDecimais FROM nSubsequente FOR 1) AS INTEGER) > 5) OR
(CAST(SUBSTRING(cDecimais FROM nSubsequente FOR 1)AS DOUBLE PRECISION) < 5)) THEN
RETURN ROUND(AVALOR,ADECIMAIS);
ELSE
IF (CAST(SUBSTRING(cDecimais FROM nSubsequente FOR 1)AS DOUBLE PRECISION) = 5) THEN
IF (MOD(CAST(SUBSTRING(cDecimais FROM ADECIMAIS FOR 1)AS DOUBLE PRECISION) ,2) <> 0) THEN
RETURN ROUND(AVALOR,ADECIMAIS);
ELSE
IF (CAST(SUBSTRING(cDecimais FROM nSubsequente+1 FOR 1)AS DOUBLE PRECISION) > 0) THEN
RETURN ROUND(AVALOR,ADECIMAIS);
ELSE
RETURN TRUNC(AVALOR,ADECIMAIS);
END
END |
create or alter function ROUNDABNT (
AVALOR double precision,
ADECIMAIS smallint)
returns double precision
AS
declare variable cDecimais varchar(100);
declare variable vlrstr varchar(100);
declare variable nSubsequente smallint;
declare variable posponto smallint;
BEGIN
vlrstr = Cast(AVALOR as varchar(100));
posponto = POSITION('.',vlrstr);
cDecimais = SUBSTRING(vlrstr from posponto+1 for CHAR_LENGTH(vlrstr));
nSubsequente = ADECIMAIS+1;
if (:ADECIMAIS < 1) Then
RETURN TRUNC(AVALOR);
else
If (CHAR_LENGTH(cDecimais) <= :ADECIMAIS) Then
RETURN AVALOR;
else
Begin
If ((Cast(SUBSTRING(cDecimais from nSubsequente for 1) as integer) > 5) Or
(Cast(SUBSTRING(cDecimais From nSubsequente For 1)as double precision) < 5)) Then
RETURN ROUND(AVALOR,ADECIMAIS);
Else
if (Cast(SUBSTRING(cDecimais From nSubsequente For 1)as double precision) = 5) Then
If (MOD(Cast(SUBSTRING(cDecimais From ADECIMAIS For 1)as double precision) ,2) <> 0) Then
RETURN ROUND(AVALOR,ADECIMAIS);
Else
If (Cast(SUBSTRING(cDecimais From nSubsequente+1 For 1)as double precision) > 0) Then
RETURN ROUND(AVALOR,ADECIMAIS);
Else
RETURN TRUNC(AVALOR,ADECIMAIS);
End
END
Exemplo de uso da function em firebird 3.0
1
2
3
4
5
6
7
8
9
10
| SELECT
roundabnt(1.645, 2) AS exemplo1,
roundabnt(1.655, 2) AS exemplo2,
roundabnt(1.605, 2) AS exemplo3,
roundabnt(1.605, 2) AS exemplo4
FROM rdb$database |
select
roundabnt(1.645, 2) as exemplo1,
roundabnt(1.655, 2) as exemplo2,
roundabnt(1.605, 2) as exemplo3,
roundabnt(1.605, 2) as exemplo4
from rdb$database
STORED PROCEDURE – PARA FIREBIRD 2.5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
| CREATE OR ALTER PROCEDURE SP_ROUNDABNT (
AVALOR DOUBLE PRECISION,
ADECIMAIS SMALLINT)
RETURNS
(
VALOR DOUBLE PRECISION
)
AS
DECLARE VARIABLE CDECIMAIS VARCHAR(100);
DECLARE VARIABLE VLRSTR VARCHAR(100);
DECLARE VARIABLE NSUBSEQUENTE SMALLINT;
DECLARE VARIABLE POSPONTO SMALLINT;
BEGIN
VLRSTR = CAST(AVALOR AS VARCHAR(100));
POSPONTO = POSITION('.',VLRSTR);
CDECIMAIS = SUBSTRING(VLRSTR FROM POSPONTO+1 FOR CHAR_LENGTH(VLRSTR));
NSUBSEQUENTE = ADECIMAIS+1;
IF (:ADECIMAIS < 1) THEN
BEGIN
VALOR = TRUNC(AVALOR);
SUSPEND;
exit;
END
ELSE
IF (CHAR_LENGTH(CDECIMAIS) <= :ADECIMAIS) THEN
BEGIN
VALOR = AVALOR;
SUSPEND;
exit;
END
ELSE
BEGIN
IF ((CAST(SUBSTRING(CDECIMAIS FROM NSUBSEQUENTE FOR 1) AS INTEGER) > 5) OR
(CAST(SUBSTRING(CDECIMAIS FROM NSUBSEQUENTE FOR 1)AS DOUBLE PRECISION) < 5)) THEN
BEGIN
VALOR = ROUND(AVALOR,ADECIMAIS);
SUSPEND;
exit;
END
ELSE
IF (CAST(SUBSTRING(CDECIMAIS FROM NSUBSEQUENTE FOR 1)AS DOUBLE PRECISION) = 5) THEN
BEGIN
IF (MOD(CAST(SUBSTRING(CDECIMAIS FROM ADECIMAIS FOR 1)AS DOUBLE PRECISION) ,2) <> 0) THEN
BEGIN
VALOR = ROUND(AVALOR,ADECIMAIS);
SUSPEND;
exit;
END
ELSE IF (CAST(SUBSTRING(CDECIMAIS FROM NSUBSEQUENTE+1 FOR 1)AS DOUBLE PRECISION) > 0) THEN
BEGIN
VALOR = ROUND(AVALOR,ADECIMAIS);
SUSPEND;
exit;
END
ELSE
BEGIN
VALOR = TRUNC(AVALOR,ADECIMAIS);
SUSPEND;
exit;
END
END
END
END |
CREATE OR ALTER PROCEDURE SP_ROUNDABNT (
AVALOR DOUBLE PRECISION,
ADECIMAIS SMALLINT)
RETURNS
(
VALOR DOUBLE PRECISION
)
AS
DECLARE VARIABLE CDECIMAIS VARCHAR(100);
DECLARE VARIABLE VLRSTR VARCHAR(100);
DECLARE VARIABLE NSUBSEQUENTE SMALLINT;
DECLARE VARIABLE POSPONTO SMALLINT;
BEGIN
VLRSTR = CAST(AVALOR AS VARCHAR(100));
POSPONTO = POSITION('.',VLRSTR);
CDECIMAIS = SUBSTRING(VLRSTR FROM POSPONTO+1 FOR CHAR_LENGTH(VLRSTR));
NSUBSEQUENTE = ADECIMAIS+1;
IF (:ADECIMAIS < 1) THEN
BEGIN
VALOR = TRUNC(AVALOR);
SUSPEND;
exit;
END
ELSE
IF (CHAR_LENGTH(CDECIMAIS) <= :ADECIMAIS) THEN
BEGIN
VALOR = AVALOR;
SUSPEND;
exit;
END
ELSE
BEGIN
IF ((CAST(SUBSTRING(CDECIMAIS FROM NSUBSEQUENTE FOR 1) AS INTEGER) > 5) OR
(CAST(SUBSTRING(CDECIMAIS FROM NSUBSEQUENTE FOR 1)AS DOUBLE PRECISION) < 5)) THEN
BEGIN
VALOR = ROUND(AVALOR,ADECIMAIS);
SUSPEND;
exit;
END
ELSE
IF (CAST(SUBSTRING(CDECIMAIS FROM NSUBSEQUENTE FOR 1)AS DOUBLE PRECISION) = 5) THEN
begin
IF (MOD(CAST(SUBSTRING(CDECIMAIS FROM ADECIMAIS FOR 1)AS DOUBLE PRECISION) ,2) <> 0) THEN
BEGIN
VALOR = ROUND(AVALOR,ADECIMAIS);
SUSPEND;
exit;
END
ELSE IF (CAST(SUBSTRING(CDECIMAIS FROM NSUBSEQUENTE+1 FOR 1)AS DOUBLE PRECISION) > 0) THEN
BEGIN
VALOR = ROUND(AVALOR,ADECIMAIS);
SUSPEND;
exit;
END
ELSE
begin
VALOR = TRUNC(AVALOR,ADECIMAIS);
SUSPEND;
exit;
END
end
END
END
Fonte Base: https://www.projetoacbr.com.br/forum/topic/9709-minha-pequena-contribui%C3%A7%C3%A3o-arredondamento-abnt/
Exemplo de uso da stored procedure em firebird 2.5
1
2
3
4
5
6
7
8
9
10
| SELECT
(SELECT a.valor FROM SP_ROUNDABNT(1.645, 2) a) AS exemplo1,
(SELECT a.valor FROM SP_ROUNDABNT(1.655, 2) a) AS exemplo2,
(SELECT a.valor FROM SP_ROUNDABNT(1.605, 2) a) AS exemplo3,
(SELECT a.valor FROM SP_ROUNDABNT(1.605, 2) a) AS exemplo4
FROM rdb$database |
select
(select a.valor from SP_ROUNDABNT(1.645, 2) a) as exemplo1,
(select a.valor from SP_ROUNDABNT(1.655, 2) a) as exemplo2,
(select a.valor from SP_ROUNDABNT(1.605, 2) a) as exemplo3,
(select a.valor from SP_ROUNDABNT(1.605, 2) a) as exemplo4
from rdb$database
Pessoal, os códigos acima foram muito úteis para mim e espero que ajude a todos.
Um abraço e até a próxima.
Valeu!
-
Giovani Da Cruz
-
4.152 views
- 0 comentários
- 27 de dezembro de 2019
Está gostando do conteúdo? Considere pagar um cafezinho para nossa equipe!
Posts Relacionados - Continue Aprendendo