SQL Server decimal 和 numeric 区别

本文详细对比了SQL Server中decimal和numeric两种数据类型的异同,并通过具体示例验证了它们在精度、小数位数及类型转换上的表现。

最近看到了decimal 和 numeric ,又记不起来区别是什么,还是总结一下。


decimal 和 numeric 在 SQL 标准中可以说是等价的的,在SQL Server 中是一样的(参考:decimal 和 numeric (Transact-SQL)),可以查看类型定义确认:

SELECT * FROM sys.types WHERE name IN('DECIMAL','NUMERIC')
SELECT * FROM sys.systypes WHERE name IN('DECIMAL','NUMERIC')

到底有什么不一样呢?有人在 SQL-92 标准中找出了微妙的描述。

in the SQL-92 standard, decimalisexactly as precise as declared, whilenumericisat least as precise as declared. In SQL Server both are exactly as precise as declared


decimal 完全和声明的一样精确;numeric  至少和声明的一样精确。在 sql server 中两者使用完全和声明的一样精确。但是没有例子,很难明白。事实上,不仅sql server 有这两个类型,其他满足 sql 标准的数据库都有。


SQL2003 标准中对两者的描述:

21) NUMERIC specifies the data type
    exact numeric, with the decimal
    precision and scale specified by the
    <precision> and <scale>.

22) DECIMAL specifies the data type
    exact numeric, with the decimal scale
    specified by the <scale> and the
    implementation-defined decimal
    precision equal to or greater than the
    value of the specified <precision>.

这段描述比较清楚了,小数类型的定义格式为(P,S),即固定精度和小数位数;numeric  要求固定精度和小数位一样精确,小数位固定长度;而 decimal 不一定,可能会大于或等于固定精度P的长度,即小数位的长度在存储的时候比实际的长,只是我们看不到罢了。。


没有例子,描述确实看不懂。上面是 SQL 标准的描述,在 SQL Server 当然也不一样。


但不管怎样,在 SQL Server 中,两者类型(名称)不同,但可以说是一样的,用哪个都行!


示例测试:

--	DROP TABLE [dbo].[TypeTest]
CREATE TABLE [dbo].[TypeTest](
	[DecType] [decimal](18, 8) NOT NULL,
	[NumType] [numeric](18, 8) NOT NULL
) ON [PRIMARY]
GO

现在查看测试:

DECLARE @DecType DECIMAL(18,8)
SET @DecType = 3.1415926
SELECT * FROM TypeTest WHERE DecType=@DecType
SELECT * FROM TypeTest WHERE NumType=@DecType
GO
DECLARE @NumType NUMERIC(18,8)
SET @NumType = 3.1415926
SELECT * FROM TypeTest WHERE DecType=@NumType
SELECT * FROM TypeTest WHERE NumType=@NumType
GO


可以看到,两者传递的类型虽然不一样,但是并没有在内部进行转换,此时传递的参数将 decimal 和 numeric 当做相同的。


现在直接赋值查询:

SELECT * FROM TypeTest WHERE DecType=3.1415926
SELECT * FROM TypeTest WHERE NumType=3.1415926


可以看到,decimal 类型的没有隐式转换,而 numeric  则进行了类型转换。也就是说传递的 “3.1415926” 既不不是 decimal 类型,也不是 numeric  类型?因为以下的查询是没有隐式转换的。

SELECT * FROM TypeTest WHERE DecType=CONVERT(DECIMAL(20,10),3.1415926)
SELECT * FROM TypeTest WHERE DecType=CONVERT(NUMERIC(20,10),3.1415926)
SELECT * FROM TypeTest WHERE NumType=CONVERT(DECIMAL(20,10),3.1415926)
SELECT * FROM TypeTest WHERE NumType=CONVERT(NUMERIC(20,10),3.1415926)

“3.1415926”  到底是什么类型??

查看该数值类型:

SELECT SQL_VARIANT_PROPERTY(3.1415926,'BaseType') AS [BaseType]
,SQL_VARIANT_PROPERTY(3.1415926,'Precision') AS [Precision]
,SQL_VARIANT_PROPERTY(3.1415926,'Scale') AS [Scale]

