Программирование SQLDDL и типы данныхРазработчик серверной части, работающий с реляционными базами данных

В таблице задан тип DECIMAL 5, 2 . Предскажите, какая вставка завершится ошибкой из за диапазона типа, и об...

В таблице задан тип DECIMAL(5, 2). Предскажите, какая вставка завершится ошибкой из-за диапазона типа, и объясните механизм.

CREATE TABLE prices (
    item_id INTEGER PRIMARY KEY,
    amount DECIMAL(5, 2)
);

INSERT INTO prices VALUES (1, 999.99);
INSERT INTO prices VALUES (2, 1000.00);
Проходите собеседования с ИИ помощником Hintsage

Краткий ответ

Ошибкой завершится вторая вставка: значение 1000.00 не помещается в DECIMAL(5, 2). Первое число в скобках — общая точность типа, второе — количество цифр после десятичного разделителя; значит, до десятичного разделителя остаётся 5 - 2 = 3 цифры.

Исторический контекст

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

Постановка проблемы

Для DECIMAL(5, 2) всего разрешено пять значащих цифр, из которых две находятся после десятичного разделителя. Поэтому максимально допустимое по модулю значение — 999.99; значение 1000.00 требует уже шести цифр: четырёх до разделителя и двух после него.

Если выбрать слишком маленькую точность, корректные бизнес-значения начнут отклоняться при вставке или обновлении. Если выбрать чрезмерно большую точность, возрастут требования к хранению и может стать менее очевидной проверка корректности данных.

Подробное решение

В данном объявлении:

CREATE TABLE prices ( item_id INTEGER PRIMARY KEY, amount DECIMAL(5, 2) ); INSERT INTO prices VALUES (1, 999.99); INSERT INTO prices VALUES (2, 1000.00);

DECIMAL(5, 2) означает:

  • 5 — максимум цифр во всём числе, без учёта знака и десятичного разделителя;
  • 2 — максимум цифр в дробной части;
  • 3 — максимум цифр в целой части.

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

Знак отрицательного числа не считается цифрой точности: -999.99 также укладывается в этот тип. При значении с большим количеством дробных цифр конкретная СУБД может применять правила округления или выдавать ошибку; такое поведение нужно проверять по документации используемой СУБД.

NUMERIC и DECIMAL относятся к стандартным точным числовым типам, хотя детали реализации и некоторые правила приведения типов могут различаться между СУБД. Для денежных значений обычно дополнительно задают NOT NULL и проверяют бизнес-ограничения отдельным CHECK.

Ситуация из практики

Интернет-магазин хранит цену товара. Команда выбрала DECIMAL(5, 2), потому что большинство цен меньше тысячи, но затем появился товар стоимостью 1250.00. Вставка стала завершаться ошибкой, хотя число было корректным с точки зрения бизнеса.

Вариант с FLOAT решил бы проблему диапазона, но создал бы риск приближённых результатов при расчётах и сравнении денежных сумм. Вариант с DECIMAL(5, 2) сохранил бы текущую модель, но продолжил бы отклонять более дорогие товары.

Выбранное решение — увеличить точность, например до DECIMAL(10, 2), предварительно проверив существующие данные и требования к максимальной цене. Такой тип сохраняет точность до копеек и допускает значения до 99 999 999.99; результатом становится предсказуемое хранение денег без неоправданного перехода к приближённой арифметике.

Что кандидаты часто упускают

1. Вопрос: Считается ли знак минус частью точности DECIMAL(p, s)?

Ответ: Нет. Точность относится к цифрам числа, а знак и десятичный разделитель в неё не входят. Поэтому DECIMAL(5, 2) допускает как 999.99, так и -999.99, если остальные ограничения столбца это разрешают.

2. Вопрос: Что произойдёт с числом 12.345, если столбец имеет тип DECIMAL(5, 2)?

Ответ: Универсально обещать один результат для всех СУБД нельзя. Некоторые реализации округляют значение до масштаба 2, получая 12.35, а другие режимы или операции могут завершиться ошибкой. В прикладном коде нельзя полагаться на неявное округление: нужное правило следует задать явно и проверить средствами конкретной СУБД.

3. Вопрос: Достаточно ли увеличить точность, чтобы разрешить большие суммы с тем же количеством знаков после разделителя?

Ответ: Да, если увеличить именно p, сохранив s. Например, переход от DECIMAL(5, 2) к DECIMAL(10, 2) увеличит число допустимых цифр в целой части с трёх до восьми. Но изменение типа является DDL-операцией: перед ним нужно учитывать совместимость существующих данных, индексов, ограничений и зависимого прикладного кода.