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

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


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


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

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

评论

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

stackoverflow.com/questions/1056323/…

#1 楼

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

我从MSDN中的措辞解释的实际上是:


这些类型是相同的,只是名称不同。


除了type_id值以外,这里的所有内容都是相同的:

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


我完全不了解两者之间的任何行为差异,然后返回SQL服务器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年8月29日在18:27

@MichaelEdenfield更新了我对您的新问题的答案。

–亚伦·伯特兰(Aaron Bertrand)
2014年8月29日在18:56

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

– Zohar Peled
18 Mar 9 '18 at 10:31

@AaronBertrand我赞成您的回答,因为它很有帮助。两种类型看起来都相同,所以如果是这样,为什么它们的名称不同?有历史原因吗?

–伊万津尼奥
19年5月17日在15:47



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

–亚伦·伯特兰(Aaron Bertrand)
19年5月17日在19:10

#2 楼

但实际上它们是相同的(从SQL 2003标准开始):

21)NUMERIC指定数据类型
精确数字,十进制
精度和小数位数由
precisionscale

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

评论


当时的基本问题(我相信答案是“否”),SQL Server实施DECIMAL的精度是否不同于NUMERIC的精度。标准所说的可以做的远不及实际要做的重要。

–亚伦·伯特兰(Aaron Bertrand)
2014年8月29日在18:50



谢谢。对于为什么存在两种名称不同但行为相同的类型的后续问题,这是一个很好的答案。

–加布
2014年8月30日在12:37