--------------------------------------------|

BaseType      Precision   Scale    |

----------          -------------  -----------|
numeric         8                7           |

------------------------------------------  |

可以看到,“3.1415926”  类型确实为 numeric,怎么一个需要隐式转换,一个不需要呢??当显如下sql式转换后查询,发现确实有隐式转换!

SELECT * FROM TypeTest WHERE DecType=CONVERT(NUMERIC(8,7),3.1415926)
SELECT * FROM TypeTest WHERE NumType=CONVERT(NUMERIC(8,7),3.1415926)


【渐渐地,越来越接近真相了…………】


现在转换成与精度一样的类型:

SELECT * FROM TypeTest WHERE DecType=CONVERT(NUMERIC(18,7),3.1415926)
SELECT * FROM TypeTest WHERE NumType=CONVERT(NUMERIC(18,7),3.1415926)


当固定精度为 18 时,没有发现需要隐式转换,即使小数位长度不一样。现在换成固定精度与字段定义的不一样看看。

SELECT * FROM TypeTest WHERE DecType=CONVERT(NUMERIC(17,7),3.1415926)
SELECT * FROM TypeTest WHERE NumType=CONVERT(NUMERIC(17,7),3.1415926)


好了,出现隐式转换了!!字段DecType类型(decimal )还是一样没什么影响,而 字段 NumTypel类型(numeric)出现了隐式转换!所以确定,类型 numeric 要求的固定精度大于等于声明的精度!


=====================================

接下来任意测试:

=====================================

故意设置较短的精度,可以看到数值 “321.1415926” 类型为 numeric。即传递的带小数位的数值,默认类型为numeric。

DECLARE @DecType DECIMAL(5,3)
SET @DecType = 321.1415926
GO
DECLARE @NumType NUMERIC(5,3)
SET @NumType = 321.1415926
GO
消息 8115,级别 16,状态 8,第 21 行
将 numeric 转换为数据类型 numeric 时出现算术溢出错误。
消息 8115,级别 16,状态 8,第 24 行
将 numeric 转换为数据类型 numeric 时出现算术溢出错误。


=====================================

将数据类型 decimal 和 numeric 都加上一个小数(如:3.14),发现 decimal  加上任意小时后,类型转变为 numeric 。

DECLARE @DecType DECIMAL(18,8)
DECLARE @NumType NUMERIC(18,8)
SET @DecType = 3.1415926
SET @NumType = 3.1415926

SELECT SQL_VARIANT_PROPERTY(@DecType+3.14,'BaseType') AS [BaseType]
	,SQL_VARIANT_PROPERTY(@DecType+3.14,'Precision') AS [Precision]
	,SQL_VARIANT_PROPERTY(@DecType+3.14,'Scale') AS [Scale]

SELECT SQL_VARIANT_PROPERTY(@NumType+3.14,'BaseType') AS [BaseType]
	,SQL_VARIANT_PROPERTY(@NumType+3.14,'Precision') AS [Precision]
	,SQL_VARIANT_PROPERTY(@NumType+3.14,'Scale') AS [Scale]


=====================================

对表创建外键,主外键类型不一样。可确定,decimal 和 numeric 类型是不一样的(本来就不一样,名字都不一样,哈哈!)

ALTER TABLE [TypeTest] ADD CONSTRAINT PK_TypeTest PRIMARY KEY([DecType]) 
GO
ALTER TABLE [TypeTest] ADD CONSTRAINT FK_TypeTest FOREIGN KEY([NumType]) REFERENCES [TypeTest]([DecType]) 
GO
消息 1778,级别 16,状态 0,第 13 行
列 'TypeTest.DecType' 的数据类型与外键 'FK_TypeTest' 中的引用列 'TypeTest.NumType' 的数据类型不同。
消息 1750,级别 16,状态 0,第 13 行
无法创建约束或索引。请参阅前面的错误。



最后总结:

数据类型 decimal 和 numeric 虽然在小数存储方面都一样,但建议使用Decimal(原因参考文章红色标注)



相关探讨:

