¿Cuál es la causa de este problema con CONVERT ()?

12

Considere las siguientes dos declaraciones:

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

Ambas declaraciones regresan -1; ¿No es incorrecto ya que el segundo valor binario es 65.536 decimal más alto que el primer valor, no?

¿Seguramente esto no puede ser debido al truncamiento silencioso?

Si ejecuto las siguientes declaraciones:

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

Me aparece el siguiente error:

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

¿Cómo puedo diagnosticar lo que está sucediendo aquí?

Estoy ejecutando esto en SQL Server 2012, v11.0.5058. Los resultados son los mismos en SQL Server 2008 R2 SP2, SQL Server 2005 y SQL Server 2000.

Max Vernon
fuente
44
Los números decimales y enteros se codifican de manera muy diferente en varbinary. Los decimales necesitan más espacio. PruebaSELECT CONVERT(VARBINARY(32), 1), CONVERT(VARBINARY(32), 1.0);
Aaron Bertrand
44
Aaron es perfecto. Su cerebro está convirtiendo los datos binarios en datos enteros y luego directamente a numéricos, pero SQL Server no hace esa conversión implícita de binario -> entero -> numérico (x, y). Para SQL Server para seguir su proceso de pensamiento, que tendría que hacer algo como esto: PRINT CONVERT(NUMERIC(38, 0), convert(int, 0x00000001), 0); PRINT CONVERT(NUMERIC(38, 0), convert(int, 0x00010001), 0);.
Thomas Stringer
55
El primer byte es la escala (0x01 = 1), el segundo byte es la precisión (0x00 = 0), el byte final es el valor (0x01 = 1). No estoy seguro de para qué son los bytes tres y cuatro. El letrero está allí, pero eso no necesita dos bytes. Ciertamente, cambiar ese bit no parece haber afectado nada.
Martin Smith
1
Gracias, @ MartinSmith: ¿cómo demonios determinaste que los dos primeros bytes se usan así? ¿Eso está documentado?
Max Vernon
3
@AaronBertrand: ¿Le gustaría responder eso? Podemos marcar esto en la lista de "sin respuesta".
Jon of All Trades

Respuestas:

2

Los números decimales y enteros se codifican de manera muy diferente en varbinary. Los decimales necesitan más espacio. Tratar:

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

En cuanto a su objetivo final, almacenar números enteros como varbinary para ahorrar espacio, creo que ha respondido esa pregunta usted mismo, no vale la pena.

Aaron Bertrand
fuente