5

Zgodnie z MSDN, zakres rzeczywistych wartości wynosi - 3,40E + 38 do -1.18E - 38, 0 i 1,18E - 38 do 3,40E + 38. Mam jednak dość kilka wartości poza tym zakresem w mojej tabeli.PRAWDZIWE wartości trzymania kolumny poza udokumentowanym zakresem

Następująca kwerenda zwraca wiele bardzo małych wartości i nie bardzo duże te:

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) 
      ) 

Łatwo pokazać, w jaki sposób kończy się w tabeli te wartości. Nie mogę wstawić je bezpośrednio:

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 

Ale mogę podzielić dwie kolumny i dostać a poza zakres wartości:

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 

Więc myślę MSDN daje błędne zakresy prawidłowych danych, prawda? Czy brakuje mi czegoś?

Kilka osób zasugerowało, że jest to błąd.

Którą częścią tego zachowania jest właśnie błąd. jest to:

  1. Wrong stałych udokumentowanych w MSDN i używanych w DBCC, a także nieprawidłowy próg do zaokrąglania w dół.
  2. Aktualizacja jest w stanie zapisać błędne wartości
+0

Wygląda jak błąd, masz złożyła ona w swoim ulubionym miejscu? Sądzę, że można dodać własne ograniczenia, takie jak 'CHECK (r3> 3.40E-38)' :-) –

+0

@AaronBertrand Mogę zdecydowanie dodać ograniczenie, ale chciałbym zrozumieć, dlaczego SQL Server nie zachowuje się jak udokumentowane. –

+3

'dbcc checktable ('a') z DATA_PURITY': Kolumna" r3 "jest poza zakresem dla typu danych" rzeczywisty ". Zaktualizuj kolumnę do wartości prawnej. Zgłoś to ... –

Odpowiedz

7

Książki Online dokumentuje tylko normalny zakres liczb zmiennoprzecinkowych jedno- i podwójnej precyzji. Reguły IEEE 754 również określają liczby zmiennoprzecinkowe bliżej zera niż najmniejsza niezerowa wartość normalna, znana różnie jako liczby denormalized, denormal, and subnormal. Od tego ostatniego łącza:

Denormalne liczby gwarantują, że dodawanie i odejmowanie liczb zmiennoprzecinkowych nigdy nie będzie niedokładne; dwa pobliskie liczby zmiennoprzecinkowe mają zawsze reprezentowalną niezerową różnicę. Bez stopniowego niedomiaru, odejmowanie a-b może być niedopełnione i powodować zerowanie , nawet jeśli wartości nie są równe. Może to z kolei prowadzić do podziału przez zero błędów, które nie mogą wystąpić, gdy stopniowy niedomiar jest użyty .

SQL Server postępuje zgodnie z regułami dla single-precision floating point obliczeń w zamieszczonych przykładach. Błąd może być taki, że DBCC sprawdza tylko wartości normalnej wartości i generuje niepoprawny komunikat o błędzie, gdy napotka zachowaną wartość denormalną.

Przykład wytwarzając Brak reprezentacji wartość pojedynczej precyzji:

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

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

Przykład pokazujący zapisaną float Brak reprezentacji przechodzi kontrole 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

Która część błędu zależy od * zamiaru * programistów SQL Server. Z dokumentacji (i "DBCC CHECKDB") wynika, że ​​intencją * było przechowywanie tylko znormalizowanych liczb. –

+2

@Damien_The_Unbeliever Być może, ale jeśli to było * intencją *, to czy nie jest to ciekawe, że 'CHECKDB' nie sprzeciwia się subormalnym float? 'CREATE TABLE b (v1 float); INSERT b VALUES (POWER (2e0, -1075)); SELECT v1 FROM b; DBCC CHECKTABLE (b) WITH DATA_PURITY; '. –

+0

Rzeczywiście, dowodzi to, że w 'DBCC CHECKDB' występuje błąd. Możliwość przechowywania denormal floats może, ale nie musi, w zależności od decyzji projektowej podjętej przez zespół produktu. +1 – usr

0

Jest to błąd w SQL Server. Ostatni skrypt, który publikujesz, to fajna repro. Dodać jedną linię do niego na końcu:

DBCC CHECKDB WITH data_purity 

ten nie powiedzie się z:

Msg 2570, Level 16, State 3, wiersz 1 stronie (1: 313), gniazdo 0 W Object ID 357576312, indeks ID 0, identyfikator partycji 1801439851932155904, identyfikator jednostki alokacji 2017612634169999360 (wpisz "Dane w wierszu"). Wartość "r3" kolumny jest poza zakresem dla typu danych "rzeczywisty". Zaktualizuj kolumnę do wartości prawnej.

Dowodzi to, że jest to błąd. Proponuję zgłosić błąd z Microsoft Connect for SQL Server.

+0

+1, ale: jaka część tego zachowania jest dokładnie błędem. jest to: 1. Nieprawidłowe stałe udokumentowane w MSDN i używane w DBCC, a także błędny próg zaokrąglania w dół. 2. Aktualizacja jest w stanie zapisać złe wartości –

+0

@AlexKuznetsov, nie. 2 to błąd: http://www.sqlskills.com/BLOGS/PAUL/post/CHECKDB-From-Every-Angle-How-to-tell-if-data-purity-checks-will-be-run.aspx ("W wersjach programu SQL Server sprzed 2005 r. Możliwe było zaimportowanie nieprawidłowych wartości danych do bazy danych, które mogą powodować problemy z wykonywaniem zapytań, a nawet błędne wyniki." W 2005 r., Kiedy zostały zamknięte "importowane" otwory ") . Oni * powinni * być zamknięci. To nie jest oficjalna dokumentacja, ale myślę, że zespół potraktuje to jako błąd. – usr

+0

Dzięki! Upewnię się, że nieudokumentowane wartości nie zostaną zapisane za pomocą polecenia UPDATE/MERGE. –