1. 程式人生 > 實用技巧 >SQL Server 小數型別(float 和 decimal)(轉載)

SQL Server 小數型別(float 和 decimal)(轉載)

在SQL Server中,實際上小數數值只有兩種資料型別:floatdecimal分別是近似數值和精確數值。其他小數型別,都可以使用float和decimal來替代,例如,雙精度(double precision)資料型別等價於 float(53),real等價於float(24),numeric是 decimal的同義詞,應該避免在程式中直接使用 double precision、real和numeric,而是用 float(24) 、float(53)和decimal 代替。

float是近似數值,存在精度缺失;decimal是精確數值,不存在精度損失。當數值不允許精度丟失時,使用 decimal資料型別儲存資料。在計算小數的除法時,SQL Server 內部隱式升級資料型別,根據小數數值的資料型別,就近向float(24) 或float(53)轉換。

一,近似數值

float 表示近似數值,存在精度損失,資料型別是 float(n),n是可選的,預設型別是float(53),佔用8bytes。雖然n的取值範圍是1-53,實際上,float 只能表示兩種型別float(53) 和 float(24),分別佔用 8Bytes 和 4Bytes。

其中n是以科學計數法儲存浮點數尾數的位數,因此決定了精度和儲存大小。 如果指定了n,則它必須是介於1和53之間的值,n的預設值是53。

n

Precision

Storage size

1-24

7 digits

4 bytes

25-53

15 digits

8 bytes

注意:SQL Server將n視為兩個可能值之一。 如果1 <= n <= 24,則將n視為24;如果25 <= n <= 53,則將n視為53。
近似數值很難確定是否相等,因此,應避免對 float 型別做相等比較,而只限於比較 > 或 < 。

二,精確數值

decimal不存在精度損失,資料型別decimal(p,s) 需要分別指定小數的最大位數(p)和小數位的數量(s):

  • p (precision) :指定小數的最大位數,小數點的左側和右側的數字的總數量不能超過p,p的取值範圍是從1到38,預設值為18。
  • s (scale):指定在小數點右側的小數位數,p-s是小數點左邊的最大位數。s必須是從0到p的值,只有在指定了精度的情況下才能指定s,s的預設值是0,因此,0 <= s <= p。

Precision

Storage bytes

1 - 9

5

10-19

9

20-28

13

29-38

17

p 和 s 必須遵守規則:0 <= s <= p <= 38,decimal(p,s) 能夠表示的有效值是從 - 10^38 +1 到 10^38 - 1。

decimal 資料型別的最大精度為 38,這意味著,decimal 資料型別最多可以儲存 38位數字,所有這些數字均可位於小數點後面。decimal 資料型別儲存精確的數字表示形式,沒有近似值。

三,小數的除法是近似計算

小數的除法是近似計算,必須把小數的型別提升為float型別。小數常量的預設資料型別是decimal,float的優先順序比decimal高。

在Transact-SQL語句中,具有小數點的常量會自動轉換為decimal,並使用必需的最小精度和小數位數。 例如,將常量12.345轉換為小數型別,decimal(5,3),即精度為5,小數位為3。

在TSQL中,小數常量是decimal型別,如以下示例,TSQL把常量 1.0 自動轉換為decimal(2,1),在計算除法時,TSQL自動把decimal轉換位float型別。

declare @f_low float(24)
declare @f_high float(53)
select @f_low=cast(1.0 as float(24))/3,@f_high=cast(1.0 as float(53))/3
select 1.0/3 as f,@f_low as f_low, @f_high as f_high

declare @dec decimal(38,37)
declare @num decimal(38,37)

select @dec=cast(1.0 as decimal(38,37))/3,@num=cast(1.0 as decimal(38,37))
select @dec,@num,1.0/3,cast(1.0 as float(24))/3,1.000000000000/3,cast(1.0 as float(53))/3

預設情況下,SQL Server將小數常量作為decimal 資料型別,在計算小數的除法時,就近進行資料型別的升級,轉換為float(24)或float(53) 資料型別。

在 Transact-SQL 語句中,小數數值的常量自動轉換為 decimal 資料型別,在轉換時,使用最小的精度和小數位數。例如,常量 12.345 被轉換為 numeric 值,其精度為 5,小數位為 3。

In Transact-SQL statements, a constant with a decimal point is automatically converted into a numeric data value, using the minimum precision and scale necessary. For example, the constant 12.345 is converted into a numeric value with a precision of 5 and a scale of 3.

四,將小數轉換成字串(varchar)

相比cast(float_expression as float(24/53)),使用 str 函式能夠有效控制近似數值的小數位數,函式str獲取的是近似數值。

STR ( float_expression [ , length [ , decimal ] ] )
  • length是小數的總位數,包含正負符號,小數點,小數點左邊和右邊數字個數之和;
  • decimal是小數位的數量(小數點右邊數字個數),小數位最大為16位,不能超過16,否則,會被截斷為16位。如果小數位沒有decimal多,那麼右邊補0。
  • 返回值是varchar型別。

1,對小數常量轉換為varchar型別,減少小數位的數量,由2位減少為1位。

SELECT STR(123.45, 6, 1);

2,將decimal 變數轉換為varchar型別

declare @d decimal(10,2)
set @d=123.45

SELECT STR(@d, 6, 1);

3,將 float 表示式的值轉換為varchar 型別

1.0/3 預設轉換為float(24) 型別,因此只有6位小數,小於decimal 引數的8位,右邊補兩個0。

SELECT STR(1.0/3, 10, 8);

4,在將float和decimal轉換為varchar型別時,使用函式str或cast強制轉換,返回的數值可能是不相同

declare @dt decimal(38,30)
declare @df float(53)

set @dt=50.8863983154297
set @df=50.8863983154297

select @df as df,@dt as dt,
    str(@dt,38,30) as str_dt,str(@df,38,30) as str_df,
    cast(@dt as varchar(100)) as var_dt,cast(@df as varchar(100)) as var_df

欄位str_dt和str_df的值是不相同的,str函式首先對這兩個小數數值取近似值,使用cast強制轉換,對於decimal,返回的是精確值,對於float,返回的是近似值。

參考文獻:

float and real (Transact-SQL)

decimal and numeric (Transact-SQL)

STR (Transact-SQL)

原文連結