Должны ли вы выбирать типы данных MONEY или DECIMAL (x, y) в SQL Server?

Мне любопытно, существует ли реальная разница между типом данных money и чем-то вроде decimal(19,4) (что, как я полагаю, использует внутренние средства).

Я знаю, что money специфичны для SQL Server. Я хочу знать, есть ли веские причины выбирать один за другим; большинство образцов SQL Server (например, база данных AdventureWorks) используют money а не decimal для таких вещей, как информация о ценах.

Должен ли я просто продолжать использовать тип данных денег, или есть ли преимущество использования десятичного числа? Денег меньше символов для ввода, но это не допустимая причина :)

Ответ 1

Никогда не следует использовать деньги. Это не точно, и это чистый мусор; всегда используйте десятичную/цифровую.

Запустите это, чтобы понять, что я имею в виду:

DECLARE
    @mon1 MONEY,
    @mon2 MONEY,
    @mon3 MONEY,
    @mon4 MONEY,
    @num1 DECIMAL(19,4),
    @num2 DECIMAL(19,4),
    @num3 DECIMAL(19,4),
    @num4 DECIMAL(19,4)

    SELECT
    @mon1 = 100, @mon2 = 339, @mon3 = 10000,
    @num1 = 100, @num2 = 339, @num3 = 10000

    SET @mon4 = @mon1/@mon2*@mon3
    SET @num4 = @num1/@num2*@num3

    SELECT @mon4 AS moneyresult,
    @num4 AS numericresult

Выход: 2949,0000 2949,8525

Некоторым из людей, которые говорили, что вы не делите деньги на деньги:

Вот один из моих запросов для расчета корреляций, и изменение этого на деньги дает неправильные результаты.

select t1.index_id,t2.index_id,(avg(t1.monret*t2.monret)
    -(avg(t1.monret) * avg(t2.monret)))
            /((sqrt(avg(square(t1.monret)) - square(avg(t1.monret))))
            *(sqrt(avg(square(t2.monret)) - square(avg(t2.monret))))),
current_timestamp,@MaxDate
            from Table1 t1  join Table1 t2  on t1.Date = traDate
            group by t1.index_id,t2.index_id

Ответ 2

SQLMenace сказал, что деньги неточны. Но вы не размножаете/делим деньги деньгами! Сколько стоит 3 доллара 50 центов? 150 долларов? Вы умножаете/делите деньги на скаляры, которые должны быть десятичными.

DECLARE
@mon1 MONEY,
@mon4 MONEY,
@num1 DECIMAL(19,4),
@num2 DECIMAL(19,4),
@num3 DECIMAL(19,4),
@num4 DECIMAL(19,4)

SELECT
@mon1 = 100,
@num1 = 100, @num2 = 339, @num3 = 10000

SET @mon4 = @mon1/@num2*@num3
SET @num4 = @num1/@num2*@num3

SELECT @mon4 AS moneyresult,
@num4 AS numericresult

Результаты с правильным результатом:

moneyresult           numericresult
--------------------- ---------------------------------------
2949.8525             2949.8525

money хорош, если вам не нужно больше 4 десятичных цифр, и вы убедитесь, что ваши скаляры, которые не представляют собой деньги, - это decimal s.

Ответ 3

Все опасно, если вы не знаете, что делаете

Даже высокоточные десятичные типы не могут сохранить день:

declare @num1 numeric(38,22)
declare @num2 numeric(38,22)
set @num1 = .0000006
set @num2 = 1.0
select @num1 * @num2 * 1000000

1.000000 - должно быть 0,6000000


Типы money представляют собой целые числа

Текстовые представления smallmoney и decimal(10,4) могут выглядеть одинаково, но это не делает их взаимозаменяемыми. Вы сжимаете, когда видите даты, хранящиеся как varchar(10)? Это то же самое.

За кулисами money/smallmoney - это всего лишь bigint/int Десятичная точка в текстовом представлении money является визуальным пухом, точно так же, как тире в yyyy-mm-dd Дата. SQL фактически не сохраняет их внутри.

