Firebird РУКОВОДСТВО РАЗРАБОТЧИКА БАЗ ДАННЫХ
Шрифт:
Для следующей таблицы, определенной в диалекте 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),
SELECT n1/n2 FROM t1
Используя предыдущий пример, следующий запрос в диалекте 3 вернет целое 0, потому что каждый операнд имеет масштаб 0, следовательно, сумма масштабов будет 0:
SELECT i1/i2 FROM t1
В диалекте 1, как и в большинстве других СУБД, деление одного целого на другое целое даст результат с плавающей точкой типа DOUBLE PRECISION:
SELECT 1/3 AS RESULT FROM RDB$DATABASE
Это дает .333333333333333.
Хотя настоящее правило диалекта 1 является интуитивным для языков программирования, оно не соответствует стандарту SQL-92. Целые типы имеют масштаб 0. Для согласованности это требует, чтобы результат (частное) любой операции деления целого на целое соответствовал правилам масштабирования для чисел с фиксированной точкой и был бы целым.
Диалект 3 соответствует стандарту и усекает частное от операций деления целого на целое до целого. Следовательно, следующий оператор является неразумным:
SELECT 1/3 AS RESULT FROM RDB$DATABASE
Он вернет 0.
Если вам нужно сохранить дробную часть в результате (в частном) деления целого на целое в диалекте 3, убедитесь, что у одного из операндов присутствует нужный масштаб, или включите "множитель" в выражение, чтобы гарантировать масштаб результата.
Примеры:
SELECT 1.00/3 AS RESULT FROM RDB$DATABASE
Вернет .33.
SELECT (5 * 1.00)/2 AS RESULT FROM RDB$DATABASE
Этот вернет 2.50.
База данных диалекта 1, которая была открыта клиентом диалекта 3, может преподнести некоторые сюрпризы в отношении деления целых чисел. Когда операция выполняет нечто, что приводит к проверке условия CHECK, или выполняется хранимая процедура или триггер, то осуществляемые действия основаны на диалекте, на котором CHECK, хранимая процедура или триггер были определены, а не на действующем диалекте, на котором приложение выполняет проверку, хранимую процедуру или триггер.
Например, в базе данных диалекта 1 таблица содержит столбцы MYCOL1 (INTEGER) и MYCOL2 (INTEGER) и следующее условие CHECK, которое было определено, когда база данных имела диалект 1:
CHECK(MYCOL1 / MYCOL2 >0.5)
Пусть теперь пользователь запускает isql или приложение, задав диалект 3. Программа пытается добавить строку в конвертированную базу данных:
INSERT INTO MYTABLE (COL1, COL2) VALUES (2,3);
Поскольку ограничение CHECK было определено в диалекте 1, оно вернет частное 0.666666666666667, и строка будет соответствовать условию CHECK.
Обратное также
! ! !
СОВЕТ. Мораль всего этого: используйте базы данных диалекта 3 и всегда соединяйтесь с ними, применяя диалект 3. Если вы собираетесь использовать Firebird, то обновите все существующие базы данных до диалекта 3 - желательно описав новую базу данных и поместив в нее ваши старые данные - таким образом вы сохраните покой и сможете избежать уймы неприятных сюрпризов.
. ! .
Если оба операнда являются точными числами, умножение операндов даст точное число с масштабом, равным сумме масштабов операндов. Например,
CREATE TABLE t1 (
n1 NUMERIC(9,2),
n2 NUMERIC (9,3) ) ;
COMMIT;
INSERT INTO t1 VALUES (12.12, 123.123);
COMMIT;
Следующий запрос возвращает число 1492.25076, потому что n1 имеет масштаб 2, а n2 - масштаб 3. Сумма масштабов 5.
SELECT n1*n2 FROM t1
В диалекте 3 точность результата умножения чисел с фиксированной точкой будет равна 18. Нужно принять меры предосторожности, чтобы быть уверенным, что не будет переполнения результата при распространении масштаба в умножении.
В диалекте 1, если распространение масштаба приводит к тому, что вычисление даст результат с точностью больше 9, то результатом будет DOUBLE PRECISION.
Если все операнды являются точными числами, то сложение и вычитание операндов даст точное число с масштабом, равным максимальному масштабу операндов. Например,
CREATE TABLE t1 (
n1 NUMERIC(9, 2) ,
n2 NUMERIC(9, 3)) ;
COMMIT;
INSERT INTO t1 VALUES (12.12, 123.123);
COMMIT;
SELECT n1 + n2 FROM t1;
Этот запрос возвращает 135.243, выбирая максимальный масштаб операндов. Аналогично, следующий запрос возвращает число -111.003:
SELECT n1 - n2 FROM t1;
В диалекте 3 результат любого сложения или вычитания имеет тип NUMERIC(18,n). В диалекте 1 он имеет тип NUMERIC (9, n), где n - масштаб максимального операнда.
Числовой ввод и показатели степени
Любые числовые строки в DSQL, которые могут быть сохранены как DECIMAL(18,S), вычисляются без потери точности, что могло бы произойти при промежуточном сохранении в виде DOUBLE. Синтаксический анализатор DSQL можно заставить распознавать числовые строки как числа с плавающей точкой при использовании научной нотации - если добавить символ "е" или "Е" перед показателем степени, который может быть нулевым.