NUMERIC和DECIMAL之间有什么区别吗?


47

我知道SQL Server中的NUMERIC和DECIMAL数据类型是相同的:创建它们的语法是相同的,可以在其中存储的值的范围是相同的,等等。

但是,MSDN文档将两者之间的关系描述如下:

数字在功能上等同于十进制。

通常,当我看到限定词“在功能上等效”时,这意味着这两件事并不完全相同,但是它们是两种不同的类型,它们与外界无法区分

这是真的吗?NUMERIC和DECIMAL之间是否有区别,只是外部观察者的行为相同?还是它们实际上是等效的,例如NUMERIC只是DECIMAL的传统同义词吗?


1
您可能会发现SQL Server 外部支持方面的差异,例如,我刚刚意识到SSIS中这种奇怪差异
阿龙贝特朗

Answers:


56

它们实际上是等效的,但它们是独立的类型,在技术上不是同义词,就像ROWVERSIONTIMESTAMP-尽管它们可能在文档中一次被称为同义词。这与同义词的含义稍有不同(例如,除了名称上,它们是无法区分的,没有一个是另一个的别名)。具有讽刺意味,对吗?

我从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 2014年

@MichaelEdenfield更新了我对您的新问题的答案。
阿龙贝特朗

1
我知道这是一个古老的答案,但是我只是发现一种情况,认为数字和十进制是同义词会导致SQL Server引发错误。只是认为我应该在这里发表评论,以防其他人从中受益。
Zohar Peled

@AaronBertrand我赞成您的回答,因为它很有帮助。两种类型看起来都相同,因此,为什么这样命名不同?有历史原因吗?
伊万津尼奥

@Ivanzinho我不确定您的问题是否有说服力,有很多理论(此页面上以及您链接的答案),但是如果您想确定的答案,可能会很不幸。您需要跟踪最初在SQL Server中实现这两种类型的原始工程师,并依赖他们当时对该实现的记忆以及对标准的解释。
亚伦·伯特兰

15

但实际上它们是相同的(根据SQL 2003标准):

21)NUMERIC指定数据类型为精确数值,其小数精度和小数位数由precision和所指定 scale

22)DECIMAL指定数据类型为精确数值,由所指定的十进制小数位数scale实现定义的十进制精度等于或大于指定的值precision


5
当时的基本问题(我相信答案是“否”),SQL Server实现DECIMAL的精度与NUMERIC的精度不同。标准所说的可以做的远不如实际做的重要。
阿龙贝特朗

5
谢谢。对于为什么存在两种名称不同但行为相同的类型的后续问题,这是一个很好的答案。
加布2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.