Разработчик объявил столбец типа FLOAT 2 , ожидая хранение чисел с двумя знаками после запятой. В чём ошибк...

Разработчик объявил столбец типа FLOAT(2), ожидая хранение чисел с двумя знаками после запятой. В чём ошибка такого предположения?

Проходите собеседования с ИИ помощником Hintsage

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

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

Для фиксированного количества десятичных знаков используют DECIMAL или NUMERIC, где отдельно задаются общая точность и масштаб. Поэтому FLOAT(2) не является аналогом DECIMAL(…, 2) и не подходит для требования «ровно две цифры после запятой».

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

SQL поддерживает разные модели чисел из-за разных задач. Приближённые типы предназначены для научных, инженерных и статистических расчётов, где важны широкий диапазон и эффективность представления, а небольшая погрешность допустима.

Точные десятичные типы появились для значений, где результат должен соответствовать десятичной арифметике: денежным суммам, тарифам, налогам и количествам с фиксированной разрядностью. Поэтому в SQL точность и масштаб DECIMAL не смешиваются с параметром точности FLOAT.

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

Ожидание двух знаков после запятой приводит к неверному выбору типа. Приближённое число хранится в формате, который обычно не может точно представить многие десятичные дроби, например 0,1.

Из-за этого возможны ошибки сравнения, накопление погрешности при суммировании и неожиданные результаты округления. Кроме того, значение FLOAT(2) может иметь другой диапазон и точность в разных СУБД, поэтому полагаться на него как на переносимое правило форматирования нельзя.

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

У FLOAT параметр в скобках относится к точности приближённого представления. Он не означает ни масштаб после десятичного разделителя, ни обязательное округление значения до двух знаков.

У DECIMAL(p, s) параметр p задаёт общее количество десятичных значащих цифр, а s — количество цифр после десятичного разделителя. Например, тип с общей точностью 10 и масштабом 2 предназначен для значений вроде 1234567,89, если значение укладывается в диапазон конкретного типа.

CREATE TABLE measurements ( approximate_value FLOAT, price DECIMAL(10, 2) ); INSERT INTO measurements VALUES (0.1, 19.99);

В этом примере approximate_value может храниться с представимой погрешностью приближённого формата, а price должен соответствовать десятичной точности и масштабу. Однако отображение значения всё равно может зависеть от клиентского инструмента: тип данных и формат вывода — разные вопросы.

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

Если требуется только показывать две цифры, это обычно решается форматированием результата. Если требуется именно хранить и проверять значение с двумя десятичными знаками, применяют DECIMAL с масштабом 2 и при необходимости отдельные ограничения диапазона.

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

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

Рассматривались три варианта. Оставить FLOAT было просто и удобно для вычислений, но это сохраняло риск погрешности. Хранить сумму в целых минимальных единицах, например в копейках, давало точный результат, но требовало явно контролировать пересчёт и диапазон. Использовать DECIMAL(12, 2) было наиболее выразительно для денежной модели и совместимо с бизнес-требованием, хотя арифметика могла быть менее производительной.

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

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

  1. Означает ли DECIMAL(10, 2), что любое значение будет автоматически храниться ровно с двумя десятичными цифрами?

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

  1. Можно ли использовать FLOAT для сравнения результатов вычислений на точное равенство?

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

  1. Станет ли DECIMAL точным независимо от переполнения и преобразований типов?

Нет. DECIMAL точно представляет допустимые десятичные значения в пределах объявленной точности и масштаба, но операция может привести к переполнению, округлению или неявному преобразованию в другой тип. Поэтому нужно проверять диапазоны выражений и явно контролировать преобразования, особенно при смешивании DECIMAL с FLOAT и целыми типами.