Comprensione dei tipi di data di MS SQL Server


8

Considera quanto segue:

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

Produzione:

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

Ora, ho già capito da documentazione che datetimeha una gamma più piccola, e parte da 1753/01/01, mentre datetime2e dateuso 0001-01-01 come la loro data di inizio.

Quello che non capisco, però, è che datetimesembra essere mentre little-endian datetime2e datesono big-endian. In tal caso, come possono anche essere adeguatamente ordinabili?

Considera se voglio sapere quanti giorni interi sono rappresentati da un datetipo. Penseresti di poter fare questo:

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

Ma a causa dell'endianità, ottieni 1966080 giorni!

Per ottenere il risultato corretto di 30 giorni, è necessario invertirlo:

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

Oppure, ovviamente puoi farlo:

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

Ma ciò significa internamente da qualche parte che sta invertendo comunque i byte.

Allora perché hanno cambiato endianness?

Mi interessa solo perché sto lavorando su un UDT personalizzato in SQLCLR e l'ordine binario dei byte sembra importare lì, ma questi tipi predefiniti sembrano molto più flessibili. SQL Server ha qualcosa di interno in cui ogni tipo arriva a fornire il proprio algoritmo di ordinamento? E se è così, c'è un modo in cui posso attingere a quello per il mio UDT personalizzato?

Vedi anche, una domanda correlata (ma diversa) su StackOverflow.


Hai provato a implementare IComparable? Non dovresti mai dover scavare nella rappresentazione interna dei tipi di dati, mai.
Jon Seigel,

In base a ciò (scorrere fino a "Implementazione di un UDT con un formato definito dall'utente"), è possibile implementare IComparable, ma viene utilizzato solo sul lato client. SQL Server lo ignora e disattiva l'ordine dei byte.
Matt Johnson-Pint,

Oh. Bene, questo è fastidioso.
Jon Seigel,

@PaulWhite - Questo è davvero utile. Almeno è la conferma di ciò che sto vivendo. Grazie!
Matt Johnson-Pint,

@PaulWhite - La parte che non affronta in quell'articolo è come rimuovere il byte iniziale per il null. Perché un int deve essere archiviato in 5 byte?
Matt Johnson-Pint,

Risposte:


2

SQL Server non si basa sull'ordine binario per i suoi "propri" tipi di dati. Per i tipi di dati CLR è possibile utilizzare l'interfaccia iComparable, ma come menzionato da @MattJohnson, SQL Server la ignora:

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


Microsoft non pubblica i dettagli su come i diversi tipi di dati vengono archiviati e utilizzati. Tuttavia, Books Online afferma esplicitamente che non è possibile fare affidamento su un formato binario specifico per un tipo di dati specifico e che il formato che utilizzano potrebbe cambiare in qualsiasi momento. Quindi è una buona idea archiviare un INT come quello e non come VARBINARY, perché potresti non essere più in grado di leggere i tuoi dati dopo il prossimo SP.

Per quanto riguarda l'ordinamento: la maggior parte del core di SQL Server è scritto in C ++. Presumo internamente un metodo simile a un iComparable viene utilizzato. Ma ancora una volta, non è disponibile alcuna documentazione pubblicamente accessibile a riguardo. Anche se lo fosse, probabilmente non saresti in grado di sfruttarlo a causa delle differenze intrinseche tra .NET e C ++.


L'altro numero di problema menzionato era anche informativo. Ma hai qualche dettaglio su come lo fanno i tipi interni?
Matt Johnson-Pint,

@MattJohnson, vedi il mio aggiornamento sopra. Temo che non sia quello che cercavi ...
Sebastian Meine,

Quindi, stai raccomandando di usare un SQL intcome campo di supporto del mio CLR UDT? Hai un esempio di come farlo? La CREATE TYPEdichiarazione richiederà un base_type, o un assembly esterno, ma non entrambi.
Matt Johnson-Pint,

No, quello era solo un esempio. Quello che sto dicendo è che devi trovare un modo per serializzare il tuo UDT in modo che possa essere ordinato in modo binario, in quanto non esiste un modo attuale per implementare un'interfaccia iComparable (o simile) e fare in modo che SQL Server lo usi.
Sebastian Meine,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.