5

根據MSDN,REAL值的範圍是 - 3.40E + 38到-1.18E-38,0和1.18E -38到3.40E + 38.但是,我有一個相當我的表中超出這個範圍的數值很少。REAL列保持值超出記錄範圍

下面的查詢返回大量的非常小的值,並沒有非常大的:

SELECT MyColumn , 
     * 
FROM data.MyTable 
WHERE MyColumn <> 0 
     AND (MyColumn < CONVERT(REAL, 1.18E-38) 
       OR MyColumn > CONVERT(REAL, 3.40E+38) 
      ) 
     AND (MyColumn < CONVERT(REAL, -3.40E+38) 
       OR MyColumn > CONVERT(REAL, -1.18E-38) 
      ) 

很容易顯示這些值是如何在表中結束。我不能直接將其插入:

CREATE TABLE a(r REAL NULL); 
GO 
INSERT INTO a(r) VALUES(4.330473E-39); 
GO 
SELECT r FROM a 
GO 
DROP TABLE a; 

---- 
0.0 

但我可以分爲兩列和範圍值的獲取和外:

CREATE TABLE a 
    (
    r1 REAL NULL , 
    r2 REAL NULL , 
    r3 REAL NULL 
) ; 
GO 
INSERT INTO a 
     (r1, r2) 
VALUES (4.330473E-38, 1000) ; 
GO 
UPDATE a 
SET  r3 = r1/r2 ; 
SELECT r1 , 
     r2 , 
     r3 
FROM a 

r1   r2   r3 
------------- ------------- ------------- 
4.330473E-38 1000   4.330433E-41 

所以我想MSDN給出了有效數據的錯誤的範圍,是否正確? 我錯過了什麼嗎?

有人提出這是一個錯誤。

這種行爲的哪一部分正是一個錯誤。是:

  1. 錯誤常量記錄在MSDN和DBCC使用,以及錯誤的門檻,向下取整。
  2. 更新能夠保存錯誤值
+0

似乎是一個錯誤,你有沒有在你最喜歡的地方申請呢?我想你可以添加自己的約束,像'CHECK(r3> 3.40E-38)':-) –

+0

@AaronBertrand我可以肯定地添加一個約束,但我想了解爲什麼SQL Server不像記錄文件那樣工作。 –

+3

dbcc checktable('a')with DATA_PURITY':列「r3」值超出數據類型「real」的範圍。將列更新爲合法值。舉報... –

回答

7

聯機叢書只記錄單精度和雙精度浮點數的正常範圍。 IEEE 754規則還指定比最小的非零正常值更接近於零的浮點數,以不同的方式稱爲denormalized, denormal, and subnormal數字。從最後一個鏈接開始:

非正規數提供了保證浮點數的加法和減法不會下溢;兩個附近的浮點數 總是有一個可表示的非零差異。如果沒有 漸變下溢,即使值不相等,減法a-b也可能會下溢併產生零點數 。這可以反過來導致 除零錯誤,當使用逐漸下溢時不會發生 。

的SQL Server是繼在張貼的例子single-precision floating point計算規則。該錯誤可能是DBCC僅檢查正常的值,並在遇到存儲的非規範值時拋出不正確的錯誤消息。

例生產非標準單精度值:

DECLARE 
    @v1 real = 14e-39, 
    @v2 real = 1e+07; 

-- 1.4013e-045 
SELECT @v1/@v2; 

範例顯示存儲float非標準通過DBCC檢查:

CREATE TABLE dbo.b (v1 float PRIMARY KEY); 
INSERT b VALUES (POWER(2e0, -1075)); 
SELECT v1 FROM b; -- 4.94065645841247E-324 
DBCC CHECKTABLE(b) WITH DATA_PURITY; -- No errors or warnings 
DROP TABLE dbo.b; 
+4

哪部分是bug取決於SQL Server程序員的*意圖*。從文檔(和'DBCC CHECKDB')看來,*意圖*僅存儲標準化數字。 –

+2

@Damien_The_Unbeliever也許,但如果這是*意圖*然後是不是奇怪,「CHECKDB」不反對低於正常的浮點數據? CREATE TABLE b(v1 float); INSERT b VALUES(POWER(2e0,-1075)); SELECT v1 FROM b; DBCC CHECKTABLE(b)WITH DATA_PURITY;'。 –

+0

的確,這證明'DBCC CHECKDB'中存在一個錯誤。根據產品團隊的設計決策,能夠存儲非正態浮點數可能是也可能不是。 +1 – usr

0

這是SQL Server中的一個錯誤。你發佈的最後一個腳本是一個很好的repro。一行添加到它在末尾:

DBCC CHECKDB WITH data_purity 

此失敗:

消息2570,級別16,狀態3,行1頁(1:313),在對象ID 時隙0 357576312,索引ID 0,分區ID 1801439851932155904,分配單元ID 2017612634169999360(類型「行內數據」)。數據類型「real」的列「r3」值不在 範圍內。將列更新爲合法值。

這證明它是一個錯誤。我建議你用Microsoft Connect for SQL Server提交一個bug。

+0

+1,但是:此行爲的哪一部分正是一個錯誤。是它: 1.在MSDN中記錄並在DBCC中使用的錯誤常量以及舍入的錯誤閾值。 2.更新能夠保存錯誤的值 –

+0

@AlexKuznetsov,no。 2是該錯誤:http://www.sqlskills.com/BLOGS/PAUL/post/CHECKDB-From-Every-Angle-How-to-tell-if-data-purity-checks-will-be-run.aspx (「在2005年以前的SQL Server版本中,可以將無效的數據值導入數據庫,這些無效的值可能會導致查詢執行問題,甚至可能導致錯誤的結果,2005年,當導入」洞「被關閉時) 。他們*應該*關閉。這不是官方文檔,但我想團隊會認爲它是一個錯誤。 – usr

+0

謝謝!我將確保未記錄的值不會通過UPDATE/MERGE命令保存。 –