Чи є взагалі якась різниця між NUMERIC і DECIMAL?


47

Я знаю, що типи даних NUMERIC і DECIMAL у SQL Server працюють однаково: синтаксис для їх створення однаковий, діапазони значень, які ви можете зберігати в них, однакові тощо.

Однак документація MSDN описує відносини між ними так:

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

Зазвичай, коли я бачу класифікатор " функціонально еквівалентним", це означає, що дві речі не зовсім однакові, але це два різних типи, які не відрізняються ззовні .

Чи правда ця наслідка? Чи є відмінності між NUMERIC і DECIMAL, які просто так поводяться з зовнішнім спостерігачем? Або вони насправді еквівалентні, наприклад, NUMERIC є лише успадкованим синонімом DECIMAL?


1
Можливо, ви знайдете відмінності в підтримці поза SQL Server, наприклад, мені щойно стало відомо про цю дивну різницю в SSIS .
Аарон Бертран

Відповіді:


56

Вони насправді еквівалентні, але вони є незалежними типами, а не технічно синонімами, як, ROWVERSIONі, TIMESTAMPхоча вони, можливо, в документації їх називали свого часу . Це дещо інше значення синоніму (наприклад, вони не відрізняються за винятком назви, не один є псевдонімом для іншого). Іронічно, правда?

Те, що я трактую з формулювання в MSDN, насправді:

Ці типи однакові, вони просто мають різні назви.

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

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

Я абсолютно не знаю жодних поведінкових відмінностей між ними, і повертаючись до SQL Server 6.5, завжди вважав їх 100-відсотковими взаємозамінними.

для DECIMAL (18,2) та NUMERIC (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
Дякую. Це відмінна відповідь на наступне питання, чому існує два типи з різними назвами, але однаковою поведінкою.
Гейб
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.