Таблица 9.2. Диапазон и способ хранения в Firebird типов данных NUMERIC и DECIMAL
Точность
|
Тип
|
Диалект 1
|
Диалект 3
|
1-4
|
NUMERIC
|
SMALLINT
|
SMALLINT
|
1-4
|
DECIMAL
|
INTEGER
|
INTEGER
|
5-9
|
NUMERIC и DECIMAL
|
INTEGER
|
INTEGER
|
10-18
|
NUMERIC и DECIMAL
|
BIGINT
|
DOUBLE PRECISION*
|
* Точные числа с точностью больше чем 9, могут быть объявлены в диалекте 1 базы данных без появления исключения. Эти числа будут храниться как DOUBLE PRECISION и будут подчиняться тем же самым ограничениям точности, что и любые числа с плавающей точкой. В процессе преобразования базы данных диалекта 1 в диалект 3 клиент диалекта 2, открыв таблицу, содержащую столбцы DECIMAL или NUMERIC с точностью, большей 9, получит сообщение об ошибке. Более подробную информацию о преобразованиях диалекта 1 в диалект 3 см. в разд. "Специальная тема миграции: диалекты SQL" главы 8.
Конвертированные базы данных
Если база данных диалекта 1 была обновлена до диалекта 3 с использованием создания резервной копии gbak, а затем восстановлена, то числовые поля, определенные с точностью, большей 9, сохранят тип данных DOUBLE PRECISION. Хотя они будут представлены так, как были вначале определены (например, NUMERIC (15,2)), они будут сохраняться и использоваться в вычислениях как DOUBLE PRECISION.
Более подробную информацию о преобразованиях баз данных диалекта 1 в диалект 3 см. в разд. "Специальная тема миграции: диалекты SQL" главы 8.
Специальные ограничения в статическом SQL
Включающий язык встроенных приложений не может использовать или распознавать малые точности типов данных NUMERIC или DECIMAL С дробной частью, когда они внутренне хранятся как типы SMALLINT или INTEGER. для устранения такой проблемы в любой базе данных, к которой предполагается доступ из таких встроенных приложений (ESQL):
* не определяйте столбцы или домены с типом NUMERIC или DECIMAL малой точности в базе данных диалекта 1. или храните данные как целые и пишите в приложениях код, учитывающий масштаб, или используйте DOUBLE PRECISION и применяйте подходящий алгоритм округления для вычислений;
* в базе данных диалекта 3 определяйте столбцы или домены любого размера типа NUMERIC и DECIMAL, используя точность не меньше 10, чтобы получить их внутреннее хранение как BIGINT. Указывайте масштаб, если вы хотите управлять точностью и масштабом. Используйте ограничения CHECK, если вам нужно контролировать диапазоны значений.
Поведение типов с фиксированной точкой в операциях
Деление
При выполнении деления типов с фиксированной точкой диалекты 1 и 3 ведут себя по-разному.
В диалекте 3, когда оба операнда являются типами с фиксированной точкой, Firebird суммирует масштабы обоих операндов для определения масштаба результата (частного). Частное имеет точность 18. При проектировании запросов с выражениями, содержащими деление, убедитесь, что частное всегда будет иметь точность больше, чем любой из операндов, и примите меры предосторожности в случаях, когда точность потенциально может превысить допустимый максимум 18.
В диалекте 1 деление всегда создает частное типа DOUBLE PRECISION.
Примеры
В диалекте 3 частное от деления DECIMAL(12,3) на DECIMAL(9,2) будет DECIMAL(18,5). Масштабы суммируются:
SELECT 11223344.556/1234567.89 FROM RDB$DATABASE
Это дает 9.09090.
Посмотрим, чем отличается частное, когда этот же запрос выполняется в диалекте 1. Первый операнд трактуется как число DOUBLE PRECISION, потому что его точность (12) превышает максимум масштабируемого типа для диалекта 1. Частное также является числом DOUBLE PRECISION. Результат 9.09090917308727 по причине ошибок, присущих типам с плавающей точкой.
Для следующей таблицы, определенной в диалекте 3, операции деления дают различные результаты.
CREATE TABLE t1 (
i1 INTEGER,
i2 INTEGER,
n1 NUMERIC(16, 2),
n2 NUMERIC(16,2));
COMMIT;
INSERT INTO t1 VALUES (1, 3, 1.00, 3.00);
COMMIT;
Следующий запрос возвращает значение 0.33 типа NUMERIC(18,2), потому что сумма масштабов 0 (операнд 1) и 2 (операнд 2) равна 2:
SELECT i1/n2 from t1
Следующий запрос возвращает значение 0.3333 типа NUMERIC (18,4), потому что сумма масштабов двух операндов равна 4:
SELECT n1/n2 FROM t1
Деление целого на целое
Используя предыдущий пример, следующий запрос в диалекте 3 вернет целое 0, потому что каждый операнд имеет масштаб 0, следовательно, сумма масштабов будет 0:
SELECT i1/i2 FROM t1
В диалекте 1, как и в большинстве других СУБД, деление одного целого на другое целое даст результат с плавающей точкой типа DOUBLE PRECISION:
Читать дальше