В чем причина этой проблемы с CONVERT ()?

12

Рассмотрим следующие два утверждения:

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

Оба утверждения возвращаются -1; не так ли это, поскольку второе двоичное значение является десятичным на 65 536 больше первого значения, не так ли?

Конечно, это не может быть связано с тихим усечением?

Если я запускаю следующие заявления:

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

Мне представляется следующая ошибка:

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

Как я могу диагностировать, что здесь происходит?

Я запускаю это на SQL Server 2012, v11.0.5058. Результаты одинаковы для SQL Server 2008 R2 с пакетом обновления 2, SQL Server 2005 и SQL Server 2000.

Макс Вернон
источник
4
Десятичные и целые числа по-разному кодируются в varbinary. Десятичным знакам нужно больше места. ПопробуйтеSELECT CONVERT(VARBINARY(32), 1), CONVERT(VARBINARY(32), 1.0);
Аарон Бертран
4
Аарон на месте. Ваш мозг преобразует двоичные данные в целочисленные, а затем прямо в числовые, но SQL Server не делает этого неявного преобразования из двоичного -> целое число -> числовое (x, y). Для SQL Server следовать мыслительному процессу, вы должны сделать что - то вроде этого: PRINT CONVERT(NUMERIC(38, 0), convert(int, 0x00000001), 0); PRINT CONVERT(NUMERIC(38, 0), convert(int, 0x00010001), 0);.
Томас Стрингер
5
Первый байт - это масштаб (0x01 = 1), второй байт - точность (0x00 = 0), последний байт - значение (0x01 = 1). Не уверен, что байты три и четыре для. Знак есть, но для этого не нужно двух байтов. Конечно, щелчок этого бита, похоже, ни на что не повлиял.
Мартин Смит
1
Спасибо, @MartinSmith - с какой стати вы определили, что первые два байта используются таким образом? Это задокументировано?
Макс Вернон
3
@AaronBertrand: Вы хотели бы ответить на этот вопрос? Мы можем пометить это из списка «без ответа».
Джон на все руки

Ответы:

2

Десятичные и целые числа по-разному кодируются в varbinary. Десятичным знакам нужно больше места. Пытаться:

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

Что касается вашей конечной цели, хранить целые числа как varbinary для экономии места, я думаю, что вы сами ответили на этот вопрос - не стоит.

Аарон Бертран
источник