SQLServer 唯一键约束和唯一索引有什么区别?

SQLServer 可变字符怎么设置长度?(如varchar)

<think>好的,我现在需要回答用户关于SQL Servernumericdecimal数据类型的区别及用法的问题。首先,我需要回顾已有的引用资料,看看这些资料里提供了哪些信息。 根据引用[1][3],在SQL Server中,decimalnumeric是功能上等价的,甚至可以互换使用。这意味着它们具有相同的存储方式精度控制。而引用[2]提到,虽然它们被视为不同的数据类型,但在实际使用中并没有实际区别。此外,引用[2]还指出,对于存储过程中的变量,推荐使用float或real而不是decimal,这可能是因为性能或存储方面的考虑。 接下来,我需要整理这些信息,确保准确无误。首先明确decimalnumeric在功能上是相同的,可以互换。然后,它们的定义方式都是decimal(p, s)或numeric(p, s),其中p是总位数,s是小数位数。同时,它们都用于精确存储数值,与floatreal不同,后者是近似存储。 需要注意的是,尽管它们是等价的,但在某些文档或历史原因中可能有不同的名称,但实际使用时没有区别。此外,引用[2]中提到SQL Server将不同精度小数位数的组合视为不同的数据类型,这可能会影响存储过程中的变量定义,但用户的问题主要关注的是类型本身的区别,所以这可能是一个额外的注意事项,但并非核心区别。 然后,关于用法,用户可能想知道何时选择其中一个。根据资料,实际上没有选择的需要,因为它们是一样的。但可能需要考虑与其他数据库系统的兼容性,比如其他数据库中可能只有decimal而没有numeric,这时使用decimal可能更通用。 最后,确保回答结构清晰,分点说明区别用法,并给出示例。同时,生成相关问题,帮助用户进一步了解。</think>### SQL Servernumericdecimal数据类型对比 #### 一、核心区别 1. **功能等价性** SQL Server中$decimal$$numeric$数据类型**完全等价**,两者均用于存储精确数值,在精度定义、存储方式使用场景上无差异[^1][^3]。例如: ```sql DECLARE @a DECIMAL(10,2) = 1234.56 DECLARE @b NUMERIC(10,2) = 7890.12 ``` 2. **类型名称历史背景** 二者名称差异源于SQL标准的历史演进,但微软官方明确指出它们在SQL Server中具有相同实现[^3]。 #### 二、共同特性 1. **精确数值存储** 与$float$/$real$的近似存储不同,这两个类型能准确存储$p$位有效数字(最大支持$p=38$),例如: ```sql CREATE TABLE Account ( Balance DECIMAL(15,2), --精确到分 TaxRate NUMERIC(5,4) --精确到万分位 ) ``` 2. **定义格式** 统一使用$DECIMAL(p,s)$或$NUMERIC(p,s)$格式定义,其中: - $p$(精度):总位数(1-38) - $s$(小数位数):小数点后位数(必须≤$p$) 3. **存储空间计算** | 精度范围(p) | 存储字节 | |-------------|----------| | 1-9 | 5 | | 10-19 | 9 | | 20-28 | 13 | | 29-38 | 17 | #### 三、使用建议 1. **优先选择$decimal$** 因$decimal$更符合通用SQL标准,例如MySQL、PostgreSQL等数据库仅支持$decimal$[^3]。 2. **存储过程变量限制** 在T-SQL存储过程中定义变量时,需显式指定精度: ```sql DECLARE @temp NUMERIC(18,6) --必须声明精度 ``` 而$float$类型变量则无需指定精度[^2]。 3. **精确计算场景** 财务金额、税率计算等必须避免舍入误差时优先使用,例如: ```sql SELECT (UnitPrice * Quantity) AS Total FROM Orders --单价数量应定义为decimal ``` #### 四、对比近似类型 | 类型 | 存储方式 | 适用场景 | 示例值 | |-----------|----------|------------------|-----------------| | decimal | 精确 | 财务数据 | 123456.78 | | float | 近似 | 科学计算 | 1.2345678e+5 | | real | 近似 | 工程测量 | 12345.67 |
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值