Esta sección proporciona algunos ejemplos que muestran cómo la matemática precisa mejora los resultados de consultas en MySQL 5 comparados con versiones anteriores.
Ejemplo 1. Los números se usan con su valor exacto tal y como se da cuando es posible.
Antes de MySQL 5.0.3, los números tratados como valores en coma flotante producen valores inexactos:
mysql> SELECT .1 + .2 = .3; +--------------+ | .1 + .2 = .3 | +--------------+ | 0 | +--------------+
Desde MySQL 5.0.3, los números se usan tal y como se dan cuando es posible:
mysql> SELECT .1 + .2 = .3; +--------------+ | .1 + .2 = .3 | +--------------+ | 1 | +--------------+
Sin embargo, para valores en coma flotante, todavía ocurre la inexactitud:
mysql> SELECT .1E0 + .2E0 = .3E0; +--------------------+ | .1E0 + .2E0 = .3E0 | +--------------------+ | 0 | +--------------------+
Otra forma de ver la diferencia en el tratamiento de valores aproximados y exactos es añadir un pequeño número en una suma muchas veces. Considere el siguiente procedimiento aproximado, que añade .0001 a una variable 1000 veces.
CREATE PROCEDURE p ()
BEGIN
  DECLARE i INT DEFAULT 0;
  DECLARE d DECIMAL(10,4) DEFAULT 0;
  DECLARE f FLOAT DEFAULT 0;
  WHILE i < 10000 DO
    SET d = d + .0001;
    SET f = f + .0001E0;
    SET i = i + 1;
  END WHILE;
  SELECT d, f;
END;
      La suma de ambos d y f
      lógicamente debe ser 1, pero eso es cierto sólo para cálculos
      decimales. El cálculo de coma flotante introduce pequeños
      errores:
    
+--------+------------------+ | d | f | +--------+------------------+ | 1.0000 | 0.99999999999991 | +--------+------------------+
      Ejemplo 2. La multiplicación se
      hace con la escala requerida por el estándar SQL. Esto es, para
      dos números X1 y
      X2 con escala
      S1 y S2, la
      escala del resultado es S1 +
      S2
Antes de MySQL 5.0.3, esto es lo que ocurre:
mysql> SELECT .01 * .01; +-----------+ | .01 * .01 | +-----------+ | 0.00 | +-----------+
El valor mostrado es incorrecto. El valor se calcula correctamente en este caso, pero no se muestra en la escala requerida. Para comprobar que el valor calculado realmente es .0001, pruebe:
mysql> SELECT .01 * .01 + .0000; +-------------------+ | .01 * .01 + .0000 | +-------------------+ | 0.0001 | +-------------------+
Desde MySQL 5.0.3, la escala mostrada es correcta:
mysql> SELECT .01 * .01; +-----------+ | .01 * .01 | +-----------+ | 0.0001 | +-----------+
Ejemplo 3. El comportamiento del redondeo está bien definido.
      Antes de MySQL 5.0.3, el comportamiento para el redondeo (por
      ejemplo con la función ROUND() ) depende de la
      implementación de la biblioteca C subyacente. Esto provoca
      inconsistencias entre plataformas. Por ejemplo, puede obtener un
      valor distinto en Windows y en Linux, o un valor distinto en
      máquinas x86 y PowerPc.
    
Desde MySQL 5.0.3, el redondeo se realiza así:
      El redondeo para columnas DECIMAL y de valor
      exacto usa la regla de "redondeo hacia arriba". Los valoeres con
      una parte fraccional de .5 o mayor se redondean al entero más
      cercano y más lejano al cero, como se muestra aquí:
    