Относительно decimal vs money выберите все, что подходит для ваших нужд. Типы money существуют, потому что хранение учетных значений как целочисленных кратных 1/10000-й единицы очень распространено. Кроме того, если вы имеете дело с фактическими деньгами и расчетами, помимо простого сложения и вычитания, вы не должны делать это на уровне базы данных! Сделайте это на уровне приложения с помощью библиотеки, поддерживающей Округление Banker (IEEE 754)

Ответ 4

Я понимаю, что WayneM заявила, что знает, что деньги специфичны для SQL Server. Тем не менее, он спрашивает, есть ли какие-либо причины использовать деньги за десятичные или наоборот, и я думаю, что одна очевидная причина все еще должна быть указана, и что использование десятичного означает, что нужно меньше беспокоиться о том, что вам когда-либо придется менять свою СУБД - что может случиться.

Сделайте ваши системы максимально гибкими!

Ответ 5

Ну, мне нравится MONEY! Это байт дешевле, чем DECIMAL, и вычисления выполняются быстрее, потому что (под обложками) операции сложения и вычитания являются по существу целыми операциями. @SQLMenace example &mdash, который является отличным предупреждением для не знающего &mdash, может быть одинаково применим к INT egers, где результат будет равен нулю. Но это не значит, что вы не должны использовать целые числа &mdash, где это необходимо.

Итак, он отлично "безопасен" и подходит для использования MONEY, когда вы имеете дело с MONEY и используете его в соответствии с математическими правилами, которые он следует (такими же, как INT eger).

Было бы лучше, если бы SQL Server способствовал разделению и умножению MONEY на DECIMAL (или FLOAT s?) — возможно, но они не решили это сделать; и они не решили продвигать INT egers до FLOAT при их делении.

MONEY не имеет точности; что DECIMAL получить более крупный промежуточный тип, используемый во время вычислений, - это просто "функция" использования этого типа (и я не уверен, насколько далеко продвинулась эта функция).

Чтобы ответить на конкретный вопрос, "убедительная причина"? Ну, если вы хотите абсолютную максимальную производительность в SUM(x), где x может быть либо DECIMAL, либо MONEY, тогда MONEY будет иметь ребро.

Кроме того, не забывайте, что это меньший кузен, SMALLMONEY — всего 4 байта, но он максимальный в 214,748.3647 - который довольно мал для денег — и поэтому не всегда хорошо подходит.

Чтобы доказать точку вокруг использования более крупных промежуточных типов, если вы явно назначаете промежуточную переменную, DECIMAL испытывает такую ​​же проблему:

declare @a decimal(19,4)
declare @b decimal(19,4)
declare @c decimal(19,4)
declare @d decimal(19,4)

select @a = 100, @b = 339, @c = 10000

set @d = @a/@b

set @d = @d*@c

select @d

Производит 2950.0000 (хорошо, поэтому не менее DECIMAL округлено, а не MONEY усечено — то же самое, что и целое число.)

Ответ 6

В качестве противопоказания общей направленности других ответов. См. "Много преимуществ денег... Тип данных! в Руководство SQLCAT для реляционного движка

В частности, я хотел бы указать следующее

Работая над реализацией клиента, мы обнаружили несколько интересных которые относятся к типу денежных данных. Например, когда Служба Analysis Services была настроена на тип данных валюты (от двойного) до соответствуют типу данных данных SQL Server, было улучшено 13% скорость обработки (строки/сек). Чтобы получить более высокую производительность в SQL Службы интеграции с сервером (SSIS) загружают 1,18 ТБ менее чем за тридцать минут, как отмечено в SSIS 2008 - мировой рекорд ETL, это было заметил, что изменение четырех десятичных (9,2) столбцов с размером 5 байтов в таблице TPC-H LINEITEM на деньги (8 байт) улучшена объемная скорость вставки на 20%... Причина повышения производительности связана с протоколом табличного потока данных SQL Server (TDS), который имеет ключевой принцип проектирования для передачи данных в компактной двоичной форме и как можно ближе к внутреннему хранилищу формат SQL Server. Эмпирически это наблюдалось во время SSIS 2008 - мировой рекорд производительности ETL с использованием Kernrate; протокол значительно снизился, когда тип данных был переключен на деньги с десятичной точки. Это делает передача данных как можно более эффективной. Для сложного типа данных требуется дополнительный синтаксический анализ и циклы CPU для обработки, чем тип фиксированной ширины.

