Где хранить деньги в БД?
Вот вы проектируете систему, в которой встречаются финансовые данные. Вы стоите перед выбором: в каком типе данных лучше хранить деньги?
Начну с конца — в каком типе точно НЕ хранить деньги? Конечно, это float. С одной стороны, вроде бы float подходит, так как денежные суммы обычно хранятся с целой и дробной частью: рубли с копейками. Например, эти наши любимые цены 9 руб. 75 копеек логично завести в поле «Цена» и записать как 9,75.
НО! Только не используйте для этого типы данных, подобные float, потому что это тип приблизительных числовых данных для чисел с плавающей запятой, и при вычислениях он будет давать погрешность.
Как сказал Боб Мартин (Robert C. Martin): «В этом нет ничего смешного, я знавал людей, которых посадили в тюрьму за то, что они использовали тип float в БД для хранения денег».
А что тогда подходит?
Теперь, когда мы выяснили, что типы для чисел с плавающей запятой (да, да и double тоже) нам НЕ подходят, посмотрим, какие есть варианты:
● MONEY и SmallMoney (для небольших сумм). Соответственно, 8 и 4 байта. Это встроенные типы в SQL Server, и в общем это отличный выбор. Единственный минус в том, что это нестандартные типы данных (не ANSI), и они есть только в SQL Server. Это нужно учесть, если у вас есть хоть малейший шанс перехода с SQL Server на другую СУБД.
● DECIMAL (19,4) Тип с фиксированной точностью, весит целых 9 байт. 4 — количество знаков, после запятой. Зачем 4, спросите вы? Ведь копейки, центы и прочие популярные валюты имеют только 2 знака? Да, хотя есть экзотические валюты, где дробная часть 3 знака. Кроме того, если у вас не просто хранятся деньги, а вы с ними производите какие-то вычисления с использованием умножения или, даже страшно представить, деления, у вас будет образовываться дробная часть. А на больших объемах эта дробная часть может быть кому-то и сложится в виллу, а может быть и нет… Поэтому лучше сделайте точность больше. В некоторых системах я видела до 8 знаков после запятой. При этом учтите, что округление должно быть одинаковое на все финансовые данные, которые выводятся из базы данных, так как бухгалтерия страшно нервничает, если у вас во внутренних документах для компании и для клиента указывается разное количество копеек.
● А есть ещё варианты? Да, есть! Вы можете использовать тип INT. При этом обычно все суммы в БД хранятся в копейках, а при отображении делятся на 100. Этот подход встречается не очень часто, но имеет место быть, и в тюрьму за него не сажают.
Если вы всё же обнаружили у себя деньги в типе float, задумайтесь над рефакторингом. Даже если это кажется дорого, с ростом проекта проблемы будут только расти, и лучше это сделать прямо сейчас, не откладывая на потом.
А как вы храните деньги в БД? Пишите в комментариях!