Погружение в базы данных Oracle

Данная книга является руководством для начинающих специалистов в области анализа и обработки данных. В книге рассматривается язык SQL и его процедурное расширение PL/SQL от компании Oracle.

Купить книгу

SQL без слёз

Цель книги заключается в том, чтобы научить любого человека работать с реляционными базами данных и получать из них необходимую информацию посредством выполнения SQL-запросов.

Скачать книгу

 ›  ›  ›  › Тип данных NUMBER в PL/SQL Oracle

Тип данных NUMBER в PL/SQL Oracle

Тип данных NUMBER — это тип данных с фиксированной точностью, идеально подходящий для работы с денежными суммами. Это единственный из числовых типов PL/SQL, реализация которого совершенно не зависит от платформы. Все операции с NUMBER должны работать одинаково независимо от оборудования, на котором работает программа.

В простейшем варианте переменная объявляется с ключевым словом NUMBER:

DECLARE
   x NUMBER;

Такое объявление определяет число с плавающей запятой. Память, выделяемая Oracle для переменной, позволяет хранить 40 значащих цифр, а плавающая десятичная запятая обеспечивает оптимальное представление присваиваемых значений. В переменных типа NUMBER могут храниться числа от 10−130 (1.0E-130) до 10126-1 (1.0E126-1). Значения, меньшие 10−130, округляются до 0, а значения, большие либо равные 10126, считаются неопределенными; это создает проблемы на стадии выполнения, но не приводит к выдаче исключения.

Диапазон значений NUMBER продемонстрирован в следующем примере:

DECLARE
   tiny_nbr NUMBER := 1e-130;
   test_nbr NUMBER;
   --                     1111111111222222222233333333334
   --                     1234567890123456789012345678901234567890
   big_nbr      NUMBER := 9.999999999999999999999999999999999999999e125;
   --                     1111111111222222222233333333334444444
   --                     1234567890123456789012345678901234567890123456
   fmt_nbr VARCHAR2(50) := '9.99999999999999999999999999999999999999999EEEE';
BEGIN
   DBMS_OUTPUT.PUT_LINE('tiny_nbr          =' || TO_CHAR(tiny_nbr, '9.9999EEEE'));
   -- Слишком малые числа округляются до нуля
   test_nbr := tiny_nbr / 1.0001;
   DBMS_OUTPUT.PUT_LINE('tiny made smaller =' || TO_CHAR(test_nbr, fmt_nbr));
   -- Слишком большие числа приводят к ошибке
   DBMS_OUTPUT.PUT_LINE('big_nbr           =' || TO_CHAR(big_nbr, fmt_nbr));
   test_nbr := big_nbr * 1.0001;        -- Слишком большое число
   DBMS_OUTPUT.PUT_LINE('big made bigger   =' || TO_CHAR(test_nbr, fmt_nbr));
END;

/*
Результат выполнения программы:
tiny_nbr          = 1.0000E-130
tiny made smaller =   .00000000000000000000000000000000000000000E+00
big_nbr           = 9.99999999999999999999999999999999999999900E+125
big made bigger   =#################################################
*/

При попытке явного присваивания переменной NUMBER слишком большого значения происходит исключение числового переполнения или потери значимости. Но в случае присваивания результата вычислений, превышающего самое большое допустимое значение, исключение не инициируется. Если приложению действительно необходимо работать с такими большими числами, придется либо организовать проверку диапазона, либо перейти на тип BINARY_DOUBLE, поддерживающий сравнение с BINARY_DOUBLE_INFINITY. С другой стороны, использование двоичных типов данных приводит к погрешностям округления; В большинстве приложений из-за ошибок округления предпочтение отдается типу NUMBER.

При объявлении переменной NUMBER можно задать для ее значения дополнительные параметры:

NUMBER (А, B)

Такое объявление определяет число с фиксированной запятой, где A — общее количество значащих цифр в числе, а B — количество цифр справа (положительное значение) или слева (отрицательное значение) от десятичной запятой. Оба параметра должны быть целочисленными литералами; ни переменные, ни константы в объявлении использоваться не могут. Допустимые значения параметра A находятся в диапазоне от 1 до 38, а параметра B — от –84 до 127.

При объявлении чисел с фиксированной запятой параметр B обычно меньше A. Например, переменную для хранения денежных сумм можно объявить как NUMBER(9,2); это позволяет представлять значения до 9 999 999,99 включительно. Интерпретация этого объявления показана на рисунке 1.

Типичное объявление числа с фиксированной запятой в Oracle

Рисунок 1 — Типичное объявление числа с фиксированной запятой

Как видно из рисунка, значение переменной NUMBER(9,2) представляет собой число с фиксированной запятой, состоящее из семи цифр слева от десятичной запятой и двух справа. Значения, хранимые в переменной, будут округляться максимум до сотых (см табл. 1).

