PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Dados de dinheiro no PostgreSQL usando Java

NUMERIC /DECIMAL


Como disse Joachim Isaksson , você deseja usar NUMERIC /DECIMAL type, como um tipo de precisão arbitrária.

Dois pontos importantes sobre NUMERIC /DECIMAL :
  • Leia o doc cuidadosamente para saber que você deve especificar a escala para evitar a escala padrão de 0, significando valores inteiros onde a fração decimal é cortada. Embora este seja um dos lugares onde o Postgres se afasta do SQL padrão (oferecendo a você qualquer escala até o limite de implementação). Portanto, não especificar a escala é uma má escolha.
  • Os tipos SQL NUMERIC &DECIMAL são próximos, mas não idênticos de acordo com o padrão SQL. Em SQL:92 , sua precisão especificada para NUMERIC é respeitado, enquanto para DECIMAL o servidor de banco de dados tem permissão para adicionar precisão adicional além do que você especificou. Aqui, novamente, o Postgres se afasta um pouco do padrão, com NUMERIC &DECIMAL documentado como equivalente.

Termos:
  • Precisão é o número total de dígitos em um número.
  • Escala é o número de dígitos à direita do ponto decimal (a fração decimal).
  • ( Precisão - Escala ) =Número de dígitos à esquerda do ponto decimal (parte inteira).

Seja claro nas especificações do seu projeto para precisão e escala:
  • Grande
    A precisão deve ser grande o suficiente para lidar com números maiores que possam ser necessários no futuro. Significado… Talvez seu aplicativo hoje funcione em valores de milhares de dólares, mas no futuro deve realizar relatórios de totalização que chegam a milhões.
  • Pequeno
    Para alguns propósitos contábeis, pode ser necessário armazenar uma fração do menor valor em moeda. Significado… Mais de 3 ou 4 casas decimais em vez das 2 necessárias para um centavo em USD .

Evite MONEY tipo


O Postgres oferece um MONEY tipo também. Isso pode parecer certo, mas provavelmente não é o melhor para a maioria dos propósitos. Uma desvantagem é que com MONEY a escala é definida por uma configuração de todo o banco de dados com base em localidade . Portanto, essa configuração pode variar perigosamente facilmente quando você troca de servidor ou faz outras alterações. Além disso, você não pode controlar essa configuração para colunas específicas, enquanto pode definir a escala em cada coluna de NUMERIC modelo. Por último, MONEY não é SQL padrão, conforme mostrado nesta lista de dados SQL padrão tipos . Postgres inclui MONEY para a conveniência das pessoas portarem dados de outros sistemas de banco de dados.

Mova o ponto decimal


Outra alternativa empregada por alguns é mover o ponto decimal, e apenas armazenar no tipo de dado inteiro grande.

Por exemplo, se estiver armazenando USD dólares por centavo, multiplique qualquer número fracionário por 100, converta para um tipo inteiro e prossiga. Por exemplo, $ 123,45 se torna o inteiro 12.345.

O benefício dessa abordagem são os tempos de execução mais rápidos. Operações como sum são muito rápidos quando executados em números inteiros. Outro benefício para números inteiros é menos uso de memória.

Acho essa abordagem irritante, confusa e arriscada. Irritante porque os computadores devem estar funcionando para nós, não contra nós. Arriscado porque algum programador ou usuário pode deixar de multiplicar/dividir para converter novamente em número fracionário, dando resultados incorretos. Se estiver trabalhando em um sistema sem um bom suporte para números fracionários precisos, essa abordagem pode ser uma solução alternativa aceitável.

Não vejo nenhuma vantagem em mover o ponto decimal quando temos DECIMAL /NUMERIC em SQL e BigDecimal em Java.

Arredondamento e NaN


Na programação do seu aplicativo, bem como em quaisquer cálculos feitos no lado do servidor Postgres, tenha muito cuidado e fique atento aos arredondamentos e truncamentos na fração decimal. E teste para NaNs inadvertidas aparecendo.

Em ambos os lados, aplicativo e Postgres, sempre evite ponto flutuante tipos de dados para o trabalho de dinheiro. O ponto flutuante foi projetado para velocidade de desempenho , mas ao custo de precisão . Os cálculos podem resultar em dígitos extras aparentemente loucos na fração decimal. Não é bom para fins financeiros/dinheiro ou outros onde a precisão é importante.

BigDecimal


Sim, em Java, você deseja BigDecimal como seu tipo de precisão arbitrária. BigDecimal é mais lento e usa mais memória, mas armazena com precisão seus valores em dinheiro. SQL NUMERIC /DECIMAL deve mapear para BigDecimal conforme discutido aqui e em StackOverflow .

BigDecimal é uma das melhores coisas sobre Java. Não conheço nenhuma outra plataforma com uma classe semelhante, especialmente uma tão bem implementada e aprimorada com grandes melhorias e correções feitas ao longo dos anos.

Usando BigDecimal é definitivamente mais lento do que usar tipos de ponto flutuante do Java , float &double . Mas em aplicativos do mundo real, duvido que seus cálculos de dinheiro sejam um gargalo. Além disso, o que você ou seus clientes querem:o mais rápido cálculos de dinheiro, ou precisos cálculos de dinheiro? 😉

Sempre pensei em BigDecimal como o maior recurso de dormente em Java, a vantagem mais importante de usar a plataforma Java sobre tantas outras plataformas sem suporte tão sofisticado para números fracionários.

Pergunta semelhante:Melhor tipo de dados para moeda