Quelle est la cause de ce problème avec CONVERT ()?

12

Considérez les deux déclarations suivantes:

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

Les deux déclarations reviennent -1; n'est-ce pas incorrect puisque la deuxième valeur binaire est supérieure de 65 536 décimales à la première valeur, n'est-ce pas?

Cela ne peut certainement pas être dû à une troncature silencieuse?

Si je lance les instructions suivantes:

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

On me présente l'erreur suivante:

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

Comment puis-je diagnostiquer ce qui se passe ici?

J'exécute cela sur SQL Server 2012, v11.0.5058. Les résultats sont les mêmes sur SQL Server 2008 R2 SP2, SQL Server 2005 et SQL Server 2000.

Max Vernon
la source
4
Les nombres décimaux et entiers sont codés très différemment en varbinary. Les décimales ont besoin de plus d'espace. TrySELECT CONVERT(VARBINARY(32), 1), CONVERT(VARBINARY(32), 1.0);
Aaron Bertrand
4
Aaron est sur place. Votre cerveau convertit les données binaires en données entières puis directement en numérique, mais SQL Server ne fait pas cette conversion implicite de binaire -> entier -> numérique (x, y). Pour SQL Server pour suivre votre processus de pensée, vous auriez à faire quelque chose comme ceci: PRINT CONVERT(NUMERIC(38, 0), convert(int, 0x00000001), 0); PRINT CONVERT(NUMERIC(38, 0), convert(int, 0x00010001), 0);.
Thomas Stringer
5
Le premier octet est échelle (0x01 = 1), le deuxième octet est précision (0x00 = 0), le dernier octet est la valeur (0x01 = 1). Je ne sais pas à quoi servent les octets trois et quatre. Le signe est là, mais cela n'a pas besoin de deux octets. Il est certain que retourner ce bit ne semble avoir rien affecté.
Martin Smith
1
Merci, @MartinSmith - comment diable avez-vous déterminé que les deux premiers octets sont utilisés comme ça? Est-ce documenté?
Max Vernon
3
@AaronBertrand: Souhaitez-vous en faire une réponse? Nous pouvons marquer cela sur la liste "sans réponse".
Jon of All Trades,

Réponses:

2

Les nombres décimaux et entiers sont codés très différemment en varbinary. Les décimales ont besoin de plus d'espace. Essayer:

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

Quant à votre objectif ultime, stocker des nombres entiers sous forme de fichiers varbinary pour économiser de l'espace, je pense que vous avez répondu vous-même à cette question - cela n'en vaut pas la peine.

Aaron Bertrand
la source