Memahami Jenis Tanggal MS SQL Server

8

Pertimbangkan yang berikut ini:

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

Keluaran:

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

Sekarang, saya sudah mengerti dari dokumentasi yang datetimememiliki rentang yang lebih kecil, dan mulai dari 1753-01-01, sementara datetime2dan datemenggunakan 0001-01-01 sebagai tanggal mulai.

Apa yang saya tidak mengerti, adalah yang datetimetampaknya menjadi little-endian sementara datetime2dan datebig-endian. Jika itu masalahnya, bagaimana mereka bisa disortir dengan baik?

Pertimbangkan jika saya ingin tahu berapa hari bilangan bulat diwakili oleh suatu datetipe. Anda akan berpikir Anda bisa melakukan ini:

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

Tetapi karena endianness, Anda mendapatkan 1966080 hari!

Untuk mendapatkan hasil yang benar selama 30 hari, Anda harus membaliknya:

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

Atau, tentu saja Anda dapat melakukan ini:

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

Tapi itu berarti secara internal di suatu tempat ia membalik byte.

Jadi mengapa mereka beralih endianness?

Saya hanya peduli karena saya sedang mengerjakan custom UDT di SQLCLR dan urutan biner dari byte tampaknya penting di sana, tetapi tipe bawaan ini tampak jauh lebih fleksibel. Apakah SQL Server memiliki sesuatu internal di mana setiap jenis dapat menyediakan algoritma pengurutan itu sendiri? Dan jika demikian, apakah ada cara saya dapat memanfaatkannya untuk UDT khusus saya?

Lihat juga, pertanyaan terkait (tetapi berbeda) di StackOverflow.

Matt Johnson-Pint
sumber
Sudahkah Anda mencoba implementasi IComparable? Anda tidak perlu menggali representasi internal tipe data, selamanya.
Jon Seigel
Menurut ini (gulir ke bawah ke "Menerapkan UDT dengan Format yang Ditentukan Pengguna"), Anda dapat menerapkan IComparable, tetapi hanya digunakan sisi klien. SQL Server mengabaikannya dan mematikan urutan byte.
Matt Johnson-Pint
Oh Nah itu menyebalkan.
Jon Seigel
@ PaulWhite - Itu memang berguna. Setidaknya itu konfirmasi dari apa yang saya alami. Terima kasih!
Matt Johnson-Pint
@ PaulWhite - Bagian yang tidak dia bahas dalam artikel itu adalah cara menghapus byte terkemuka untuk null. Mengapa int perlu disimpan dalam 5 byte?
Matt Johnson-Pint

Jawaban:

2

SQL Server tidak bergantung pada urutan biner untuk tipe datanya "sendiri". Untuk tipe data CLR Anda bisa menggunakan antarmuka iComparable, tetapi seperti yang disebutkan @MattJohnson, SQL Server mengabaikannya:

http://connect.microsoft.com/SQLServer/feedback/details/252230/sqlclr-menyediakan-kemampuan-untuk-menggunakan-icomparable-atau--samailar-mekanisme-untuk-udts


Microsoft tidak mempublikasikan detail tentang bagaimana tipe data yang berbeda disimpan dan bekerja dengan. Namun Books Online secara eksplisit menyatakan bahwa Anda tidak dapat bergantung pada format biner tertentu untuk tipe data tertentu dan bahwa format yang mereka gunakan dapat berubah sewaktu-waktu. Jadi adalah ide yang baik untuk menyimpan INT hanya sebagai itu dan bukan sebagai VARBINARY, karena Anda mungkin tidak dapat membaca data Anda lagi setelah SP berikutnya.

Adapun penyortiran: Sebagian besar inti SQL Server ditulis dalam C ++. Saya menganggap secara internal metode yang mirip dengan iComparable digunakan. Tetapi sekali lagi, tidak ada dokumentasi yang dapat diakses publik tentang ini tersedia. Bahkan jika itu, Anda mungkin tidak akan dapat memanfaatkannya karena perbedaan yang melekat antara .NET dan C ++.

Sebastian Meine
sumber
Nomor masalah lain yang disebutkan di sana juga informatif. Tetapi apakah Anda memiliki rincian tentang bagaimana tipe internal melakukannya?
Matt Johnson-Pint
@MattJohnson, lihat pembaruan saya di atas. Saya khawatir itu bukan yang Anda cari ...
Sebastian Meine
Jadi, Anda merekomendasikan menggunakan SQL intsebagai bidang dukungan CLR UDT saya? Apakah Anda memiliki contoh cara melakukannya? The CREATE TYPEpernyataan akan mengambil base_type, atau perakitan eksternal - tetapi tidak keduanya.
Matt Johnson-Pint
Tidak, itu hanya contoh. Apa yang saya katakan adalah bahwa Anda perlu menemukan cara untuk membuat cerita bersambung UDT Anda agar dapat disortir biner, karena tidak ada cara saat ini untuk mengimplementasikan antarmuka iComparable (atau serupa) dan meminta SQL Server menggunakannya.
Sebastian Meine