Тип данных DECIMAL
DECIMAL (также NUMERIC) — это тип данных, используемый в системах управления базами данных (СУБД) и языках программирования для хранения чисел с фиксированной точностью и масштабом. В отличие от чисел с плавающей запятой (например, FLOAT или DOUBLE), DECIMAL хранит значения точно, без ошибок округления, что делает его незаменимым для финансовых расчётов, бухгалтерского учёта и других задач, где требуется высокая точность десятичных дробей.
История и стандарты
Тип DECIMAL был стандартизирован в языке SQL (первая версия — SQL-86, затем SQL:1992, SQL:2003). Первоначально он был предложен как альтернатива типам REAL и DOUBLE PRECISION (с плавающей точкой), которые допускают погрешности при арифметических операциях. Стандарт SQL определяет два синонимичных ключевых слова: DECIMAL и NUMERIC. Формально, по стандарту, NUMERIC гарантирует точное соблюдение заданной точности, а DECIMAL допускает реализацию с точностью не ниже указанной, хотя на практике большинство СУБД трактуют их как взаимозаменяемые.
В других областях, например, в языке программирования COBOL (1960-е годы), десятичные числа с фиксированной точкой использовались под названием PIC 9(n)V9(m) (PICTURE). Впоследствии концепция была заимствована всеми крупными СУБД: Oracle Database (тип NUMBER), PostgreSQL (тип numeric), MySQL (типы DECIMAL и NUMERIC), Microsoft SQL Server (типы DECIMAL и NUMERIC), а также многими специализированными бухгалтерскими и финансовыми системами.
Синтаксис и параметры
Тип DECIMAL обычно объявляется в формате:
``sql DECIMAL(точность, масштаб) ``
- Точность (precision, p) — общее количество значащих цифр числа (слева и справа от десятичной точки). Диапазон зависит от СУБД; чаще всего — от 1 до 38 (в Oracle — до 38, в SQL Server — до 38, в MySQL — до 65). Максимальная точность может быть расширена в новых версиях.
- Масштаб (scale, s) — количество цифр после десятичной точки. Масштаб не может быть больше точности (s ≤ p). Если масштаб не указан, по умолчанию принимается 0 (целое число). Если точность не указана, в разных СУБД могут применяться различные умолчания (обычно
DECIMAL(18,0)илиDECIMAL(10,0)).
Примеры объявлений:
price DECIMAL(10,2)— числа с 8 цифрами до запятой и 2 после (макс. значение: 99999999,99).rate DECIMAL(5,4)— числа от –9,9999 до +9,9999.count DECIMAL(9,0)— целые числа от –999999999 до +999999999.
Отличия от NUMERIC, FLOAT, DOUBLE
| Тип | Хранение | Точность | Применение |
|---|---|---|---|
DECIMAL / NUMERIC | Двоично-десятичное кодирование (BCD) или десятичное представление | Фиксированная, точная | Финансы, бухгалтерия, налоги |
FLOAT / REAL | С плавающей точкой (IEEE 754) | Приблизительная, с ошибками округления | Научные расчёты, статистика, графика |
DOUBLE PRECISION | С плавающей точкой двойной точности | Приблизительная, более высокая точность | Аналогично FLOAT, но с большей точностью |
Устройство и хранение
Точное хранение DECIMAL основано на двоично-десятичном кодировании (BCD) или специализированных десятичных форматах (например, decfloat). Каждая цифра от 0 до 9 кодируется отдельным 4-битным полубайтом (в BCD) или используется упакованное представление (по две цифры на байт). В современных СУБД (PostgreSQL, SQL Server) применяются алгоритмы сжатия, позволяющие хранить до 9–16 цифр в одном 64-битном блоке.
Типичные размеры памяти для хранения:
- Для точности 1–9 цифр — 4 байта.
- Для точности 10–19 цифр — 8 байт.
- Для точности 20–28 цифр — 13 байт.
- Для точности 29–38 цифр — 16 или 17 байт.
Точное внутреннее устройство варьируется между СУБД.
Применение
Финансовый учёт и бухгалтерия
Наиболее частое и важное применение DECIMAL — хранение сумм, курсов валют, налогов, процентных ставок, коэффициентов. В бухгалтерском учёте (например, в план счетов, оборотно-сальдовые ведомости) все денежные значения должны храниться с абсолютной точностью до копейки (масштаб 2 и более). Использование FLOAT или DOUBLE может привести к накоплению ошибок округления, что недопустимо для финансовой отчётности и законодательных требований (например, правила МСФО и РСБУ в РФ).
Научные и статистические данные
В случаях, когда требуется строгая повторяемость и сопоставимость результатов (например, при обработке измерений с фиксированным количеством десятичных знаков), DECIMAL предпочтительнее чисел с плавающей запятой. Особенно это актуально в демографии, социологии, метеорологии при публикации официальных данных (коэффициенты рождаемости, доли населения, проценты).
Административные и государственные информационные системы
В России DECIMAL активно используется в системах Федерального казначейства, бюджетного учёта, налоговых расчётах (например, суммы НДС, начисления пеней). Также он применяется в государственных реестрах (ЕГРЮЛ, ЕГРИП), где хранятся денежные показатели или индексы.
Интернет-торговля и электронные кошельки
Поскольку любые транзакции с реальными деньгами требуют точности до копейки (или его аналога), DECIMAL является стандартом для хранения балансов счетов, стоимости товаров, комиссий и скидок в платёжных системах, криптобиржах и банковских API.
Особенности и ограничения
Арифметические операции
Арифметика с DECIMAL выполняется в десятичной системе счисления, поэтому результат сложения или умножения двух DECIMAL-чисел теоретически должен быть точным. Однако точность результата может потребовать большей точности, чем задано; в этом случае СУБД либо округляет результат по определённым правилам (банковское округление, математическое округление), либо выводит ошибку переполнения.
Производительность
Операции с DECIMAL медленнее, чем с FLOAT или DOUBLE, из-за необходимости использования эмуляции десятичной арифметики (особенно на процессорах без аппаратной поддержки BCD). В высоконагруженных системах (аналитические запросы, OLAP) это может потребовать оптимизации: например, перевод DECIMAL в целые числа (храня сумму в копейках) для ускорения расчётов.
Ограничения по диапазону
Максимальное значение DECIMAL зависит от точности. При точности 38 максимальное значение приблизительно равно 10^38 – 1. Для финансовых расчётов это более чем достаточно, но для астрономических или физических величин может потребоваться NUMERIC с большей точностью (за пределами SQL-стандарта, в специализированных библиотеках).
Поддержка в основных СУБД
| СУБД | Поддерживаемый тип | Максимальная точность | Особенности |
|---|---|---|---|
| PostgreSQL | NUMERIC / DECIMAL | 131072 (при использовании numeric с указанием точности свыше 1000) | Стандартный тип; поддерживает масштаб 0–16383 |
| MySQL / MariaDB | DECIMAL / NUMERIC | 65 | По умолчанию DECIMAL(10,0) |
| Microsoft SQL Server | DECIMAL / NUMERIC | 38 | Эквивалентны по функциональности |
| Oracle Database | NUMBER | 38 | NUMBER(p,s) — общий тип для точных и целых чисел |
| SQLite | Нет отдельного DECIMAL | — | Использует REAL или INTEGER; точность не гарантируется |
Примеры использования
Создание таблицы с денежным полем (PostgreSQL): ``sql CREATE TABLE orders ( id SERIAL PRIMARY KEY, amount DECIMAL(12,2) NOT NULL, tax_rate DECIMAL(5,4) NOT NULL ); ``
Вставка и вычисление (SQL Server): ``sql INSERT INTO orders (amount, tax_rate) VALUES (1500, 0.2000); SELECT amount * tax_rate AS tax FROM orders; ` Результат: 300.000000` (точное значение, без потерь).
Хранение валютного курса (MySQL): ``sql CREATE TABLE exchange_rates ( currency_code CHAR(3), rate DECIMAL(10,6) -- например, 1.250000 (6 знаков после запятой) ); ``
Критика и альтернативы
Основной недостаток DECIMAL — медленная арифметика по сравнению с целыми числами. В некоторых высоконагруженных системах применяют «копеечное хранение»: сумму умножают на 100 (или на 10000 для четырёхзначных дробей) и хранят как BIGINT или INTEGER. Это позволяет использовать быструю целочисленную арифметику и снижает накладные расходы, но требует дополнительного контроля при делении. Такой подход часто используется в бэкенде электронных кошельков (например, YooMoney, Сбербанк API).
Существуют также библиотеки для языков программирования, предоставляющие десятичные числа высокой точности (Java — BigDecimal, Python — Decimal из модуля decimal, C# — decimal). Они не зависят от СУБД и используются для обработки чисел на стороне приложения.
Интересные факты
- В ранних версиях MySQL тип DECIMAL хранился как строка символов (до версии 5.0.3), что приводило к неэффективному использованию памяти и низкой производительности. Начиная с MySQL 5.0.3 (https://dev.mysql.com/doc/relnotes/mysql/5.0/en/news-5-0-3.html) DECIMAL хранится в двоичном формате.
- Стандарт IEEE 754-2008 (редакция 2019 года) определил формат «decimal floating-point» (decFloat), который сочетает преимущества DECIMAL и чисел с плавающей запятой (большой диапазон значений с фиксированной точностью). Этот формат поддерживается некоторыми процессорами (IBM POWER9, Z/Architecture) и СУБД (Oracle, IBM Db2).
- В языке SQL в некоторых СУБД (например, PostgreSQL) подтип
MONEYявляется устаревшей формой DECIMAL с фиксированным масштабом (2) и региональными настройками форматирования.
Источники
- ISO/IEC 9075:1992, SQL-92 standard
- PostgreSQL Documentation, Chapter 8.1. Numeric Types
- MySQL Reference Manual, 11.1.3 Fixed-Point Types (DECIMAL, NUMERIC)
- T-SQL Reference (Microsoft SQL Server), decimal and numeric (Transact-SQL)
- Oracle Database SQL Language Reference, Data Types
- IEEE Standard for Floating-Point Arithmetic (IEEE 754-2019)
- Стандарты бухгалтерского учёта РФ (ПБУ 4/99, ПБУ 18/02)
- Статья «Decimal floating point in computer arithmetic», M. F. Cowlishaw, IBM Journal of Research and Development, 2003.
- Документация Yandex Pay (YooMoney) по хранению денежных сумм в системе.
BFOmetr — база данных и аналитика по компаниям России.
На главную BFOmetr →