Итак, ответ на вопрос "это зависит". Вам нужно быть более осторожным с определенными арифметическими операциями, чтобы сохранить точность, но вы можете обнаружить, что соображения производительности делают это стоящим.

Ответ 7

Мы столкнулись с очень похожими проблемами, и теперь я очень люблю +1, чтобы никогда не использовать деньги, кроме презентации на высшем уровне. У нас есть несколько таблиц (фактически ваучер на продажу и счет-фактура), каждый из которых содержит по одному или нескольким денежным полям по историческим причинам, и нам нужно выполнить пропорциональный расчет, чтобы определить, какая часть общего налога на накладную имеет отношение к каждому лайн на ваучере продажи. Наш расчет

vat proportion = total invoice vat x (voucher line value / total invoice value)

Это приводит к расчету реальных денег/денег, который вызывает ошибки шкалы в части деления, которая затем умножается на некорректную пропорцию вата. Когда эти значения впоследствии добавляются, мы получаем сумму пропорций вата, которые не суммируются с общей стоимостью счета. Если бы одно из значений в скобках было десятичным (я собираюсь бросить один из них как таковой), пропорция vat будет правильной.

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

Ответ 8

Я хочу дать другое представление о MONEY vs. NUMERICAL, в значительной степени основанный на моем собственном опыте и опыте... Моя точка зрения здесь - ДЕНЬГИ, потому что я работал с ней в течение долгого времени и никогда не использовал ЧИСЛЕННЫЙ много..,

MONEY Pro:

  • Собственный тип данных. Он использует собственный тип данных (целочисленный) как тот же, что и регистр CPU (32 или 64 бит), поэтому для вычисления не нужны лишние накладные расходы, поэтому он меньше и быстрее... Денежные средства нуждаются в 8 байтах и NUMERICAL (19, 4 ) требует 9 байтов (на 12,5% больше)...

    ДЕНЬГИ быстрее, пока она используется для того, чтобы она была (как деньги). Как быстро? Мой простой тест SUM на 1 миллион данных показывает, что MONEY составляет 275 мс, а NUMERIC 517 мс... Это почти в два раза быстрее... Почему тест SUM? См. Следующий пункт Pro

  • Лучше всего для денег. ДЕНЬГИ лучше всего хранить деньги и делать операции, например, в сфере бухгалтерского учета. Один отчет может запускать миллионы дополнений (SUM) и несколько умножений после выполнения операции SUM. Для очень больших учетных приложений это почти в два раза быстрее, и это чрезвычайно важно...
  • Низкая точность денег. Деньги в реальной жизни не обязательно должны быть очень точными. Я имею в виду, что многие люди могут заботиться о 1 центах, но как насчет 0,01% доллара США? Фактически, в моей стране банки больше не заботятся о центах (цифра после десятичной запятой); Я не знаю об американском банке или другой стране...

MONEY Con:

  • Ограниченная точность. ДЕНЬГИ имеет только четыре цифры (после запятой), поэтому ее нужно преобразовать, прежде чем делать операции, такие как деление... Но опять же money не должны быть настолько точными и предназначены для использования как деньги, а не только число...

Но... Большой, но здесь даже ваше приложение связано с реальными деньгами, но не используйте его во многих операциях СУМ, как в бухгалтерии. Если вы используете множество делений и умножений, вместо этого вы не должны использовать ДЕНЬГИ...

Ответ 9

