Отправляет email-рассылки с помощью сервиса Sendsay

Вопросы и ответы по MS SQL Server

  Все выпуски  

Вопросы и ответы по MS SQL Server


Информационный Канал Subscribe.Ru


Вопросы и ответы по MS SQL Server

Выпуск No. 5 от 2003-03-23

Вопрос : Какой тип данных предпочтительнее выбрать для хранения денежных величин?

Ответ:
Это очень спорный вопрос. Сколько людей - столько мнений. Я также не претендую на исключительную правоту и законченность ответа.
Спешу Вас порадовать. Какой бы тип Вы не выбрали, в нем все равно будет недостаток. Но недостаток выбора будет обходить Вас стороной, если сделать правильный выбор. О чем это я? Перечислю все типы данных, в которых удобнее хранить денежные величины, и их плюсы и минусы.

1. Тип money, smallmoney

Вот, вроде бы, специальный тип данных для хранения денежных величин. Тип money для хранения больших величин, а smallmoney для величин поменьше. Его бы и нужно использовать. Но не все так просто. Проведем эксперимент:
declare @x money, @y money

select @x=2, @y=3
select @x/@y as r1,
(@x/@y)*@y as r2,
cast(cast(@x as decimal)/@y as money) as r3,

(cast(@x as decimal)/@y)*@y as r4

GO

Результат:
r1    r2     r3    r4

----- ------ ----- --------
.6666 1.9998 .6667 2.000000

(1 row(s) affected)

В колонке r1 получили неправильный результат. Система провела обрезание "хвоста", а не округление, как хотелось бы. Скажем так - в России не принято так работать с деньгами.
В колонке r2 получился результат, который и следовало ожидать.
В колонке r3 правильный результат.
В колонке r4 тоже правильный результат. Почему? Потому что при проведении вычислений с деньгами, например, при вычислении сложных процентов за определенный промежуток времени, округляют данные в самом конце вычислений.
Стало быть, перед проведением сложных вычислений необходимо приводить тип money к другому типу, который не обрезает значимые знаки. Например, к decimal.

Второй недостаток сразу навалится тяжким бременем, если Вам необходимы только 2 знака после запятой. Хотя это решается очень просто с помощью декларирования пользовательского типа (user defined data type) с ограничением (Rule). Например:
create rule [CheckCent] as ROUND(@Cent,2)=@Cent


Третий недостаток - в полях с типом данных money не получится сохранить ОЧЕНЬ большие суммы. В полях с типом данных decimal можно сохранить бОльшие значения. Но в некоторых случаях это тоже разрешимо. Например, в мультивалютных системах, где особенно часто появляются большие суммы, обычно используется множитель курса валют значительно больше или значительно меньше единицы.

Четвертый недостаток, а точнее особенность. Тип money не производит автоматического преобразования строковых величин так, как это делают другие числовые типы. Например, попробуйте выполнить следующий код:
declare @d decimal(18,4), @f float, @i int

select @d='123.45', @f='123.45', @i='123'
select @d, @f, @i
GO

-- ошибка преобразования
declare @m money
select @m='123.45'
GO

Результат:


-------- ------ -----------
123.4500 123.45 123

(1 row(s) affected)

Server: Msg 257, Level 16, State 3, Line 4
Implicit conversion from data type varchar to money is not allowed.
Use the CONVERT function to run this query.


2. Тип decimal

Что-то тип money имеет слишком много недостатков. Значит лучше использовать тип decimal? Давайте проверим. Проведем эксперимент:
declare @x decimal(18,4), @y decimal(18,4)

select @x=2, @y=3
select @x/@y as r1,
(@x/@y)*@y as r2,
cast(@x/@y as decimal(18,4)) as r3,
cast(@x/@y as decimal(18,4))*@y as r4
GO

Результат:
r1                    r2       r3    r4

--------------------- -------- ----- ----------
.66666666666666666666 2.000000 .6667 2.00010000

(1 row(s) affected)

В колонке r1 получился результат, совершенно не похожий на денежный. Но это не страшно. Надо просто округлить. Если присвоить это значение обратно типу decimal(18,4), то округление будет выполнено автоматически. Но при передаче этого результата сразу на клиентскую часть, число будет передано со всеми знаками после запятой.
В колонке r2 очень хороший результат - не то, что у money.
В колонке r3 тоже правильный результат. Приведение к типу decimal работает как округление.
При вычислении колонки r4 мы тоже привели значение к типу decimal. И что получилось? Все правильно получилось.
Получается, что при работе с decimal нет необходимости перед вычислением приводить данные к другому типу. Но в конце вычислений результат желательно привести к нужному типу данных. Чтобы случайно не получить лишние знаки.

Второе. Для хранения величин, сопоставимых с величинами, хранимыми в типе money, используется 9 байт. Тип money использует всего 8 байт.

И третье. Кроме серверной части почти всегда существует клиентская часть, которая получает данные с сервера и работает с ними. Так вот. Некоторые клиентские части воспринимают тип decimal как тип float. А это знаете ли очень нехорошо. Вы не собираетесь контактировать с такими клиентами ни сейчас, ни в будущем? Тогда все в порядке.

3. Тип numeric

Ничем не отличается от decimal. Я ранее видел информацию, что OLE DB, имеет для них разные типы представления. Подтвердить это не могу. А "Books Online" это только опровергает в указателе "OLE DB, data types".

4. Типы float и real

Тип float для хранения денежных величин совершенно не подходит. На эту тему можно долго говорить. Я же приведу всего один пример:
create table #temp (f float)


insert #temp values(45678.2300)
insert #temp values(45678.2400)

select * from #temp
GO

Результат:
f

------------------
45678.230000000003
45678.239999999998

(2 row(s) affected)

А тип real то же самое, что и float(24).
Не используйте эти типы для работы с денежными величинами!

5. Тип int

Некоторые банковские системы используют для хранения денежных величин именно этот тип. В основном это старые банковские системы. При этом хранятся суммы не в рублях и копейках, а в копейках или сотых копейки. Работать с таким денежным видом несколько неудобно. При каждом выводе результата его необходимо будет приводить к нужному типу данных, и делить на 100 или 1000.
Надеюсь, Вы нашли эту информацию полезной. Вопросы, предложения и пожелания шлите на адрес sql@likor.ru
С уважением, Сергей Кошкин.
Адрес сайта Рассылки - http://sql.boom.ru/

Архив на Subscribe.Ru
Поиск по архиву рассылки
"Вопросы и ответы по MS SQL Server"



Рейтинг@Mail.ru Rambler's Top100

http://subscribe.ru/
E-mail: ask@subscribe.ru
Отписаться
Убрать рекламу

В избранное