O tipo de dados money armazena uma quantia
monetária com precisão fracionária fixa;
veja a Tabela 8.3.
A precisão fracionária é determinada pela configuração do parâmetro
lc_monetary no servidor de banco de dados.
O intervalo mostrado na tabela assume serem dois dígitos
fracionários.
A entrada é aceita em vários formatos, incluindo literais inteiros
e de ponto flutuante, assim como a formatação monetária típica, como
'$1.000,00'.
A saída geralmente está nessa última forma, mas depende da
localidade.
Tabela 8.3. Tipo monetário
| Nome | Tamanho de armazenamento | Descrição | Intervalo dos valores |
|---|---|---|---|
money | 8 bytes | quantia monetária | -92233720368547758.08 a +92233720368547758.07 |
Como a saída desse tipo de dados é sensível à localidade, carregar
dados do tipo de dados money em um banco de dados que
tenha uma configuração diferente de lc_monetary
pode não funcionar.
Para evitar problemas, antes de restaurar um
dump em um novo banco de dados,
certifique-se de que lc_monetary tenha o mesmo
valor, ou um valor equivalente, do banco de dados de onde foi feito
o dump.
Valores dos tipos de dados numeric, int e
bigint podem ser convertidos diretamente para
money. A conversão dos tipos de dados real
e double precision podem ser feitas convertendo para
numeric primeiro, por exemplo:
SELECT '12.34'::float8::numeric::money;
Contudo, isto não é recomendado. Os números de ponto flutuante não devem ser usados para lidar com dinheiro, devido ao erro possível de arredondamento.
O tipo de dados money pode ser convertido para
numeric sem perda de precisão.
A conversão para outros tipos de dados pode perder precisão e,
também, deve ser feita em duas etapas:
SELECT '52093.89'::money::numeric::float8;
A divisão de um valor money por um valor inteiro é
realizada com truncamento da parte fracionária em direção a zero.
Para obter um resultado arredondado, deve-se dividir por um valor
de ponto flutuante ou converter o valor money para
numeric antes de dividir e voltar para
money depois.
(Este último é preferível para evitar o risco de perda de precisão.)
Quando um valor do tipo de dados money é dividido por
outro valor do tipo de dados money, o resultado é de
precisão dupla
(ou seja, um número puro, não dinheiro); as unidades monetárias se
cancelam na divisão.
Exemplo 8.3. Exemplo do tradutor
Soma de dois valores do tipo de dados money,
executado no Debian 12 com
locale = “LC_MONETARY=pt_BR.UTF-8”.
SELECT name, setting
FROM pg_settings WHERE name='lc_monetary';
name | setting
-------------+-------------
lc_monetary | pt_BR.UTF-8
(1 linha)
CREATE OR REPLACE FUNCTION soma_monetária(op1 MONEY, op2 MONEY)
RETURNS MONEY AS $$
-- Somar dois números do tipo de dados money
-- @param op1 tipo de dados money - primeiro operando
-- @param op2 tipo de dados money - segundo operando
-- @return soma de op1 com op2
BEGIN
RETURN op1 + op2;
END;
$$ LANGUAGE plpgsql;
SELECT soma_monetária('1.234,56'::money, 1000::money);
soma_monetária
----------------
R$ 2.234,56
(1 linha)