Estou usando uma coluna decimal para armazenar valores monetários em um banco de dados e hoje estava pensando em qual precisão e escala usar.
Como colunas supostamente char de largura fixa são mais eficientes, eu estava pensando que o mesmo poderia ser verdade para colunas decimais. É isso?
E que precisão e escala devo usar? Eu estava pensando em precisão 24/8. Isso é um exagero, não é suficiente ou ok?
Isto é o que eu decidi fazer:
- Armazene as taxas de conversão (quando aplicável) na própria tabela de transações, como um flutuador
- Armazene a moeda na tabela da conta
- O valor da transação será um
DECIMAL(19,4)
- Todos os cálculos usando uma taxa de conversão serão tratados pelo meu aplicativo, então eu mantenho o controle dos problemas de arredondamento
Eu não acho que um problema para a taxa de conversão seja um problema, pois é principalmente para referência, e eu o converteremos em decimal de qualquer maneira.
Obrigado a todos por sua contribuição valiosa.
DECIMAL(19, 4)
é uma escolha popular. verifique isso também verifique aqui Formatos de Moeda Mundial para decidir quantas casas decimais usar, a esperança ajuda.Respostas:
Se você estiver procurando por um tamanho único, sugiro que
DECIMAL(19, 4)
seja uma escolha popular (um rápido Google confirma isso). Eu acho que isso se origina do antigo tipo de dados VBA / Access / Jet Currency, sendo o primeiro tipo de ponto fixo decimal no idioma;Decimal
só veio no estilo 'versão 1.0' (ou seja, não foi totalmente implementado) no VB6 / VBA6 / Jet 4.0.A regra prática para armazenar valores decimais de ponto fixo é armazenar pelo menos mais uma casa decimal do que você realmente precisa para permitir o arredondamento. Uma das razões para mapear o
Currency
tipo antigo no front-end paraDECIMAL(19, 4)
digitar no back-end foi queCurrency
exibia o arredondamento dos banqueiros por natureza, enquanto oDECIMAL(p, s)
arredondamento por truncamento.Uma casa decimal extra no armazenamento
DECIMAL
permite que um algoritmo de arredondamento personalizado seja implementado em vez de assumir o padrão do fornecedor (e o arredondamento dos banqueiros é alarmante, para dizer o mínimo, para um designer que espera que todos os valores que terminem em 0,5 para arredondar para zero) .Sim,
DECIMAL(24, 8)
parece um exagero para mim. A maioria das moedas é cotada com quatro ou cinco casas decimais. Conheço situações em que é necessária uma escala decimal de 8 (ou mais), mas é aqui que uma quantia monetária 'normal' (digamos quatro casas decimais) foi proporcional, implicando que a precisão decimal deve ser reduzida adequadamente (considere também um tipo de ponto flutuante nessas circunstâncias). Hoje em dia, ninguém tem tanto dinheiro para exigir uma precisão decimal de 24 :)No entanto, em vez de uma abordagem de tamanho único, algumas pesquisas podem estar em ordem. Pergunte ao seu designer ou especialista em domínio sobre regras contábeis que podem ser aplicáveis: GAAP, UE etc. Lembro-me vagamente de algumas transferências intra-estaduais da UE com regras explícitas para arredondar para cinco casas decimais, portanto,
DECIMAL(p, 6)
para armazenamento. Os contadores geralmente parecem favorecer quatro casas decimais.PS Evite o
MONEY
tipo de dados do SQL Server, pois apresenta sérios problemas de precisão ao arredondar, entre outras considerações, como portabilidade, etc. Consulte o blog de Aaron Bertrand .A Microsoft e os designers de idiomas escolheram o arredondamento de banqueiros porque os designers de hardware o escolheram [citação?]. Está consagrado nos padrões do Institute of Electrical and Electronics Engineers (IEEE), por exemplo. E os designers de hardware escolheram porque os matemáticos preferem. Veja Wikipedia ; Parafraseando: A edição de 1906 da Probabilidade e Teoria dos Erros chamou isso de 'regra do computador' ("computadores" significa seres humanos que realizam cálculos).
fonte
DECIMAL(19, 4)
mais popular do queDECIMAL(19, 2)
? A maioria das moedas mundiais tem apenas duas casas decimais.Recentemente, implementamos um sistema que precisa lidar com valores em várias moedas e converter entre elas, e descobrimos algumas coisas da maneira mais difícil.
NUNCA USE NÚMEROS DE PONTO FLUTUANTE PARA DINHEIRO
A aritmética de ponto flutuante apresenta imprecisões que podem não ser notadas até que você estrague algo. Todos os valores devem ser armazenados como números inteiros ou decimais fixos, e se você optar por usar um tipo decimal fixo, certifique-se de entender exatamente o que esse tipo faz sob o capô (por exemplo, ele usa internamente um número inteiro ou ponto flutuante tipo).
Quando você precisa fazer cálculos ou conversões:
Ao converter um número de ponto flutuante em um número inteiro na etapa 3, não basta convertê-lo - use uma função matemática para arredondá-lo primeiro. Isso geralmente será
round
, embora em casos especiais possa serfloor
ouceil
. Conheça a diferença e escolha com cuidado.Armazene o tipo de um número ao lado do valor
Isso pode não ser tão importante para você se você estiver lidando apenas com uma moeda, mas foi importante para nós lidar com várias moedas. Usamos o código de três caracteres para uma moeda, como USD, GBP, JPY, EUR etc.
Dependendo da situação, também pode ser útil armazenar:
Conheça os limites de precisão dos números com os quais você está lidando
Para valores reais, você quer ser tão preciso quanto a menor unidade da moeda. Isso significa que você não possui valores menores que um centavo, um centavo, um iene, um fen, etc. Não armazene valores com maior precisão do que isso sem motivo.
Internamente, você pode optar por lidar com valores menores; nesse caso, é um tipo diferente de valor da moeda . Verifique se o seu código sabe qual é qual e não os mistura. Evite usar valores de ponto flutuante mesmo aqui.
Adicionando todas essas regras, decidimos pelas seguintes regras. No código em execução, as moedas são armazenadas usando um número inteiro para a menor unidade.
No banco de dados, os valores são armazenados como uma sequência no seguinte formato:
Isso armazena o valor de US $ 25,00. Conseguimos fazer isso apenas porque o código que lida com moedas não precisa estar dentro da camada do banco de dados, para que todos os valores possam ser convertidos em memória primeiro. Outras situações, sem dúvida, se prestam a outras soluções.
E caso não tenha deixado claro antes, não use float!
fonte
bigint
se você pretender classificar pela quantidade. E não perca seu tempo com PHP 32bit ao lidar com grandes números inteiros, atualizar para 64 bits ou Node.js;)Ao manipular dinheiro no MySQL, use DECIMAL (13,2) se você souber a precisão de seus valores monetários ou use DOUBLE se você quiser apenas um valor aproximado suficientemente bom e rápido. Portanto, se seu aplicativo precisar lidar com valores monetários de até um trilhão de dólares (ou euros ou libras), isso deve funcionar:
Ou, se você precisar cumprir o GAAP , use:
fonte
Quatro casas decimais dariam a você a precisão de armazenar as menores subunidades monetárias do mundo. Você pode reduzi-lo ainda mais se precisar da precisão do micropagamento (nanopagamento ?!).
Eu também prefiro
DECIMAL
tipos de dinheiro específicos ao DBMS, você é mais seguro mantendo esse tipo de lógica no aplicativo IMO. Outra abordagem na mesma linha é simplesmente usar um número inteiro [long], com a formatação em ¤unit.subunit para facilitar a leitura humana (¤ = símbolo de moeda) feita no nível do aplicativo.fonte
O tipo de dados monetário no SQL Server possui quatro dígitos após o decimal.
Nos Manuais Online do SQL Server 2000:
Os dados monetários representam quantias positivas ou negativas de dinheiro. No Microsoft® SQL Server ™ 2000, os dados monetários são armazenados usando os tipos de dados money e smallmoney. Os dados monetários podem ser armazenados com precisão de quatro casas decimais. Use o tipo de dados monetários para armazenar valores no intervalo de -922.337.203.685.477,5808 a +922.337.203.685.477.5807 (requer 8 bytes para armazenar um valor). Use o tipo de dados smallmoney para armazenar valores no intervalo de -214.748.3648 a 214.748.3647 (requer 4 bytes para armazenar um valor). Se for necessário um número maior de casas decimais, use o tipo de dados decimal.
fonte
Às vezes, você precisará ir a menos de um centavo e há moedas internacionais que usam demoniações muito grandes. Por exemplo, você pode cobrar de seus clientes 0,088 centavos por transação. No meu banco de dados Oracle, as colunas são definidas como NUMBER (20,4)
fonte
Se você estiver realizando algum tipo de operação aritmética no banco de dados (multiplicando as taxas de cobrança e assim por diante), provavelmente precisará de muito mais precisão do que as pessoas sugerem, pelos mesmos motivos que nunca deseja usar algo menor que um valor de ponto flutuante de precisão dupla no código do aplicativo.
fonte
BigDecimal
), mas por um longo tempo foi de precisão dupla (pense emdouble
vez defloat
). Além disso, a precisão arbitrária possui penalidades significativas de desempenho em alguns casos. Testar é definitivamente a abordagem correta.Se você estivesse usando o IBM Informix Dynamic Server, teria um tipo MONEY que é uma variante secundária no tipo DECIMAL ou NUMERIC. É sempre um tipo de ponto fixo (enquanto DECIMAL pode ser um tipo de ponto flutuante). Você pode especificar uma escala de 1 a 32 e uma precisão de 0 a 32 (o padrão é uma escala de 16 e uma precisão de 2). Portanto, dependendo do que você precisa armazenar, você pode usar DECIMAL (16,2) - ainda grande o suficiente para manter o déficit federal dos EUA, até o centavo mais próximo - ou usar um intervalo menor ou mais casas decimais.
fonte
Eu acho que, em grande parte, os requisitos de seus clientes devem determinar qual precisão e escala usar. Por exemplo, no site de comércio eletrônico em que estou trabalhando que lida apenas com dinheiro em libras esterlinas, fui obrigado a mantê-lo em decimal (6, 2).
fonte
Uma resposta tardia aqui, mas eu usei
que eu estou certo em pensar deve permitir até 99.999.999.999,99.
fonte