Понимание типов даты MS SQL Server

8

Учтите следующее:

declare @dt datetime, @dt2 datetime2, @d date
set @dt  = '2013-01-01'
set @dt2 = '2013-01-01'
set @d   = '2013-01-01'

select convert(varbinary, @dt) as dt,
       convert(varbinary, @dt2) as dt2,
       convert(varbinary, @d) as d

Вывод:

dt                    dt2                     d
------------------    --------------------    --------
0x0000A13900000000    0x07000000000094360B    0x94360B

Теперь я уже понимаю из документации, которая datetimeимеет меньший диапазон и начинается с 1753-01-01, datetime2а также dateиспользует 0001-01-01 в качестве даты начала.

Что я не понимаю, хотя, это то, что, datetimeкажется, с прямым порядком байтов в то время как datetime2и dateс обратным порядком байтов. Если это так, как они могут быть правильно отсортированы?

Подумайте, хочу ли я узнать, сколько целых дней представлено dateтипом. Вы могли бы подумать, что вы могли бы сделать это:

declare @d date
set @d = '0001-01-31'
select cast(convert(varbinary, @d) as int)

Но благодаря порядку байтов вы получаете 1966080 дней!

Чтобы получить правильный результат 30 дней, вы должны поменять его местами:

select cast(convert(varbinary,reverse(convert(varbinary, @d))) as int)

Или, конечно, вы можете сделать это:

select datediff(d,'0001-01-01', @d)

Но это означает, что внутренне где-то это все равно обращает байты.

Так почему же они поменяли порядок байтов?

Меня волнует только то, что я работаю над пользовательским UDT в SQLCLR, и двоичный порядок байтов, кажется, там имеет значение, но эти встроенные типы кажутся гораздо более гибкими. Есть ли в SQL Server что-то внутреннее, где каждый тип предоставляет собственный алгоритм сортировки? И если так, есть ли способ, которым я могу использовать это для своего пользовательского UDT?

См. Также связанный (но другой) вопрос о StackOverflow.

Мэтт Джонсон-Пинт
источник
Вы пытались реализовать IComparable? Вам никогда не нужно копаться во внутреннем представлении типов данных.
Джон Зигель
В соответствии с этим (прокрутите вниз до «Реализация UDT с определяемым пользователем форматом»), вы можете реализовать IComparable, но он используется только на стороне клиента. SQL Server игнорирует его и отключает порядок байтов.
Мэтт Джонсон-Пинт
Ой. Ну, это раздражает.
Джон Зигель
@PaulWhite - Это действительно полезно. По крайней мере, это подтверждение того, что я испытываю. Спасибо!
Мэтт Джонсон-Пинт
@PaulWhite - часть, которую он не рассматривает в этой статье, - это как удалить начальный байт для нуля. Зачем нужно хранить int в 5 байтах?
Мэтт Джонсон-Пинт

Ответы:

2

SQL Server не использует двоичный порядок для своих «собственных» типов данных. Для типов данных CLR вы можете использовать интерфейс iComparable, но, как упомянул @MattJohnson, SQL Server игнорирует его:

http://connect.microsoft.com/SQLServer/feedback/details/252230/sqlclr-provide-the-ability-to-use-icomparable-or-a-similar-mechanism-for-udts


Microsoft не публикует подробности о том, как различные типы данных хранятся и работают с ними. Однако Books Online прямо заявляет, что вы не можете полагаться на конкретный двоичный формат для определенного типа данных и что формат, который они используют, может измениться в любое время. Поэтому хорошей идеей будет хранить INT как только это, а не как VARBINARY, потому что вы не сможете больше читать ваши данные после следующего SP.

Что касается сортировки: большая часть ядра SQL Server написана на C ++. Я предполагаю, что внутренне используется метод, похожий на iComparable. Но опять же, нет общедоступной документации об этом доступном. Даже если бы это было так, вы, вероятно, не смогли бы использовать его из-за внутренних различий между .NET и C ++.

Себастьян Майн
источник
Другой упомянутый номер выпуска также был информативным. Но есть ли у вас какие-либо подробности относительно того, как это делают внутренние типы?
Мэтт Джонсон-Пинт
@MattJohnson, см. Мое обновление выше. Боюсь, это не то, что вы искали ...
Себастьян Майн
Итак, вы рекомендуете использовать SQL intв качестве вспомогательного поля моего CLR UDT? У вас есть пример, как это сделать? CREATE TYPEЗаявление будет принимать base_typeили внешний монтаж - но не оба.
Мэтт Джонсон-Пинт
Нет, это был просто пример. Я хочу сказать, что вам нужно найти способ сериализации вашего UDT, чтобы он мог быть отсортирован в двоичном виде, поскольку в настоящее время нет способа реализовать интерфейс iComparable (или аналогичный) и использовать его в SQL Server.
Себастьян Майн