Qual é a causa desse problema com CONVERT ()?

12

Considere as duas instruções a seguir:

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

As duas instruções retornam -1; não é incorreto, pois o segundo valor binário é decimal 65.536 mais alto que o primeiro valor, não é?

Certamente isso não pode ser devido ao truncamento silencioso?

Se eu executar as seguintes instruções:

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

Sou apresentado com o seguinte erro:

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

Como posso diagnosticar o que está acontecendo aqui?

Estou executando isso no SQL Server 2012, v11.0.5058. Os resultados são os mesmos no SQL Server 2008 R2 SP2, no SQL Server 2005 e no SQL Server 2000.

Max Vernon
fonte
4
Números decimais e inteiros são codificados de maneira muito diferente em varbinary. Os decimais precisam de mais espaço. TenteSELECT CONVERT(VARBINARY(32), 1), CONVERT(VARBINARY(32), 1.0);
Aaron Bertrand
4
Aaron está no local. Seu cérebro está convertendo os dados binários em dados inteiros e depois diretamente para numéricos, mas o SQL Server não faz essa conversão implícita de binário -> inteiro -> numérico (x, y). Para o SQL Server para seguir o seu processo de pensamento, você teria que fazer algo como isto: PRINT CONVERT(NUMERIC(38, 0), convert(int, 0x00000001), 0); PRINT CONVERT(NUMERIC(38, 0), convert(int, 0x00010001), 0);.
Thomas Stringer
5
O primeiro byte é escala (0x01 = 1), o segundo byte é precisão (0x00 = 0), o byte final é o valor (0x01 = 1). Não sei para que servem os bytes três e quatro. O sinal está lá, mas isso não precisa de dois bytes. Certamente, virar esse pedaço não parece ter afetado nada.
Martin Smith
1
Obrigado, @MartinSmith - como você determinou que os dois primeiros bytes são usados ​​assim? Isso está documentado?
Max Vernon
3
@AaronBertrand: Gostaria de fazer disso uma resposta? Podemos marcar isso na lista "sem resposta".
Jon of All Trades

Respostas:

2

Números decimais e inteiros são codificados de maneira muito diferente em varbinary. Os decimais precisam de mais espaço. Experimentar:

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

Quanto ao seu objetivo final, armazenar números inteiros como varbinário para economizar espaço, acho que você já respondeu essa pergunta - não vale a pena.

Aaron Bertrand
fonte