Попытка присваивания переменной двух последних значений вызывает исключение, поскольку для представления этих значений требуется больше цифр, чем помещается в переменной. Для хранения значений свыше 10 000 000 нужно минимум восемь значащих цифр в целой части числа. При округлении числа до семи цифр будут генерироваться ошибки. Ситуация становится более интересной при объявлении переменной, у которой количество цифр после десятичной запятой больше общего количества значащих цифр, или отрицательно. Пример представлен на рисунке 2.

Переменная на рисунке 2 содержит то же количество значащих цифр, что и переменная на рисунке 1 но используются они по-другому. Поскольку параметр B равен 11, девять значащих цифр могут представлять только абсолютные значения меньше 0,01, которые округляются до стомиллиардных. Результаты присваивания некоторых значений переменной типа NUMBER(9,11) приведены в таблице 2.

Таблица 1. Округление значений переменной NUMBER(9,2)

Исходное значение Округленное значение
1 234,56 1 234,56
1 234 567,984623 1 234 567,98
1 234 567,985623 1 234 567,99
1 234 567,995623 1 234 568,00
10 000 000,00 Слишком большое значение — ошибка переполнения
–10 000 000,00 Слишком большое значение — ошибка переполнения

Количество цифр после десятичной запятой больше общего количества значащих цифр в Oracle

Рисунок 2 — Количество цифр после десятичной запятой больше общего количества значащих цифр

Таблица 2. Округление значений переменной NUMBER(9,11)

Исходное значение Округленное значение
0,00123456789 0,00123456789
0,000000000005 0,00000000001
0,000000000004 0,00000000000
0,01 Слишком большое значение — ошибка переполнения
−0.01 Слишком большое значение — ошибка переполнения

Если количество цифр в дробной части задано отрицательным значением, то десятичная запятая переносится вправо. Переменная, объявленная как NUMBER(9,-11), показана на рисунке 3.

Количество цифр после десятичной запятой задано отрицательным значением

Рисунок 3 — Количество цифр после десятичной запятой задано отрицательным значением

Мы снова задали девять значащих цифр, но как видно из таблицы 3, теперь вместо малых значений вплоть до стомиллиардных наименьшим значением, которое может содержаться в переменной, стало 100 миллиардов. Значения, меньшие 100 миллиардов, округляются вверх или вниз до ближайших 100 миллиардов, как видно из таблицы 3.

Таблица 3. Округление значений переменной NUMBER(9,-11)

исходное значение Округленное значение
50 000 000 000,123 100 000 000 000
49,999,999,999.999 0
150 000 975 230 001 150 000 000 000 000
100 000 000 000 000 000 000 или 1*1020 Слишком большое значение — ошибка переполнения
-100 000 000 000 000 000 000 или -1*1020 Слишком большое значение — ошибка переполнения

Как видно из рисунка 3 и таблицы 3, отрицательное значение параметра, определяющего количество цифр после запятой, позволяет представлять очень большие значения — но за счет потери данных в младших разрядах. При записи в переменную, объявленную как NUMBER(9,-11), любое абсолютное значение меньше 50 триллионов округляется до нуля.

Учтите, что при объявлении переменных типа NUMBER количество цифр после десятичной запятой не является обязательным параметром и по умолчанию равняется нулю.

Например, следующие два объявления эквивалентны:

x NUMBER(9,0);
x NUMBER(9);

Оба объявления создают целочисленную переменную (то есть переменную с нулем цифр в дробной части) из девяти значащих цифр. В такой переменной могут храниться числа из диапазона от −999 999 999 до 999 999 999.

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

DECLARE
   low_nbr  NUMBER(38,127);
   high_nbr NUMBER(38,-84);
BEGIN
   /* 127 - наибольшее значение второго параметра, поэтому начинаем
      с 1 и перемещаем запятую на 127 позиций влево. Все просто. */
   low_nbr := 1E-127;
   DBMS_OUTPUT.PUT_LINE('low_nbr = ' || low_nbr);
   /* −84 - наиименьшее значение второго параметра. Прибавляем
      37 для нормализации научной записи, получаем E+121. */
   high_nbr := 9.9999999999999999999999999999999999999E+121;
   DBMS_OUTPUT.PUT_LINE('high_nbr = ' || high_nbr);
END;

/*
Результат:
low_nbr =
1.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000E-127
high_nbr =
9.999999999999999999999999999999999999900000000000000000000000000000000000000000000000000000000E+121
*/

Как и прежде, low_nbr представляет — нижнюю, а high_nbr — верхнюю границу положительного диапазона. Обратите внимание: при работе с числами с фиксированной запятой точность ограничивается 38 значащими цифрами.

При таком широком диапазоне допустимых значений и разнообразных возможностях не удивительно, что тип данных NUMBER столь популярен. Используя в объявлениях только ключевое слово NUMBER, можно создать переменные с плавающей запятой, а задавая параметры — переменные с фиксированной запятой. Если количество цифр после запятой указать равным нулю или не задавать вовсе, получится целочисленная переменная. Таким образом, один тип данных NUMBER покрывает все возможные варианты числовых значений.

Метки: , , , .

Записи по теме

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *