En Firebird tenemos dos tipos de datos numéricos que tienen una cantidad fija de lugares decimales: NUMERIC y DECIMAL. También tenemos dos tipos de datos numéricos cuya cantidad de lugares decimales es variable (en Matemática se les dice «flotantes») que son: FLOAT y DOUBLE PRECISION.
En este artículo nos referiremos a NUMERIC y a DECIMAL, los cuales siempre tienen una cantidad fija de lugares decimales.
A la cantidad total de dígitos se la llama precisión y se la representa con la letra «p«. A la cantidad de lugares decimales se le llama escala (scale, en inglés) y se la representa con la letra «s«.
Por lo tanto, si una columna está definida como NUMERIC(5, 2) se la representa así: ppp.ss
La precisión debe estar entre 1 y 18. La escala debe estar entre 0 y 18. La escala siempre debe ser menor o igual que la precisión, nunca puede ser mayor.
Si quieres, puedes declarar una columna NUMERIC o DECIMAL sin especificar la precisión y en ese caso será convertida a INTEGER.
Lo importante a recordar es que en NUMERIC y en DECIMAL la parte decimal es siempre exacta. Se necesita que la parte decimal sea exacta cuando se trata de dinero o de cualquier otro número que resulta de contar o de realizar operaciones aritméticas sobre unidades.
Como el resultado de multiplicar o dividir números que tienen una parte decimal fija es predecible, es el motivo por el cual se los utiliza cuando se trata de dinero. A tu usuario no le puedes decir: «el cliente Juan Pueblo está debiendo más o menos 100 dólares», el usuario quiere conocer la cantidad exacta de la deuda de Juan Pueblo, eso de «más o menos 100 dólares» no le va a gustar.
Como tanto NUMERIC como DECIMAL usan una escala se los suele llamar «escalados«. Otros sinónimos son: «números de punto fijo» o «números de coma fija«.
En el estandar SQL-92 tanto NUMERIC como DECIMAL restringen al número almacenado a estar dentro de la escala elegida. La diferencia entre ambos tipos de datos es en la forma en la cual la precisión es restringida. Cuando el tipo de dato es NUMERIC, la precisión es exactamente la declarada. En cambio, cuando el tipo de datos es DECIMAL la precisión es al menos igual a la declarada. Eso significa que NUMERIC es más estricto que DECIMAL.
Sin embargo, en Firebird NUMERIC y DECIMAL son idénticos excepto cuando la precisión es menor que 5. Ambos cumplen con el estandar SQL-92 para el tipo de datos DECIMAL y eso significa que NUMERIC no cumple con el estandar de SQL-92.
Si además de usar Firebird usas o has usado o piensas usar otro motor SQL entonces para el dinero utiliza NUMERIC porque es el recomendado según el estandar SQL-92. Si solamente usas y piensas usar Firebird, entonces puedes usar cualquiera de los dos.
Internamente, Firebird almacena a estos tipos de datos como SMALLINT, como INTEGER, o como BIGINT, dependiendo de la precisión declarada.
La forma de almacenarlos internamente es la siguiente:
- Se almacena un número entero, o sea que no tiene decimales
- Se almacena la escala a un factor menor que cero que representa a un exponente de 10
Cuando el número debe ser utilizado en una consulta o en una operación matemática se lo obtiene multiplicando el número entero almacenado por 10 elevado a la escala almacenada.
Ejemplo:
Un número ha sido declarado como NUMERIC(4, 3) y por lo tanto Firebird lo almacena como un SMALLINT.
Quieres guardar en esa columna el número 7,2348 pero como la escala de la columna es 3 y la escala del número que quieres guardar es 4 el Firebird lo redondea a 7,235
Por lo tanto, el Firebird guarda el número 7235 y el número -3
Cuando quieres utilizar ese número el Firebird multiplica 7235 por 10 elevado a la -3 y por lo tanto obtienes 7,235 ya que multiplicar un número por 10 elevado a la -3 es lo mismo que dividirlo por 1000. Y 7235 dividido por 1000 es igual a 7,235
Rango de valores
Tipo de datos Precisión Almacenado como
NUMERIC 1 a 4 SMALLINT DECIMAL 1 a 4 INTEGER NUMERIC y DECIMAL 5 a 9 INTEGER NUMERIC y DECIMAL 10 a 18 BIGINT
El tipo de datos NUMERIC
El formato del tipo de datos NUMERIC es:
NUMERIC(p, s)
Por ejemplo, NUMERIC(4, 2) define a un número que puede tener como máximo 4 dígitos, de los cuales 2 de ellos sí o sí corresponderán a la parte decimal.
Eso significa que el número 1,23 será almacenado como 1,23 pero el número 1,234 será almacenado como 1,23 porque la escala es 2 y por lo tanto no puede almacenarse con más de 2 dígitos decimales. También 1,2345678 será almacenado como 1,23. El número 567,89 no podrá ser almacenado porque la parte entera tiene 3 dígitos y solamente debería tener 2 dígitos, si intentamos almacenarlo el Firebird nos mostrará un error de overflow (número mayor que el máximo permitido para esa columna).
Sin embargo, como NUMERIC se guarda internamente como un SMALLINT y en SMALLINT se puede guardar desde el número -32.768 hasta el número 32.767 al declarar a una columna como NUMERIC(4, 2) el mayor número que podemos almacenar en ella no es 99,99 como podría suponerse viendo la declaración sino 327,67. Cuidado con esto porque NUMERIC no cumple el estándar SQL-92 ya que según ese estándar el mayor número tendría que ser 99,99.
El tipo de datos DECIMAL
El formato del tipo de datos DECIMAL es:
DECIMAL(p, s)
Similarmente a NUMERIC el mayor número que puede guardarse en una columna de este tipo no es el declarado. Por ejemplo si una columna se declara como DECIMAL(4, 1) uno podría pensar que el máximo número permitido sería 999,9 pero sin embargo el mayor número permitido es 214.748.364,7 y el menor número permitido es -214.748.364,8
¿Por qué eso? porque el tipo de datos DECIMAL se guarda internamente como un INTEGER y el rango de valores de INTEGER es de -2.147.483.648 hasta 2.147.483.647 y como en este ejemplo la escala es 1 entonces para hallar el rango de valores se divide por 10. Si la escala fuera 2 se dividiría por 100, si fuera 3 se dividiría por 1.000 y así sucesivamente.
Advertencia
El hecho de que puedas almacenar en una columna números mayores a los declarados para esa columna no significa que debas hacerlo. En futuras versiones de Firebird este comportamiento puede cambiar para adecuarse al estándar y si estás dependiendo de algo que está fuera del estándar podrás encontrarte con graves problemas más adelante.
Comportamiento de NUMERIC y DECIMAL en operaciones aritméticas
División
La precisión del resultado siempre es 18. La escala del resultado es la suma de las escalas del dividendo y del divisor. Esto implica que la escala del cociente siempre será mayor que las del dividendo y del divisor. Debes tener cuidado con esto si los números que empleas tienen muchos decimales o podrías sobrepasar la escala máxima que es 18 o necesitar una precisión mayor que 18 y en ambos casos eso te ocasionaría un error de overflow.
SELECT 1234567.89 / 54321.2345 FROM RDB$DATABASE
El resultado de esa división es 22,727169 que como puedes ver tiene 6 dígitos decimales. ¿Por qué? porque el dividendo tiene 2 dígitos decimales y el divisor tiene 4 dígitos decimales y si sumas 2 + 4 obtienes 6.
SELECT 1 / 3 FROM RDB$DATABASE
Aquí, uno esperaría que el resultado fuera 0,33333333 sin embargo el resultado es 0 (cero). ¿Por qué? porque tanto el dividendo como el divisor son números enteros y la escala de los números enteros es cero. Y como la escala del cociente es la suma de la escala del dividendo más la escala del divisor esa escala también debe ser cero (0 + 0 = 0).
Si queremos efectuar la división de arriba pero que el resultado tenga dos decimales entonces deberíamos escribir:
SELECT 1.00 / 3 FROM RDB$DATABASE
o también podríamos escribir:
SELECT (1 + 0.00) / 3 FROM RDB$DATABASE
Multiplicación
Al igual que en la división, la escala del resultado es la suma de las escalas de los operandos.
Suma y Resta
La escala del resultado es la mayor de las dos escalas.
SELECT 123.45 + 678.9 FROM RDB$DATABASE
El resultado de esta suma es 802,35 y como puedes ver la escala es 2. ¿Por qué la escala es 2? porque las escalas de los sumandos son 2 y 1. Como 2 es mayor que 1 entonces la escala del resultado es 2.
La precisión siempre es 18.
Artículos relacionados
Confusiones comunes al declarar una columna como NUMERIC o DECIMAL
Determinando la precisión y la escala de una columna NUMERIC
Eligiendo el tipo de datos numérico que se usará en una columna
El índice del blog Firebird21 | Firebird SQL
Jun 17, 2013 @ 04:44:08
Gustavo Yepes
Sep 19, 2015 @ 15:44:37
Mil gracias por todo este trabajo, ha representado una gran guía en lo que hago.
No entiendo esto: «…Ambos (Numeric y decimal) cumplen con el estandar SQL-92 para el tipo de datos DECIMAL y eso significa que NUMERIC no cumple con el estandar de SQL-92.
Más adelante dice: «Si además de usar Firebird usas o has usado o piensas usar otro motor SQL entonces para el dinero utiliza NUMERIC porque es el recomendado según el estandar SQL-92.»
Si NUMERIC no cumple, ¿por qué es el recomendado?
Gracias.
wrov
Sep 19, 2015 @ 19:30:14
Tienes razón, esas frases se prestan a confusión.
NUMERIC es el recomendado cuando se trata de dinero porque es el que más se usa en los otros SGBDR. Y aunque el tipo de datos NUMERIC de Firebird no cumple con el estándar un uso criterioso hará que no exista diferencia y pueda ser usado perfectamente.
Por ejemplo, NUMERIC(4, 1) según el estándar debería aceptar como máximo hasta el número 999,9
En Firebird puedes almacenar números más grandes, hasta 3.267,7 inclusive. Sin embargo, el hecho de que puedas hacerlo no significa que debas hacerlo. Si te limitas a guardar allí números hasta el 999,9 entonces estará todo ok y estarás cumpliendo con el estándar.
Saludos.
Walter.
jsoe
Nov 28, 2019 @ 14:28:13
gracias