Чтение онлайн

ЖАНРЫ

MySQL: руководство профессионала

Паутов Алексей В.

Шрифт:

| 3 | 2 |

+------------+--------------+

Для вставок в DECIMAL или целочисленный столбец, если адресат представляет собой точный тип данных, используется метод "округления половины" независимо от того, является ли значение, которое будет вставлено, точным или приблизительным:

mysql> CREATE TABLE t (d DECIMAL(10,0));

Query OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO t VALUES(2.5),(2.5E0);

Query OK, 2 rows affected, 2 warnings (0.00 sec)

Records: 2 Duplicates: 0 Warnings: 2

mysql> SELECT d FROM t;

+------+

| d |

+------+

| 3 |

| 3 |

+------+

1.5.

Примеры математической точности

Этот раздел обеспечивает некоторые примеры, которые показывают запросы с математической точностью в MySQL 5.1.

Пример 1. Числа используются с их точным значением, как даны, когда возможно:

mysql> SELECT .1 + .2 = .3;

+--------------+

| .1 + .2 = .3 |

+--------------+

| 1 |

+--------------+

Для значений с плавающей запятой, результаты неточны:

mysql> SELECT .1E0 + .2E0 = .3E0;

+--------------------+

| .1E0 + .2E0 = .3E0 |

+--------------------+

| 0 |

+--------------------+

Другой способ увидеть различие в точной и приблизительной обработке значения состоит в том, чтобы добавить маленькое число к сумме много раз. Рассмотрите следующую сохраненную процедуру, которая добавляет .0001 к переменной 1000 раз:

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;

Сумма для d и f логически должна быть 1, но это истинно только для десятичного вычисления. Вычисление с плавающей запятой представляет маленькие ошибки:

+--------+------------------+

| d | f |

+--------+------------------+

| 1.0000 | 0.99999999999991 |

+--------+------------------+

Пример 2. Умножение выполняется с масштабом, требуемым стандартом SQL. То есть, для двух чисел X1 и X2, которые имеют масштаб S1 и S2, масштаб результата: S1+S2:

mysql> SELECT .01 * .01;

+-----------+

| .01 * .01 |

+-----------+

| 0.0001 |

+-----------+

Пример 3. Поведение округления четко:

Поведение округления (например, с функцией ROUND) независимо от реализации основной библиотеки C, что означает, что результаты непротиворечивы

на разных платформах.

Округление для столбцов с точным значением использует округление половины, как показано здесь:

mysql> SELECT ROUND(2.5), ROUND(-2.5);

+------------+-------------+

| ROUND(2.5) | ROUND(-2.5) |

+------------+-------------+

| 3 | -3 |

+------------+-------------+

Однако, округление для значений с плавающей запятой использует библиотеку C, которая на многих системах использует другую логику работы:

mysql> SELECT ROUND(2.5E0), ROUND(-2.5E0);

+--------------+---------------+

| ROUND(2.5E0) | ROUND(-2.5E0) |

+--------------+---------------+

| 2 | -2 |

+--------------+---------------+

Пример 4. В строгом режиме вставка значения, которое является слишком большим, приводит к переполнению и ошибке, а не к усечению до допустимого значения. Когда MySQL не выполняется в строгом режиме, происходит усечение к допустимому значению:

mysql> SET sql_mode='';

Query OK, 0 rows affected (0.00 sec)

mysql> CREATE TABLE t (i TINYINT);

Query OK, 0 rows affected (0.01 sec)

mysql> INSERT INTO t SET i = 128;

Query OK, 1 row affected, 1 warning (0.00 sec)

mysql> SELECT i FROM t;

+------+

| i |

+------+

| 127 |

+------+

1 row in set (0.00 sec)

Однако, условие переполнения происходит, если включен строгий режим:

mysql> SET sql_mode='STRICT_ALL_TABLES';

Query OK, 0 rows affected (0.00 sec)

mysql> CREATE TABLE t (i TINYINT);

Query OK, 0 rows affected (0.00 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)

Пример 5: В строгом режиме и с настройкой ERROR_FOR_DIVISION_BY_ZERO деление на нуль вызывает ошибку, а не результат NULL.

В нестрогом режиме деление на нуль имеет результат NULL:

mysql> SET sql_mode='';

Query OK, 0 rows affected (0.01 sec)

mysql> CREATE TABLE t (i TINYINT);

Query OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO t SET i = 1 / 0;

Query OK, 1 row affected (0.00 sec)

mysql> SELECT i FROM t;

+------+

| i |

Поделиться с друзьями: