Os tipos de dados numéricos consistem em inteiros de dois, quatro e oito bytes, números de ponto flutuante de quatro e oito bytes, e decimais de precisão selecionável. A Tabela 8.2 lista os tipos de dados disponíveis.
Tabela 8.2. Tipos de dados numéricos
| Nome | Tamanho de armazenamento | Descrição | Intervalo dos valores |
|---|---|---|---|
smallint | 2 bytes | inteiro com intervalo de valores pequeno | -32768 a +32767 |
integer | 4 bytes | escolha usual para inteiro | -2147483648 a +2147483647 |
bigint | 8 bytes | inteiro com intervalo de valores grande | -9223372036854775808 a +9223372036854775807 |
decimal | variável | precisão especificada pelo usuário, exato | até 131072 dígitos antes do ponto decimal; até 16383 dígitos após o ponto decimal |
numeric | variável | precisão especificada pelo usuário, exato | até 131072 dígitos antes do ponto decimal; até 16383 dígitos após o ponto decimal |
real | 4 bytes | precisão variável, inexato | precisão de 6 dígitos decimais |
double precision | 8 bytes | precisão variável, inexato | precisão de 15 dígitos decimais |
smallserial | 2 bytes | inteiro pequeno com autoincremento | 1 a 32767 |
serial | 4 bytes | inteiro com autoincremento | 1 a 2147483647 |
bigserial | 8 bytes | inteiro grande com autoincremento | 1 a 9223372036854775807 |
A sintaxe das constantes para os tipos de dados numéricos é descrita na Seção 4.1.2. Os tipos de dados numéricos possuem um conjunto completo de operadores e funções aritméticas correspondentes. Veja o Capítulo 9 para obter mais informações. As próximas seções descrevem os tipos de dados numéricos em detalhe.
Os tipos de dados smallint, integer e
bigint armazenam números inteiros, ou seja, números
sem a parte fracionária, com intervalos diferentes. A tentativa de
armazenar um valor fora do intervalo permitido resulta em erro.
O tipo de dados integer é a escolha usual, porque
oferece o melhor equilíbrio entre intervalo de valores, tamanho de
armazenamento e desempenho.
Geralmente o tipo de dados smallint só é usado quando
o espaço em disco está muito escasso.
O tipo de dados bigint é projetado para ser usado quando
o intervalo de valores de integer não for suficiente.
O padrão SQL só especifica os tipos de dados
inteiros integer (ou int),
smallint e bigint.
Os nomes de tipo de dados int2, int4 e
int8 são extensões, que também são usadas por outros
sistemas de banco de dados SQL.
O tipo de dados numeric pode armazenar números com um
número muito grande de dígitos.
É particularmente recomendado para armazenar valores monetários
e outras quantidades onde a exatidão é necessária.
Cálculos com valores numeric produzem resultados exatos
sempre que possível, por exemplo, adição, subtração e multiplicação.
Entretanto, os cálculos usando valores numeric são muito
lentos em comparação com os tipos de dados inteiros ou com os
tipos de dados de ponto flutuante descritos na próxima seção.
São usados os seguintes termos abaixo:
A precisão do tipo de dados numeric
é a contagem dos dígitos significativos no número todo, ou seja,
o número de dígitos presentes em ambos os lados do ponto decimal.
A escala de um numeric é a
contagem dos dígitos decimais na parte fracionária, à direita do
ponto decimal. Assim, o número 23.5141 tem uma precisão de 6 dígitos
e uma escala de 4 dígitos. Os números inteiros podem ser
considerados tendo uma escala de zero dígitos.
Podem ser especificadas tanto a precisão máxima quanto a escala
máxima de uma coluna numeric. Para declarar uma
coluna do tipo de dados numeric é usada a sintaxe:
NUMERIC(precisão,escala)
A precisão deve ser positiva, enquanto a escala pode ser positiva ou negativa (veja abaixo). Como alternativa
NUMERIC(precisão)
seleciona uma escala de 0. Especificar
NUMERIC
sem precisão ou escala cria uma coluna
“numérica irrestrita”, na qual valores numéricos de
qualquer comprimento podem ser armazenados, até os limites da
implementação. Uma coluna desse tipo de dados não forçará os valores
de entrada para nenhuma escala específica, enquanto as colunas
numeric com uma escala declarada vão forçar os valores
de entrada para esta escala. (O padrão SQL requer
uma escala padrão de 0, ou seja, coerção para precisão inteira.
Achamos isto um pouco inútil. Se estiver preocupado com a
portabilidade, sempre especifique a precisão e a escala
explicitamente.)
A precisão máxima que pode ser especificada explicitamente em uma
declaração do tipo de dados NUMERIC é 1000.
Uma coluna NUMERIC irrestrita está sujeita aos limites
descritos na Tabela 8.2.
Se a escala de um valor a ser armazenado for maior que a escala declarada da coluna, o sistema irá arredondar o valor para o número especificado de dígitos fracionários. Então, se o número de dígitos à esquerda da vírgula decimal exceder a precisão declarada menos a escala declarada, irá ocorrer um erro. Por exemplo, uma coluna declarada como
NUMERIC(3, 1)
irá arredondar os valores para 1 casa decimal e poderá armazenar valores entre -99,9 e 99,9, inclusive.
A partir do PostgreSQL 15, é permitido
declarar uma coluna do tipo de dados numeric
com escala negativa. Assim, os valores serão arredondados para
a esquerda da vírgula decimal. A precisão ainda representa
o número máximo de dígitos não arredondados.
Portanto, uma coluna declarada como
NUMERIC(2, -3)
irá arredondar os valores para o milhar mais próximo e poderá armazenar valores entre -99000 e 99000, inclusive. Também é permitido declarar uma escala maior do que a precisão declarada. Esta coluna só pode conter valores fracionários e exige que o número de dígitos zero imediatamente à direita da vírgula decimal seja pelo menos a escala declarada menos a precisão declarada. Por exemplo, uma coluna declarada como
NUMERIC(3, 5)
irá arredondar os valores para 5 casas decimais e poderá armazenar valores entre -0,00999 e 0,00999, inclusive.
O PostgreSQL permite que a escala em
uma declaração de tipo de dados numeric seja
qualquer valor no intervalo de -1000 a 1000.
Entretanto, o padrão SQL exige que a escala
esteja no intervalo de 0 a precisão.
Utilizar escalas fora deste intervalo pode não ser compatível
com outros sistemas de banco de dados.
Os valores numéricos são fisicamente armazenados sem zeros extras à
esquerda ou à direita. Assim, a precisão declarada e a escala de
uma coluna são as máximas, e não alocações fixas.
(Nesse sentido, o tipo de dados numeric é mais
semelhante a varchar(
do que a n)char(.)
O requisito real de armazenamento é de dois bytes para cada grupo
de quatro dígitos decimais, mais três a oito bytes de sobrecarga.
n)
Além dos valores numéricos comuns, o tipo de dados
numeric possui os valores especiais
Infinity -Infinity NaN
que foram adaptados do padrão
IEEE 754,
e representam “infinito”,
“menos infinito” e “não é um número”,
respectivamente.
Ao se escrever estes valores como constantes em um comando
SQL, devem ser colocados apóstrofos ao redor deles,
por exemplo, UPDATE table SET x = '-Infinity'.
Na entrada, estas cadeias de caracteres são reconhecidas sem
ser feita distinção entre letras maiúsculas e minúsculas.
Os valores infinitos podem, como alternativa, serem escritos como
inf e -inf.
Exemplo 8.1. Exemplo do tradutor
Neste exemplo é criada uma expressão de tabela contendo os valores numéricos '-Infinity', 'Infinity' e 'NaN', em seguida é feita uma consulta para mostrar a saída destes valores.
WITH n("Menos Infinito", "Mais Infinito", "Não é um número") AS
(VALUES( '-Infinity'::numeric, 'Infinity'::numeric, 'NaN'::numeric))
SELECT * FROM n;
Menos Infinito | Mais Infinito | Não é um número
----------------+---------------+-----------------
-Infinity | Infinity | NaN
(1 linha)
Os valores infinitos se comportam segundo as expectativas
da matemática.
Por exemplo, Infinity mais qualquer valor finito
é igual a Infinity, assim como
Infinity mais Infinity;
mas Infinity menos Infinity
resulta em NaN (não é um número), porque
não tem uma interpretação bem definida.
Note que infinito só pode ser armazenado em uma coluna
numeric irrestrita, porque notacionalmente excede
qualquer limite de precisão finita.
Exemplo 8.2. Exemplo do tradutor
Neste exemplo 'Infinity' é subtraído de 'Infinity' produzindo 'NaN'.
CREATE FUNCTION subtrair(op1 NUMERIC, op2 NUMERIC)
RETURNS NUMERIC AS $$
-- Calcula a subtração entre dois números do tipo de dados numeric
-- @param op1 tipo de dados numeric - minuendo
-- @param op2 tipo de dados numeric - subtraendo
-- @return diferença (op1 - op2)
BEGIN
RETURN op1 - op2;
END;
$$ LANGUAGE plpgsql;
SELECT subtrair('Infinity', 'Infinity');
subtrair
----------
NaN
(1 linha)
O valor NaN (não é um número) é usado para
representar resultados de cálculo indefinidos.
Em geral, qualquer operação com uma entrada NaN
produz outro NaN.
A única exceção é quando as outras entradas da operação são tais
que a mesma saída seria obtida se NaN fosse
substituído por qualquer valor numérico finito ou infinito; então,
este valor de saída é usado para NaN também.
(Um exemplo desse princípio é que NaN elevado à
potência zero produz um.)
Na maioria das implementações do conceito “não-é-um-número”,
NaN não é considerado igual a nenhum outro
valor numérico (incluindo o próprio NaN).
Para permitir que os valores numeric sejam
classificados e usados em índices baseados em árvore, o
PostgreSQL trata os valores
NaN como sendo iguais, e maiores do que todos
os outros valores que não são NaN.
Os tipos de dados decimal e numeric são
equivalentes. Os dois tipos de dados fazem parte do padrão
SQL.
Ao arredondar valores, o tipo de dados numeric
arredonda para zero, enquanto (na maioria das máquinas) os tipos
de dados real e double precision
arredondam para o número mais próximo. Por exemplo:
SELECT x, round(x::numeric) AS num_round, round(x::double precision) AS dbl_round, floor(x::numeric) AS num_floor, ceil(x::numeric) AS num_ceil, trunc(x::numeric) AS num_trunc FROM generate_series(-3.5, 3.5, 1) as x;
x | num_round | dbl_round | num_floor | num_ceil | num_trunc ------+-----------+-----------+-----------+----------+----------- -3.5 | -4 | -4 | -4 | -3 | -3 -2.5 | -3 | -2 | -3 | -2 | -2 -1.5 | -2 | -2 | -2 | -1 | -1 -0.5 | -1 | -0 | -1 | 0 | 0 0.5 | 1 | 0 | 0 | 1 | 0 1.5 | 2 | 2 | 1 | 2 | 1 2.5 | 3 | 2 | 2 | 3 | 2 3.5 | 4 | 4 | 3 | 4 | 3 (8 linhas)
As colunas mostrando as saídas das funções floor,
ceil e trunc
foram adicionadas ao exemplo original, para mostrar que o
arredondamento no tipo de dados numeric não
corresponde, em todos os casos, aos resultados produzidos pela
função floor, que retorna o inteiro mais
próximo menor ou igual ao argumento, nem aos resultados produzidos
pela função ceil, que retorna o inteiro mais
próximo maior ou igual ao argumento, nem, em nenhum caso, aos
resultados produzidos pela função trunc,
que trunca para inteiro (em direção a zero).
Veja a Seção 9.3.
Os tipos de dados real e double precision
são tipos de dados numéricos inexatos de precisão variável.
Em todas as plataformas aceitas no momento, estes tipos de dados são
implementações do Padrão IEEE 754 para
Aritmética de Ponto Flutuante Binária (precisão simples e dupla,
respectivamente), na medida em que o processador, sistema
operacional e compilador subjacentes aceitam isto.
Inexato significa que alguns valores não podem ser convertidos para o formato interno de forma exata, sendo armazenados como aproximações, de modo que armazenar e recuperar o valor pode apresentar pequenas discrepâncias. Gerenciar estes erros e como eles se propagam por meio de cálculos é assunto de todo um ramo da matemática e da ciência da computação e não será discutido aqui, exceto pelos seguintes pontos:
Se precisar de armazenamento e cálculos exatos (como para
valores monetários), use o tipo de dados numeric.
Se quiser fazer cálculos complicados com estes tipos de dados para algo importante, principalmente se depender de determinado comportamento em casos limite (infinity, underflow), a implementação deve ser avaliada com cuidado.
A comparação de dois valores de ponto flutuante para igualdade pode nem sempre funcionar conforme o esperado.
Em todas as plataformas aceitas no momento, o tipo de dados
real tem um intervalo de cerca de 1E-37 a 1E+37 com
uma precisão de pelo menos 6 dígitos decimais.
O tipo de dados double precision tem um intervalo de
cerca de 1E-307 a 1E+308 com uma precisão de pelo menos 15 dígitos.
Valores muito grandes ou muito pequenos causarão erro.
Pode ocorrer arredondamento se a precisão do número de entrada
for muito alta. Números muito próximos de zero, que não são
representáveis como distintos de zero, causarão um erro de
underflow.
[42]
Por padrão, os valores de ponto flutuante são exibidos em formato
de texto em sua representação decimal precisa mais curta;
o valor decimal produzido está mais próximo do valor binário
armazenado verdadeiro do que de qualquer outro valor representável
na mesma precisão binária.
(Entretanto, no momento o valor de saída nunca está
exatamente no meio do caminho entre dois
valores representáveis, a fim de evitar um bug generalizado
onde as rotinas de entrada não respeitam adequadamente a regra
de arredondar para o valor mais próximo.)
Este valor usará no máximo 17 dígitos decimais significativos para
valores float8, e no máximo 9 dígitos para valores
float4.
Este formato de saída “mais curto e preciso” é muito mais rápido de gerar do que o formato arredondado histórico.
Para manter a compatibilidade com a saída gerada por versões mais
antigas do PostgreSQL, e para permitir
que a precisão da saída seja reduzida, pode ser usado o parâmetro
extra_float_digits para selecionar a saída
decimal arredondada em vez dessa.
Definir o valor 0 restaura o padrão anterior que era arredondar
o valor para 6 (para float4) ou 15
(para float8) dígitos decimais significativos.
Definir um valor negativo reduz ainda mais o número de dígitos;
por exemplo, -2 arredonda a saída para 4 ou 13 dígitos,
respectivamente.
Qualquer valor de extra_float_digits maior que 0 seleciona o formato mais curto e preciso.
Historicamente, as aplicações que queriam valores precisos tinham que definir extra_float_digits como 3 para obtê-los. Para a máxima compatibilidade entre as versões, elas devem continuar a fazê-lo.
Além dos valores numéricos comuns, os tipos de dados de ponto flutuante têm os valores especiais
Infinity -Infinity NaN
que representam os valores especiais IEEE 754
“infinito”, “menos infinito” e
“não é um número”, respectivamente.
Ao se escrever estes valores como constantes em um comando
SQL, devem ser colocados apóstrofos ao redor deles,
por exemplo, UPDATE table SET x = '-Infinity'.
Na entrada, estas cadeias de caracteres são reconhecidas sem
ser feita distinção entre letras maiúsculas e minúsculas.
Os valores infinitos podem, como alternativa, serem escritos como
inf e -inf.
O padrão IEEE 754 especifica que NaN não deve
ser comparado como sendo igual a nenhum outro valor de ponto
flutuante (incluindo o próprio NaN).
Para permitir que os valores de ponto flutuante sejam
classificados e usados em índices baseados em árvore, o
PostgreSQL trata os valores
NaN como sendo iguais, e maiores do que todos
os outros valores que não são NaN.
O PostgreSQL também aceita as notações
do padrão SQL float e
float( para especificar
tipos de dados numéricos inexatos.
Aqui, p)p especifica
a precisão mínima aceitável em dígitos binários.
O PostgreSQL aceita de
float(1) a float(24) para selecionar o
tipo de dados real, e de
float(25) a float(53) para selecionar o
tipo de dados double precision. Valores de
p fora do intervalo permitido ocasionam erro.
float sem precisão especificada significa
double precision.
Esta seção descreve a maneira específica usada pelo PostgreSQL para criar uma coluna com incremento automático. Outra maneira é usar o recurso de coluna de identidade do padrão SQL, descrito na Seção 5.3.
Os tipos de dados smallserial, serial e
bigserial não são tipos de dados de verdade, mas apenas
uma conveniência notacional para criar identificadores únicos para as
colunas (similar à propriedade AUTO_INCREMENT
aceita por alguns outros bancos de dados).
Na implementação corrente, especificar
CREATE TABLEnome_da_tabela(nome_da_colunaSERIAL );
equivale a especificar
CREATE SEQUENCEnome_da_tabela_nome_da_coluna_seq AS integer; CREATE TABLEnome_da_tabela(nome_da_colunainteger NOT NULL DEFAULT nextval('nome_da_tabela_nome_da_coluna_seq') ); ALTER SEQUENCEnome_da_tabela_nome_da_coluna_seq OWNED BYnome_da_tabela.nome_da_coluna;
Assim, é criada uma coluna de inteiros e organizada para que seu
valor padrão seja atribuído a partir de um gerador de sequência.
A restrição NOT NULL é aplicada para garantir
que não pode ser inserido o valor nulo.
(Geralmente é bom anexar a restrição
UNIQUE ou PRIMARY KEY,
para evitar que valores duplicados sejam inseridos acidentalmente,
mas isto não é automático.)
Por último, a sequência é marcada como
“pertencente à coluna”, para ser excluída se a
coluna ou a tabela for excluída.
Como smallserial, serial e
bigserial são implementados usando sequências,
pode haver "buracos" ou lacunas na sequência de valores que
aparece na coluna, mesmo que nenhuma linha tenha sido excluída.
Um valor alocado da sequência é considerado “usado”,
mesmo que uma linha contendo este valor nunca tenha sido inserida
com êxito na coluna da tabela. Isso pode acontecer, por exemplo,
se a transação de inserção for desfeita.
Veja nextval() na
Seção 9.17 para obter detalhes.
Para inserir o próximo valor da sequência na coluna
serial, deve ser especificado que a coluna
serial vai receber o seu valor padrão.
Isso pode ser feito excluindo a coluna da lista de colunas na
instrução INSERT, ou usando a palavra-chave
DEFAULT.
Os nomes de tipo de dados serial e serial4
são equivalentes e ambos criam colunas integer.
Os nomes de tipo de dados bigserial e serial8
funcionam da mesma maneira, exceto por criarem uma coluna do tipo de dados
bigint. Deve ser usado bigserial se for
antecipado o uso de mais de 231
identificadores durante o tempo de vida da tabela.
Os nomes de tipo de dados smallserial e
serial2 também funcionam da mesma maneira,
exceto por criarem uma coluna do tipo de dados smallint.
A sequência criada para uma coluna serial é
automaticamente excluída quando a coluna proprietária da
sequência é excluída.
É possível excluir a sequência sem excluir a coluna, mas isto
força a remoção da expressão padrão da coluna.
[42] underflow: <calculadoras> estado onde a calculadora mostra um resultado zero para a parte mais significativa de um número, enquanto a parte menos significativa do número é eliminada. ISO/IEC 2382:2015(en) Information technology — Vocabulary