Was ist die Ursache für dieses Problem mit CONVERT ()?

12

Betrachten Sie die folgenden zwei Aussagen:

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

Beide Anweisungen kehren zurück -1. Ist das nicht falsch, da der zweite Binärwert 65.536 Dezimalstellen höher ist als der erste?

Das kann doch nicht an stillem Abschneiden liegen?

Wenn ich die folgenden Anweisungen ausführen:

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

Mir wird der folgende Fehler angezeigt:

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

Wie kann ich diagnostizieren, was hier passiert?

Ich führe dies unter SQL Server 2012, Version 11.0.5058 aus. Die Ergebnisse sind auf SQL Server 2008 R2 SP2, SQL Server 2005 und SQL Server 2000 identisch.

Max Vernon
quelle
4
Dezimal- und Ganzzahlen werden im Varbinary sehr unterschiedlich codiert. Dezimalstellen benötigen mehr Platz. TrySELECT CONVERT(VARBINARY(32), 1), CONVERT(VARBINARY(32), 1.0);
Aaron Bertrand
4
Aaron ist genau richtig. Ihr Gehirn konvertiert die binären Daten in ganzzahlige Daten und dann direkt in numerische Daten, aber SQL Server führt diese implizite Konvertierung von binär -> ganzzahlig -> numerisch (x, y) nicht durch. Für SQL Server Ihres Denkprozess zu folgen, würden Sie so etwas zu tun haben: PRINT CONVERT(NUMERIC(38, 0), convert(int, 0x00000001), 0); PRINT CONVERT(NUMERIC(38, 0), convert(int, 0x00010001), 0);.
Thomas Stringer
5
Das erste Byte ist scale (0x01 = 1), das zweite Byte ist precision (0x00 = 0), das letzte Byte ist der Wert (0x01 = 1). Ich bin mir nicht sicher, wofür die Bytes drei und vier sind. Das Zeichen ist da drin, aber das braucht keine zwei Bytes. Sicherlich hat das Umdrehen dieses Bits nichts bewirkt.
Martin Smith
1
Danke, @MartinSmith - wie um alles in der Welt haben Sie festgestellt, dass die ersten beiden Bytes so verwendet werden? Ist das dokumentiert?
Max Vernon
3
@ AaronBertrand: Möchten Sie das als Antwort geben? Wir können dies von der "unbeantworteten" Liste streichen.
Jon of All Trades

Antworten:

2

Dezimal- und Ganzzahlen werden im Varbinary sehr unterschiedlich codiert. Dezimalstellen benötigen mehr Platz. Versuchen:

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

Was Ihr Endziel angeht, ganze Zahlen als Varbinary zu speichern, um Platz zu sparen, haben Sie diese Frage wahrscheinlich selbst beantwortet - es lohnt sich nicht.

Aaron Bertrand
quelle