Есть ли какая-либо разница между ЦИФРОВЫМ и ДЕСЯТИЧНЫМ?

47

Я знаю, что типы данных NUMERIC и DECIMAL в SQL Server работают одинаково: синтаксис их создания одинаков, диапазоны значений, которые можно хранить в них, одинаковы и т. Д.

Тем не менее, документация MSDN описывает отношения между ними так:

число функционально эквивалентно десятичному.

Обычно, когда я вижу квалификатор « функционально эквивалентный», это означает, что эти две вещи не совсем одинаковы, но это два разных типа, которые неотличимы снаружи .

Это правда? Существуют ли различия между NUMERIC и DECIMAL, которые просто ведут себя одинаково с внешним наблюдателем? Или они фактически эквивалентны, например, является ли NUMERIC просто устаревшим синонимом DECIMAL?

KutuluMike
источник
1
Вы можете найти различия в поддержке вне SQL Server, например, я только что узнал об этой странной разнице в службах SSIS .
Аарон Бертран
stackoverflow.com/questions/1056323/…
Шивангини Шишулкар

Ответы:

56

Они на самом деле эквивалентны, но они являются независимыми типами, а не технически синонимами, такими как ROWVERSIONи TIMESTAMP- хотя их, возможно, упоминали как синонимы в документации когда-то . Это немного другое значение синонима (например, они неразличимы, кроме имени, ни один не является псевдонимом для другого). Иронично, правда?

Что я интерпретирую из формулировки в MSDN на самом деле:

Эти типы идентичны, они просто имеют разные имена.

Кроме type_idзначений, все здесь идентично:

SELECT * FROM sys.types WHERE name IN (N'numeric', N'decimal');

Я абсолютно не знаю никаких поведенческих различий между ними, и, возвращаясь к SQL Server 6.5, всегда рассматривал их как взаимозаменяемые на 100%.

для десятичной (18,2) и числовой (18,2)? Присвоение одного другому технически является «преобразованием»?

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

CREATE TABLE [dbo].[NumDec]
(
    [num] [numeric](18, 0) NULL,
    [dec] [decimal](18, 0) NULL
);

Теперь выполните эти запросы и запишите план:

DECLARE @num NUMERIC(18,0);
DECLARE @dec DECIMAL(18,0);

SELECT 
  CONVERT(DECIMAL(18,0), [num]), -- conversion
  CONVERT(NUMERIC(18,0), [dec])  -- conversion
FROM dbo.NumDec
UNION ALL SELECT [num],[dec] 
  FROM dbo.NumDec WHERE [num] = @dec  -- no conversion
UNION ALL SELECT [num],[dec] 
  FROM dbo.NumDec WHERE [dec] = @num; -- no conversion

Как показано в SQL Sentry Plan Explorer *, план не очень интересен:

введите описание изображения здесь

Но вкладка «Выражения» точно такая:

введите описание изображения здесь

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

Попробуйте этот тест тоже (данные и индексы).

CREATE TABLE [dbo].[NumDec2]
(
    [num] [numeric](18, 2) NULL,
    [dec] [decimal](18, 2) NULL
);

INSERT dbo.NumDec2([num],[dec])
SELECT [object_id] + 0.12, [object_id] + 0.12
  FROM sys.all_columns;

CREATE INDEX [ix_num] ON dbo.NumDec2([num]);
CREATE INDEX [ix_dec] ON dbo.NumDec2([dec]);

Теперь запустите этот запрос:

DECLARE @num NUMERIC(18,2) = -1291334356.88,
        @dec NUMERIC(18,2) = -1291334356.88;

SELECT [dec] FROM dbo.NumDec2 WHERE [dec] = @num
UNION ALL
SELECT [num] FROM dbo.NumDec2 WHERE [num] = @dec;

План не имеет преобразований (фактически вкладка «Выражения» пуста):

введите описание изображения здесь

Даже это не приводит к неожиданным преобразованиям. Конечно, вы видите это в RHS в предикате, но ни в коем случае не нужно было выполнять какое-либо преобразование данных столбца, чтобы облегчить поиск (тем более, принудительное сканирование).

SELECT [dec] FROM dbo.NumDec2 WHERE [dec] = CONVERT(DECIMAL(18,2), @num)
UNION ALL
SELECT [dec] FROM dbo.NumDec2 WHERE [dec] = CONVERT(DECIMAL(18,2), @dec)
UNION ALL
SELECT [num] FROM dbo.NumDec2 WHERE [num] = CONVERT(NUMERIC(18,2), @num)
UNION ALL
SELECT [num] FROM dbo.NumDec2 WHERE [num] = CONVERT(NUMERIC(18,2), @dec)
UNION ALL
SELECT [num] FROM dbo.NumDec2 WHERE [num] = CONVERT(DECIMAL(18,2), @num)
UNION ALL
SELECT [num] FROM dbo.NumDec2 WHERE [num] = CONVERT(DECIMAL(18,2), @dec)
UNION ALL
SELECT [dec] FROM dbo.NumDec2 WHERE [dec] = CONVERT(NUMERIC(18,2), @num)
UNION ALL
SELECT [dec] FROM dbo.NumDec2 WHERE [dec] = CONVERT(NUMERIC(18,2), @dec);

Лично я предпочитаю использовать этот термин DECIMALтолько потому, что он гораздо более точный и описательный. BITтоже "числовой".

* Disclaimer: I work for SQL Sentry.
Аарон Бертран
источник
Я знаю, что SQL обрабатывает, например, DECIMAL (18,2) и DECIMAL (18,0) как «разные типы»; Означает ли это то же самое для DECIMAL (18,2) и NUMERIC (18,2)? Присвоение одного другому технически является «преобразованием»?
KutuluMike
@MichaelEdenfield Обновил мой ответ на ваш новый вопрос.
Аарон Бертран
1
Я знаю, что это старый ответ, но я только что нашел случай, когда мысль о том, что числовые и десятичные числа являются синонимами, вызвала ошибку SQL Server. Просто подумал, что я должен оставить здесь комментарий на случай, если кто-то другой может извлечь из этого пользу.
Зохар Пелед
@AaronBertrand Я проголосовал за ваш ответ, потому что это полезно. Оба типа выглядят одинаково, поэтому, если это так, почему они называются по-разному? есть ли историческая причина ?
Иванзиньо
@Ivanzinho Я не уверен, что ваш вопрос риторический, существует множество теорий (как на этой странице, так и на ответе, который вы указали), но если вы хотите получить точный ответ, вам, вероятно, не повезет. Вам нужно будет отследить оригинальных инженеров, которые сначала внедрили оба типа в SQL Server, и полагаться на их память как этой реализации, так и их интерпретации стандарта в то время.
Аарон Бертран
15

Однако на практике они идентичны (из стандарта SQL 2003):

21) NUMERIC указывает тип данных точный числовой, с десятичной точностью и масштабом, указанными precisionи scale.

22) DECIMAL указывает тип данных точный числовой, с десятичной шкалой, заданной десятичной точностью scaleи определенной реализацией точностью, равной или превышающей значение указанной precision.

Нил Макгиган
источник
5
Тогда основной вопрос (и я считаю, что ответ «нет»): реализовал ли SQL Server точность DECIMAL иначе, чем NUMERIC. То, что в стандарте сказано, что может быть сделано, гораздо менее важно, чем то, что фактически было сделано.
Аарон Бертран
5
Благодарю. Это отличный ответ на дополнительный вопрос о том, почему существует два типа с разными именами, но одинаковым поведением.
Гейб