Los tipos numéricos consisten en enteros de dos, cuatro y ocho bytes, números de punto flotante de cuatro y ocho bytes, y decimales de precisión seleccionable. La Table 8.2 lista los tipos disponibles.
Table 8.2. Tipos numéricos
| Nombre | Tamaño de almacenamiento | Descripción | Rango |
|---|---|---|---|
smallint | 2 bytes | entero de rango pequeño | -32768 a +32767 |
integer | 4 bytes | elección típica para enteros | -2147483648 a +2147483647 |
bigint | 8 bytes | entero de rango grande | -9223372036854775808 a +9223372036854775807 |
decimal | variable | precisión especificada por el usuario, exacta | hasta 131072 dígitos antes del punto decimal; hasta 16383 dígitos después del punto decimal |
numeric | variable | precisión especificada por el usuario, exacta | hasta 131072 dígitos antes del punto decimal; hasta 16383 dígitos después del punto decimal |
real | 4 bytes | precisión variable, inexacta | precisión de 6 dígitos decimales |
double precision | 8 bytes | precisión variable, inexacta | precisión de 15 dígitos decimales |
smallserial | 2 bytes | entero autoincrementable pequeño | 1 a 32767 |
serial | 4 bytes | entero autoincrementable | 1 a 2147483647 |
bigserial | 8 bytes | entero autoincrementable grande | 1 a 9223372036854775807 |
La sintaxis de las constantes para los tipos numéricos se describe en la Section 4.1.2. Los tipos numéricos tienen un conjunto completo de operadores y funciones aritméticas correspondientes. Consulta el Chapter 9 para obtener más información. Las siguientes secciones describen los tipos en detalle.
Los tipos smallint, integer y
bigint almacenan números enteros, es decir, números sin
componentes fraccionarios, de varios rangos. Los intentos de almacenar
valores fuera del rango permitido darán como resultado un error.
El tipo integer es la elección común, ya que ofrece
el mejor equilibrio entre rango, tamaño de almacenamiento y rendimiento.
El tipo smallint generalmente solo se usa si el espacio en
disco es muy limitado. El tipo bigint está diseñado para ser
usado cuando el rango del tipo integer es insuficiente.
SQL solo especifica los tipos enteros
integer (or int),
smallint y bigint. Los
nombres de tipo int2, int4 e
int8 son extensiones, que también son utilizadas por algunos
otros sistemas de bases de datos SQL.
El tipo numeric puede almacenar números con una
gran cantidad de dígitos. Se recomienda especialmente para
almacenar cantidades monetarias y otras cantidades donde se requiere
exactitud. Los cálculos con valores numeric producen resultados
exactos cuando es posible, por ejemplo, suma, resta, multiplicación.
Sin embargo, los cálculos con valores numeric son muy lentos
en comparación con los tipos enteros, o con los tipos de punto flotante
descritos en la siguiente sección.
A continuación usamos los siguientes términos: La
precisión de un numeric
es el número total de dígitos significativos en el número completo,
es decir, el número de dígitos a ambos lados del punto decimal.
La escala de un numeric es el
número de dígitos decimales en la parte fraccionaria, a la derecha del
punto decimal. Así, el número 23.5141 tiene una precisión de 6 y una
escala de 4. Se puede considerar que los enteros tienen una escala de cero.
Tanto la precisión máxima como la escala máxima de una
columna numeric se pueden
configurar. Para declarar una columna de tipo numeric usa
la sintaxis:
NUMERIC(precisión,escala)
La precisión debe ser positiva, mientras que la escala puede ser positiva o negativa (ver más abajo). Alternativamente:
NUMERIC(precisión)
selecciona una escala de 0. Especificar:
NUMERIC
sin ninguna precisión o escala crea una columna “numeric sin
restricciones” en la que se pueden almacenar valores numéricos de cualquier longitud,
hasta los límites de la implementación. Una columna de este tipo no
forzará los valores de entrada a ninguna escala en particular, mientras que las
columnas numeric con una escala declarada forzarán los
valores de entrada a esa escala. (El estándar SQL
requiere una escala por defecto de 0, es decir, la conversión a precisión
entera. Creemos que esto es un poco inútil. Si te preocupa
la portabilidad, especifica siempre la precisión y la escala de forma
explícita).
La precisión máxima que se puede especificar explícitamente en
una declaración de tipo numeric es 1000. Una
columna numeric sin restricciones está sujeta a los límites
descritos en la Table 8.2.
Si la escala de un valor a almacenar es mayor que la escala declarada de la columna, el sistema redondeará el valor al número especificado de dígitos fraccionarios. Luego, si el número de dígitos a la izquierda del punto decimal excede la precisión declarada menos la escala declarada, se genera un error. Por ejemplo, una columna declarada como
NUMERIC(3, 1)
redondeará los valores a 1 lugar decimal y puede almacenar valores entre -99.9 and 99.9, inclusive.
A partir de PostgreSQL 15, está permitido
declarar una columna numeric con una escala negativa. Entonces
los valores se redondearán a la izquierda del punto decimal. La
precisión sigue representando el número máximo de dígitos no redondeados.
Así, una columna declarada como
NUMERIC(2, -3)
redondeará los valores al millar más cercano y puede almacenar valores entre -99000 y 99000, inclusive. También está permitido declarar una escala mayor que la precisión declarada. Tal columna solo puede contener valores fraccionarios, y requiere que el número de dígitos cero justo a la derecha del punto decimal sea al menos la escala declarada menos la precisión declarada. Por ejemplo, una columna declarada como
NUMERIC(3, 5)
redondeará los valores a 5 decimales y puede almacenar valores entre -0.00999 y 0.00999, inclusive.
PostgreSQL permite que la escala en una
declaración de tipo numeric sea cualquier valor en el rango
de -1000 a 1000. Sin embargo, el estándar SQL requiere
que la escala esté en el rango de 0 a precisión.
El uso de escalas fuera de ese rango puede no ser portable a otros sistemas
de bases de datos.
Los valores numéricos se almacenan físicamente sin ceros adicionales a la
izquierda o a la derecha. Por lo tanto, la precisión y la escala declaradas de una columna
son máximos, no asignaciones fijas. (En este sentido, el tipo numeric
se parece más a varchar(
que a n)char(). El requisito real de almacenamiento
es de dos bytes por cada grupo de cuatro dígitos decimales,
más un costo adicional de tres a ocho bytes.
n)
Además de los valores numéricos ordinarios, el tipo numeric
tiene varios valores especiales:
Infinity
-Infinity
NaN
Estos están adaptados del estándar IEEE 754 y representan
“infinito”, “infinito negativo” y
“no es un número”, respectivamente. Al escribir estos valores
como constantes en un comando SQL, debes ponerlos entre comillas,
por ejemplo, UPDATE table SET x = '-Infinity'.
En la entrada, estas cadenas se reconocen sin distinguir entre mayúsculas y minúsculas.
Los valores de infinito también se pueden escribir alternativamente como inf
e -inf.
Los valores de infinito se comportan según las expectativas matemáticas. Por
ejemplo, Infinity más cualquier valor finito es igual a
Infinity, al igual que Infinity
más Infinity; pero Infinity
menos Infinity produce NaN (not a
number), porque no tiene una interpretación bien definida. Ten en cuenta que un
infinito solo se puede almacenar en una columna numeric sin
restricciones, porque teóricamente excede cualquier límite de precisión finita.
El valor NaN (no es un número) se usa para representar
resultados de cálculo indefinidos. En general, cualquier operación con
una entrada NaN produce otro NaN.
La única excepción es cuando las otras entradas de la operación son tales que
se obtendría la misma salida si el NaN fuera
reemplazado por cualquier valor numérico finito o infinito; entonces, ese valor de
salida se usa también para NaN. (Un ejemplo de este
principio es que NaN elevado a la potencia cero
produce uno).
En la mayoría de las implementaciones del concepto “no es un número”,
NaN no se considera igual a ningún otro valor numérico
(incluido NaN). Para permitir que los valores
numeric se ordenen y utilicen en índices basados en árboles,
PostgreSQL trata los valores NaN
como iguales y mayores que todos los valores no-NaN.
Los tipos decimal and numeric son
equivalentes. Ambos tipos forman parte del estándar SQL.
Al redondear valores, el tipo numeric redondea los empates alejándolos
del cero, mientras que (en la mayoría de las máquinas) los tipos real
y double precision redondean los empates al número par más cercano.
Por ejemplo:
SELECT x, round(x::numeric) AS num_round, round(x::double precision) AS dbl_round FROM generate_series(-3.5, 3.5, 1) as x; x | num_round | dbl_round ------+-----------+----------- -3.5 | -4 | -4 -2.5 | -3 | -2 -1.5 | -2 | -2 -0.5 | -1 | -0 0.5 | 1 | 0 1.5 | 2 | 2 2.5 | 3 | 2 3.5 | 4 | 4 (8 rows)
Los tipos de datos real y double precision son
tipos numéricos inexactos de precisión variable. En todas las plataformas
actualmente soportadas, estos tipos son implementaciones del estándar
IEEE 754 para aritmética de punto flotante binario (precisión
simple y doble, respectivamente), en la medida en que el procesador, el sistema
operativo y el compilador subyacentes lo soporten.
Inexacto significa que algunos valores no se pueden convertir exactamente al formato interno y se almacenan como aproximaciones, por lo que almacenar y recuperar un valor puede mostrar ligeras discrepancias. El manejo de estos errores y cómo se propagan a través de los cálculos es el tema de una rama entera de las matemáticas y la informática y no se discutirá aquí, excepto por los siguientes puntos:
Si requieres almacenamiento y cálculos exactos (como para
cantidades monetarias), usa el tipo numeric en su lugar.
Si deseas realizar cálculos complicados con estos tipos para cualquier cosa importante, especialmente si dependes de cierto comportamiento en casos límite (infinito, desbordamiento negativo o underflow), debes evaluar la implementación cuidadosamente.
Comparar dos valores de punto flotante para verificar la igualdad podría no funcionar siempre como se espera.
En todas las plataformas soportadas actualmente, el tipo real tiene un
rango de alrededor de 1E-37 a 1E+37 con una precisión de al menos 6 dígitos
decimales. El tipo double precision tiene un rango de alrededor de
1E-307 a 1E+308 con una precisión de al menos 15 dígitos. Los valores que son
demasiado grandes o demasiado pequeños causarán un error. El redondeo puede ocurrir si
la precisión de un número de entrada es demasiado alta. Los números demasiado cercanos a cero
que no son representables como distintos de cero causarán un error de desbordamiento negativo (underflow).
Por defecto, los valores de punto flotante se muestran en formato de texto en su
representación decimal precisa más corta; el valor decimal producido está
más cerca del valor binario almacenado real que de cualquier otro valor
representable en la misma precisión binaria. (Sin embargo, el valor de salida
actualmente nunca está exactamente a mitad de camino entre dos
valores representables, para evitar un error generalizado donde las rutinas de entrada
no respetan adecuadamente la regla de redondeo al par más cercano). Este valor
usará como máximo 17 dígitos decimales significativos para valores de
float8, y como máximo 9 dígitos para valores de float4.
Este formato de salida preciso más corto es mucho más rápido de generar que el format redondeado histórico.
Para compatibilidad con la salida generada por versiones anteriores
de PostgreSQL, y para permitir que se reduzca la
precisión de salida, se puede usar el parámetro extra_float_digits
para seleccionar en su lugar la salida decimal redondeada. Establecer un
valor de 0 restaura el valor predeterminado anterior de redondear el valor a 6
(para float4) o 15 (para float8)
dígitos decimales significativos. Establecer un valor negativo reduce aún más el número
de dígitos; por ejemplo, -2 redondearía la salida a 4 o 13 dígitos
respectivamente.
Cualquier valor de extra_float_digits mayor que 0 selecciona el formato preciso más corto.
Las aplicaciones que querían valores precisos históricamente han tenido que establecer extra_float_digits en 3 para obtenerlos. Para una máxima compatibilidad entre versiones, deberían seguir haciéndolo.
Además de los valores numéricos ordinarios, los tipos de punto flotante tienen varios valores especiales:
Infinity
-Infinity
NaN
Estos representan los valores especiales de IEEE 754
“infinito”, “infinito negativo” y
“no es un número”, respectivamente. Al escribir estos valores
como constantes en un comando SQL, debes ponerlos entre comillas,
por ejemplo, UPDATE table SET x = '-Infinity'. En la entrada,
estas cadenas se reconocen sin distinguir entre mayúsculas y minúsculas.
Los valores de infinito también se pueden escribir alternativamente como inf
e -inf.
IEEE 754 especifica que NaN no debería compararse como igual
a ningún otro valor de punto flotante (incluido NaN).
Para permitir que los valores de punto flotante se ordenen y utilicen
en índices basados en árboles, PostgreSQL trata
los valores NaN como iguales y mayores que todos los
valores no-NaN.
PostgreSQL también admite las notaciones del estándar SQL
float y
float( para especificar
tipos numéricos inexactos. Aquí, p)p especifica
la precisión mínima aceptable en dígitos binarios.
PostgreSQL acepta
de float(1) a float(24) como la selección del
tipo real, mientras que
de float(25) a float(53) selecciona
double precision. Los valores de p
fuera del rango permitido generan un error.
float sin precisión especificada se interpreta como
double precision.
Esta sección describe una forma específica de PostgreSQL para crear una columna autoincrementable. Otra forma es usar la característica de columna de identidad del estándar SQL, descrita en la Section 5.3.
Los tipos de datos smallserial, serial y
bigserial no son tipos verdaderos, sino simplemente
una conveniencia de notación para crear columnas de identificadores únicos
(similar a la propiedad AUTO_INCREMENT
soportada por algunas otras bases de datos). En la implementación
actual, especificar:
CREATE TABLEnombre_tabla(nombre_columnaSERIAL );
es equivalente a especificar:
CREATE SEQUENCEnombre_tabla_nombre_columna_seq AS integer; CREATE TABLEnombre_tabla(nombre_columnainteger NOT NULL DEFAULT nextval('nombre_tabla_nombre_columna_seq') ); ALTER SEQUENCEnombre_tabla_nombre_columna_seq OWNED BYnombre_tabla.nombre_columna;
Por lo tanto, hemos creado una columna de enteros y configurado sus valores predeterminados
para que se asignen desde un generador de secuencias. Se aplica una restricción
NOT NULL para garantizar que no se pueda insertar un valor nulo.
(En la mayoría de los casos, también querrás adjuntar una restricción
UNIQUE o PRIMARY KEY para evitar que se
inserten valores duplicados por accidente, pero esto no es automático).
Por último, la secuencia se marca como “propiedad de” (owned by)
la columna, de modo que se eliminará si se elimina la columna o la tabla.
Debido a que smallserial, serial y
bigserial se implementan utilizando secuencias, puede haber
"huecos" o brechas en la secuencia de valores que aparece en la
columna, incluso si nunca se eliminan filas. Un valor asignado
de la secuencia se sigue "consumiendo" incluso si una fila que contiene ese
valor nunca se inserta con éxito en la columna de la tabla. Esto puede suceder,
por ejemplo, si la transacción de inserción se revierte (rollback).
Consulta nextval() en la Section 9.17
para obtener más detalles.
Para insertar el siguiente valor de la secuencia en la columna serial,
especifica que a la columna serial se le debe asignar su valor
predeterminado. Esto se puede hacer excluyendo la columna de la lista de columnas
en la sentencia INSERT, o mediante el uso de la palabra clave
DEFAULT.
Los nombres de tipo serial y serial4 son
equivalentes: ambos crean columnas integer. Los nombres de tipo
bigserial y serial8 funcionan de la misma manera,
excepto que crean una columna bigint. Se debería usar
bigserial si prevés el uso de más de 231
identificadores a lo largo de la vida útil de la tabla. Los nombres de tipo
smallserial y serial2 también funcionan de la misma manera,
excepto que crean una columna smallint.
La secuencia creada para una columna serial se elimina
automáticamente cuando se elimina la columna propietaria. Puedes eliminar la secuencia
sin eliminar la columna, pero esto forzará la eliminación de la expresión predeterminada
de la columna.