Apa penyebab masalah ini dengan CONVERT ()?

12

Pertimbangkan dua pernyataan berikut:

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

Kedua pernyataan kembali -1; bukankah itu salah karena nilai biner kedua adalah desimal 65.536 lebih tinggi dari nilai pertama, bukan?

Tentunya ini bukan karena pemotongan diam?

Jika saya menjalankan pernyataan berikut:

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

Saya disajikan dengan kesalahan berikut:

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

Bagaimana saya bisa mendiagnosis apa yang terjadi di sini?

Saya menjalankan ini pada SQL Server 2012, v11.0.5058. Hasilnya sama pada SQL Server 2008 R2 SP2, SQL Server 2005, dan SQL Server 2000.

Max Vernon
sumber
4
Bilangan desimal dan bilangan bulat dikodekan sangat berbeda dalam varbinary. Desimal membutuhkan lebih banyak ruang. CobaSELECT CONVERT(VARBINARY(32), 1), CONVERT(VARBINARY(32), 1.0);
Aaron Bertrand
4
Aaron tepat. Otak Anda mengonversi data biner ke data integer kemudian langsung ke numerik, tetapi SQL Server tidak melakukan konversi tersirat dari biner -> integer -> numerik (x, y). Untuk SQL Server untuk mengikuti proses berpikir Anda, Anda harus melakukan sesuatu seperti ini: PRINT CONVERT(NUMERIC(38, 0), convert(int, 0x00000001), 0); PRINT CONVERT(NUMERIC(38, 0), convert(int, 0x00010001), 0);.
Thomas Stringer
5
Byte pertama adalah skala (0x01 = 1), byte kedua adalah presisi (0x00 = 0), byte terakhir adalah nilainya (0x01 = 1). Tidak yakin untuk apa byte ketiga dan empat. Tanda ada di sana tetapi itu tidak perlu dua byte. Tentu saja membalik sedikit itu tampaknya tidak mempengaruhi apa pun.
Martin Smith
1
Terima kasih, @ MartinSmith - bagaimana Anda menentukan dua byte pertama digunakan seperti itu? Apakah itu didokumentasikan?
Max Vernon
3
@AaronBertrand: Apakah Anda ingin menjawabnya? Kita dapat menandai ini dari daftar "tidak dijawab".
Jon of All Trades

Jawaban:

2

Bilangan desimal dan bilangan bulat dikodekan sangat berbeda dalam varbinary. Desimal membutuhkan lebih banyak ruang. Mencoba:

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

Adapun tujuan akhir Anda, menyimpan bilangan bulat sebagai varbinary untuk menghemat ruang, saya pikir Anda telah menjawab pertanyaan itu sendiri - tidak sepadan.

Aaron Bertrand
sumber