8.1. Tipos numéricos #

8.1.1. Tipos enteros
8.1.2. Números de precisión arbitraria
8.1.3. Tipos de punto flotante
8.1.4. Tipos serial

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

NombreTamaño de almacenamientoDescripciónRango
smallint2 bytesentero de rango pequeño-32768 a +32767
integer4 byteselección típica para enteros-2147483648 a +2147483647
bigint8 bytesentero de rango grande-9223372036854775808 a +9223372036854775807
decimalvariableprecisión especificada por el usuario, exactahasta 131072 dígitos antes del punto decimal; hasta 16383 dígitos después del punto decimal
numericvariableprecisión especificada por el usuario, exactahasta 131072 dígitos antes del punto decimal; hasta 16383 dígitos después del punto decimal
real4 bytesprecisión variable, inexactaprecisión de 6 dígitos decimales
double precision8 bytesprecisión variable, inexactaprecisión de 15 dígitos decimales
smallserial2 bytesentero autoincrementable pequeño1 a 32767
serial4 bytesentero autoincrementable1 a 2147483647
bigserial8 bytesentero autoincrementable grande1 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.

8.1.1. Tipos enteros #

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.

8.1.2. Números de precisión arbitraria #

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).

Note

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.

Note

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(n) que a char(n)). 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.

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).

Note

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)

8.1.3. Tipos de punto flotante #

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.

Note

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.

Note

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.

Note

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(p) para especificar tipos numéricos inexactos. Aquí, 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.

8.1.4. Tipos serial #

Note

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 TABLE nombre_tabla (
    nombre_columna SERIAL
);

es equivalente a especificar:

CREATE SEQUENCE nombre_tabla_nombre_columna_seq AS integer;
CREATE TABLE nombre_tabla (
    nombre_columna integer NOT NULL DEFAULT nextval('nombre_tabla_nombre_columna_seq')
);
ALTER SEQUENCE nombre_tabla_nombre_columna_seq OWNED BY nombre_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.

Note

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.