mysql> SELECT ROUND(2.5), ROUND(-2.5); +------------+-------------+ | ROUND(2.5) | ROUND(-2.5) | +------------+-------------+ | 3 | -3 | +------------+-------------+
El redondeo de valores en coma flotante todavía usa la biblioteca C, que en muchos sistemas usa la regla "redondeo al número par más cercano". Los valores con cualquier parte fraccional se redondean al entero par más cercano:
mysql> SELECT ROUND(2.5E0), ROUND(-2.5E0); +--------------+---------------+ | ROUND(2.5E0) | ROUND(-2.5E0) | +--------------+---------------+ | 2 | -2 | +--------------+---------------+
Ejemplo 4. Para inserciones en tablas, un valor demasiado grande provoca un desbordamiento y un error, no se trunca a un valor legal. (Esto requiere modo estricto.)
Antes de MySQL 5.0.2, se truncaba a un valor legal:
mysql> CREATE TABLE t (i TINYINT); Query OK, 0 rows affected (0.00 sec) mysql> INSERT INTO t SET i = 128; Query OK, 1 row affected, 1 warning (0.01 sec) mysql> SELECT i FROM t; +------+ | i | +------+ | 127 | +------+ 1 row in set (0.00 sec)
Desde MySQL 5.0.2, ocurre un desbordamiento si el modo estricto está activado:
mysql> CREATE TABLE t (i TINYINT); Query OK, 0 rows affected (0.01 sec) mysql> SET sql_mode='STRICT_ALL_TABLES'; Query OK, 0 rows affected (0.10 sec) mysql> INSERT INTO t SET i = 128; ERROR 1264 (22003): Out of range value adjusted for column 'i' at row 1 mysql> SELECT i FROM t; Empty set (0.00 sec)
      Ejemplo 5. Para inserciones en
      tablas, la división por cero causa un error, no un resultado
      NULL. (Esto requiere modo estricto y
      ERROR_FOR_DIVISION_BY_ZERO.)
    
      Antes de MySQL 5.0.2, la división por cero tiene un resultado de
      NULL:
    
mysql> CREATE TABLE t (i TINYINT); Query OK, 0 rows affected (0.01 sec) mysql> INSERT INTO t SET i = 1 / 0; Query OK, 1 row affected (0.06 sec) mysql> SELECT i FROM t; +------+ | i | +------+ | NULL | +------+ 1 row in set (0.01 sec)
Desde MySQL 5.0.2, la división por cero es un error si el modo SQL apropiado está activado:
mysql> CREATE TABLE t (i TINYINT); Query OK, 0 rows affected (0.00 sec) mysql> SET sql_mode='STRICT_ALL_TABLES,ERROR_FOR_DIVISION_BY_ZERO'; Query OK, 0 rows affected (0.00 sec) mysql> INSERT INTO t SET i = 1 / 0; ERROR 1365 (22012): Division by 0 mysql> SELECT i FROM t; Empty set (0.01 sec)
Ejemplo 6. En MySQL 4, literales de valores aproximados y exactos se convierten en valores de coma flotante y doble precisión:
mysql> CREATE TABLE t SELECT 2.5 AS a, 25E-1 AS b; mysql> DESCRIBE t; +-------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+---------+-------+ | a | double(3,1) | | | 0.0 | | | b | double | | | 0 | | +-------+-------------+------+-----+---------+-------+
      En MySQL 5, el literal de valor aproximado todavía se convierte
      en un valor de coma flotante, pero el literal de valor exacto se
      trata como DECIMAL:
    
mysql> CREATE TABLE t SELECT 2.5 AS a, 25E-1 AS b; mysql> DESCRIBE t; +-------+--------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+--------------+------+-----+---------+-------+ | a | decimal(3,1) | NO | | 0.0 | | | b | double | NO | | 0 | | +-------+--------------+------+-----+---------+-------+
Ejemplo 7. Si el argumento de una función agregada es un tipo numérico exacto, el resultado debe serlo también, con una escala al menos igual a la del argumento. El resultado no debe siempre ser un valor double.
Considere estos comandos:
mysql> CREATE TABLE t (i INT, d DECIMAL, f FLOAT); mysql> INSERT INTO t VALUES(1,1,1); mysql> CREATE TABLE y SELECT AVG(i), AVG(d), AVG(f) FROM t;
Resultado antes de MySQL 5.0.3:
mysql> DESCRIBE y; +--------+--------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +--------+--------------+------+-----+---------+-------+ | AVG(i) | double(17,4) | YES | | NULL | | | AVG(d) | double(17,4) | YES | | NULL | | | AVG(f) | double | YES | | NULL | | +--------+--------------+------+-----+---------+-------+
El resultado es un double independientemente del tipo del argumento.
Resultado desde MySQL 5.0.3:
mysql> DESCRIBE y; +--------+---------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +--------+---------------+------+-----+---------+-------+ | AVG(i) | decimal(64,0) | YES | | NULL | | | AVG(d) | decimal(64,0) | YES | | NULL | | | AVG(f) | double | YES | | NULL | | +--------+---------------+------+-----+---------+-------+
El resultado es un double sólo para el argumento de coma flotante. El resultado es un tipo exacto para argumentos con tipos exactos.
Ésta es una traducción del manual de referencia de MySQL, que puede encontrarse en dev.mysql.com. El manual de referencia original de MySQL está escrito en inglés, y esta traducción no necesariamente está tan actualizada como la versión original. Para cualquier sugerencia sobre la traducción y para señalar errores de cualquier tipo, no dude en dirigirse a mysql-es@vespito.com.

