Co jest przyczyną tego problemu z CONVERT ()?

12

Rozważ następujące dwa stwierdzenia:

PRINT CONVERT(NUMERIC(38, 0), 0x0100000001, 0);
PRINT CONVERT(NUMERIC(38, 0), 0x0100010001, 0);

Oba wyrażenia powracają -1; czy to nie jest niepoprawne, ponieważ druga wartość binarna jest o 65.536 dziesiętna wyższa od pierwszej wartości, prawda?

Z pewnością nie może to wynikać z cichego obcinania?

Jeśli uruchomię następujące instrukcje:

PRINT CONVERT(NUMERIC(38, 0),   0x00000001, 0);
PRINT CONVERT(NUMERIC(38, 0),   0x00010001, 0);

Pojawia się następujący błąd:

Msg 8114, Level 16, State 5, Line 1
Error converting data type varbinary to numeric.

Jak zdiagnozować, co się tutaj dzieje?

Używam tego na SQL Server 2012, wersja 11.0.5058. Wyniki są takie same dla SQL Server 2008 R2 SP2, SQL Server 2005 i SQL Server 2000.

Max Vernon
źródło
4
Liczby dziesiętne i liczby całkowite są kodowane w różny sposób w języku varbinary. Miejsca dziesiętne wymagają więcej miejsca. SpróbujSELECT CONVERT(VARBINARY(32), 1), CONVERT(VARBINARY(32), 1.0);
Aaron Bertrand
4
Aaron jest na miejscu. Twój mózg konwertuje dane binarne na dane całkowite, a następnie prosto na wartości liczbowe, ale SQL Server nie wykonuje tej niejawnej konwersji z binarnych -> liczb całkowitych -> liczbowych (x, y). Dla SQL Server śledzić proces myślowy, trzeba by zrobić coś takiego: PRINT CONVERT(NUMERIC(38, 0), convert(int, 0x00000001), 0); PRINT CONVERT(NUMERIC(38, 0), convert(int, 0x00010001), 0);.
Thomas Stringer
5
Pierwszy bajt to skala (0x01 = 1), Drugi bajt to precyzja (0x00 = 0), Ostatni bajt to wartość (0x01 = 1). Nie jestem pewien, do czego służą bajty trzy i cztery. Znak jest tam, ale nie potrzebuje dwóch bajtów. Z pewnością odwrócenie tego fragmentu nic nie wpłynęło.
Martin Smith
1
Dzięki, @MartinSmith - jak do cholery ustaliłeś, że pierwsze dwa bajty są używane w ten sposób? Czy to jest udokumentowane?
Max Vernon,
3
@AaronBertrand: Czy chciałbyś odpowiedzieć na to pytanie? Możemy zaznaczyć to na liście „bez odpowiedzi”.
Jon of All Trades,

Odpowiedzi:

2

Liczby dziesiętne i liczby całkowite są kodowane w różny sposób w języku varbinary. Miejsca dziesiętne wymagają więcej miejsca. Próbować:

SELECT CONVERT(VARBINARY(32), 1), CONVERT(VARBINARY(32), 1.0);

Jeśli chodzi o twój ostateczny cel, jakim jest przechowywanie liczb całkowitych w postaci liczbowej, aby zaoszczędzić miejsce, myślę, że sam odpowiedziałeś na to pytanie - nie warto.

Aaron Bertrand
źródło