2013-03-02 59 views
0

在試圖回答這裏的另一個問題我已經創建了下面的數據結構和行:我已經執行以下查詢SQL小數類型 - 精密和規模差異

create table [resource] (Name varchar(16),date datetime, project varchar(16),hours int) 
INSERT INTO resource 
values ('Andy Sandy', '2013-03-02', 'Enhancements',40) 
INSERT INTO resource 
values('Fred Jones', '2013-10-02', 'Enhancements',40) 

select 
case when sum(hours) > 0 Then 
    CAST(SUM(hours) as DECIMAL(5,2))/40 
else 0 end as [hours], 
[DATE] 
from resource group by date 

結果是這樣的:

Hours   Date 
1.000000 2013-03-02 00:00:00.000 
1.750000 2013-10-02 00:00:00.000 

當我將小時鑄造成小數時,我指定了一個精度5的離子和2的比例。我不明白爲什麼這個數字是這樣的。如果我沒有指定精度和縮放比例,那麼結果是一樣的。爲什麼是這樣?

+0

我得到這個與你提供的數據:DATE小時 - ------------------------------------- ------------- ---------- 1.000000 2013-03-02 00:00:00.000 1.000000 2013-10-02 00:00:00.000 – 2013-03-02 19:22:22

+0

除法的結果是'numeric(9,6)'。將40當作'numeric(2,0)',然後將精度和比例插入[BOL中的公式](http://msdn.microsoft.com/zh-cn/library/ms190476%28v=SQL.90% 29.aspx) – 2013-03-02 19:22:31

+0

$&%^%愚蠢的規則意味着我不能通過發佈不適當的答案來合理地設置此格式,而不會丟失代表。 – 2013-03-02 19:22:59

回答

3

你正在做numeric(5,2)/40

Precision, Scale, and Length

+-----------+------------------------------------+---------------------+ 
| Operation |   Result precision   | Result scale * | 
+-----------+------------------------------------+---------------------+ 
| e1/e2 | p1 - s1 + s2 + max(6, s1 + p2 + 1) | max(6, s1 + p2 + 1) | 
+-----------+------------------------------------+---------------------+ 

款待40作爲numeric(2,0),因爲這是保留精度和比例的最小可能的十進制表示。

所以

p1=5 
s1=2, 
p2=2 
s2=0 

然後把它插入公式從BOL

Precision: 5 - 2 + 0 + max(6, 2 + 2 + 1) = 9 
Scale: max(6, 2 + 2 + 1)     = 6 

所以結果是numeric(9,6)

你也可以看到這個從

;WITH cte(thing) AS 
(
SELECT CAST(1 as DECIMAL(5,2))/40 
) 
SELECT thing, 
     sql_variant_property(thing,'basetype') AS basetype, 
     sql_variant_property(thing,'precision') AS precision, 
     sql_variant_property(thing,'scale') AS scale, 
     sql_variant_property(thing,'maxlength') AS maxlength 
FROM cte 

返回

+----------+----------+-----------+-------+-----------+ 
| thing | basetype | precision | scale | maxlength | 
+----------+----------+-----------+-------+-----------+ 
| 0.025000 | decimal |   9 |  6 |   5 | 
+----------+----------+-----------+-------+-----------+ 

(注:decimalnumeric是同義詞)

+0

太棒了,我不知道在計算列的精度/比例計算後面有實際的數學計算。偉大的鏈接! – 2013-03-02 19:37:34

+0

@KyleHale - [這個比BOL更詳細](http://blogs.msdn.com/b/sqlprogrammability/archive/2006/03/29/564110.aspx) – 2013-03-02 19:46:41

+0

謝謝。鏈接爲+1。 – w0051977 2013-03-02 19:55:19

2

多麼奇怪。如果您運行sp_describe_first_result_set

sp_describe_first_result_set N' 
select 
case when sum(hours) > 0 Then 
    CAST(SUM(hours) as DECIMAL(5,2))/40 
else 0 end as [hours], 
[DATE] 
from resource group by date' 

你看,你返回時間列被強制轉換爲十進制(9,6)。

如果您將原始演員改爲DECIMAL(10,6),則會將其重新改寫爲(14,10)。所以你認爲它只是增加了4個級別的十進制精度。不完全的!

將您的分頻器從40.0改爲400.0 - 現在它轉換爲(15,11) - 它還根據分頻器的精度增加了一個額外的精度級別。

改爲40.0000(3個零) - 現在是(20,15)。所以有一個函數可以根據原始值和除數來確定精度。

小數點右邊的每個額外精度等級都會將(2,1)加到原始演員表上。 左側的每個精度級別都會將(1,1)添加到您的原始演員陣列中。

要返回的時間列,小數(5,2),你只需要做

select 
case when sum(hours) > 0 Then 
    CAST(SUM(hours) /40.0 as decimal(5,2)) 
else 0 end as [hours], 
[DATE] 
from resource group by date 
+0

謝謝,這確實工作+1。我早些時候嘗試了下面的CAST,但是這不起作用:CAST(SUM(小時)/ 40作爲十進制(5,2))。爲什麼改變40到40.0會有所作爲? – w0051977 2013-03-02 19:30:00

+0

什麼是:sp_describe_first_result_set N'? – w0051977 2013-03-02 19:32:40

+0

@ w0051977:因爲「/」是整數除法,除非它的一個參數強制它進行浮點除法。 – 2013-03-02 19:36:47