Вы не должны использовать деньги, когда вам нужно делать умножения/деления на значение. Деньги хранятся таким же образом, как и целое число, тогда как десятичное значение сохраняется как десятичная точка и десятичные цифры. Это означает, что в большинстве случаев деньги будут снижать точность, а десятичная - только при преобразовании обратно в исходный масштаб. Деньги - фиксированная точка, поэтому ее масштаб не изменяется во время расчетов. Однако, поскольку это фиксированная точка, когда она печатается как десятичная строка (в отличие от фиксированной позиции в строке 2), значения до шкалы 4 представлены точно. Итак, для сложения и вычитания деньги в порядке.

Десятичное число представлено в базе 10 внутренне, и, следовательно, позиция десятичной точки также основана на базовом значении 10. Который делает его дробную часть точно представлять ее ценность, как деньги. Разница заключается в том, что промежуточные значения десятичного числа могут поддерживать точность до 38 цифр.

С номером с плавающей запятой значение сохраняется в двоичном виде, как если бы оно было целым числом, а позиция десятичной (или двоичной, гем) точки относительно битов, представляющих число. Поскольку это двоичная десятичная точка, базовые 10 чисел теряют точность сразу после десятичной точки. 1/5, или 0.2, не могут быть представлены точно таким образом. Эти деньги не ограничены ни деньгами, ни десятичными знаками.

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

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

По размеру я не вижу достаточной разницы, чтобы изменить свое мнение. Деньги берут 4 - 8 байт, тогда как десятичный может быть 5, 9, 13 и 17. 9 байтов могут охватывать весь диапазон, который может использовать 8 байтов денег. Индексный (сравнение и поиск должны быть сопоставимы).

Ответ 10

Все предыдущие посты приносят действительные баллы, но некоторые не дают точного ответа на вопрос.

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

Вы используете деньги, когда не будете делать сложные вычисления и можете обменять эту точность на другие нужды.

Например, когда вам не нужно делать эти вычисления, и вам нужно импортировать данные из допустимых текстовых строк валюты. Это автоматическое преобразование работает только с типом данных MONEY:

SELECT CONVERT(MONEY, '$1,000.68')

Я знаю, что вы можете сделать свою собственную процедуру импорта. Но иногда вы не хотите воссоздавать процедуру импорта в форматах, специфичных для разных стран.

Другой пример, когда вам не нужно делать эти вычисления (вам нужно просто сохранить значение) и вам нужно сохранить 1 байт (деньги занимают 8 байт, а десятичное число (19,4) - 9 байт). В некоторых приложениях (быстрый процессор, большой объем оперативной памяти, медленный ввод-вывод), например, просто чтение огромного количества данных, это также может быть быстрее.

Ответ 11

Я только что видел эту запись в блоге: Деньги против Десятичного числа в SQL Server.

Что в основном говорит о том, что деньги имеют точность вопроса...

declare @m money
declare @d decimal(9,2)

set @m = 19.34
set @d = 19.34

select (@m/1000)*1000
select (@d/1000)*1000

Для типа money вы получите 19.30 вместо 19.34. Я не уверен, есть ли сценарий приложения, который делит деньги на 1000 частей для расчета, но этот пример действительно обнажает некоторые ограничения.

Ответ 12

Я нашел причину использования десятичной запятой в деньгах в точности.

DECLARE @dOne   DECIMAL(19,4),
        @dThree DECIMAL(19,4),
        @mOne   MONEY,
        @mThree MONEY,
        @fOne   FLOAT,
        @fThree FLOAT

 SELECT @dOne   = 1,
        @dThree = 3,    
        @mOne   = 1,
        @mThree = 3,    
        @fOne   = 1,
        @fThree = 3

 SELECT (@dOne/@dThree)*@dThree AS DecimalResult,
        (@mOne/@mThree)*@mThree AS MoneyResult,
        (@fOne/@fThree)*@fThree AS FloatResult

DecimalResult> 1.000000

MoneyResult> 0,9999

FloatResult> 1

Просто проверь это и прими решение.