Comprender los tipos de fecha de MS SQL Server


8

Considera lo siguiente:

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

Salida:

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

Ahora, yo ya entiendo de la documentación que datetimetiene un rango menor, y se inicia a partir de 01.01.1753, mientras que datetime2y dateutilizo 0001-01-01 como su fecha de inicio.

Sin embargo, lo que no entiendo es que datetimeparece ser little endian datetime2y datebig-endian. Si ese es el caso, ¿cómo pueden clasificarse correctamente?

Considere si quiero saber cuántos días enteros están representados por un datetipo. Pensarías que podrías hacer esto:

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

Pero debido a la resistencia, ¡obtienes 1966080 días!

Para obtener el resultado correcto de 30 días, debe revertirlo:

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

O, por supuesto, puedes hacer esto:

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

Pero eso significa internamente en algún lugar que está invirtiendo los bytes de todos modos.

Entonces, ¿por qué cambiaron endianness?

Solo me importa porque estoy trabajando en un UDT personalizado en SQLCLR y el orden binario de los bytes parece importar allí, pero estos tipos incorporados parecen mucho más flexibles. ¿SQL Server tiene algo interno donde cada tipo puede proporcionar su propio algoritmo de clasificación? Y si es así, ¿hay alguna manera de aprovechar eso para mi UDT personalizado?

Consulte también una pregunta relacionada (pero diferente) sobre StackOverflow.


¿Has intentado implementar IComparable? No debería necesitar profundizar en la representación interna de los tipos de datos, nunca.
Jon Seigel

De acuerdo con esto (desplácese hacia abajo hasta "Implementar un UDT con un formato definido por el usuario"), puede implementar IComparable, pero solo se usa del lado del cliente. SQL Server lo ignora y sale del orden de bytes.
Matt Johnson-Pint

Oh. Bueno, eso es molesto.
Jon Seigel

@PaulWhite - Eso es realmente útil. Al menos es la confirmación de lo que estoy experimentando. ¡Gracias!
Matt Johnson-Pint

@PaulWhite: la parte que no aborda en ese artículo es cómo eliminar el byte inicial para el nulo. ¿Por qué un int necesita ser almacenado en 5 bytes?
Matt Johnson-Pint

Respuestas:


2

SQL Server no se basa en el orden binario para sus tipos de datos "propios". Para los tipos de datos CLR, puede usar la interfaz iComparable, pero como mencionó @MattJohnson, SQL Server lo ignora:

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


Microsoft no publica los detalles sobre cómo se almacenan y trabajan los diferentes tipos de datos. Sin embargo, Books Online declara explícitamente que no puede confiar en un formato binario específico para un tipo de datos específico y que el formato que usan puede cambiar en cualquier momento. Por lo tanto, es una buena idea almacenar un INT solo como eso y no como VARBINARIO, porque es posible que ya no pueda leer sus datos después del próximo SP.

En cuanto a la clasificación: la mayor parte del núcleo de SQL Server está escrito en C ++. Supongo que internamente se usa un método similar a un iComparable. Pero, de nuevo, no hay documentación de acceso público sobre esto disponible. Incluso si lo fuera, probablemente no podría explotarlo debido a las diferencias inherentes entre .NET y C ++.


El otro número de problema mencionado allí también fue informativo. ¿Pero tiene algún detalle sobre cómo lo hacen los tipos internos?
Matt Johnson-Pint

@ MattJohnson, mira mi actualización arriba. Me temo que no es lo que estabas buscando ...
Sebastian Meine

Entonces, ¿está recomendando usar un SQL intcomo campo de respaldo de mi CLR UDT? ¿Tienes un ejemplo de cómo hacer eso? La CREATE TYPEdeclaración tomará un base_typeensamblaje externo o uno, pero no ambos.
Matt Johnson-Pint

No, eso fue solo un ejemplo. Lo que digo es que necesita encontrar una forma de serializar su UDT para que pueda clasificarse en binario, ya que no hay una forma actual de implementar una interfaz iComparable (o similar) y hacer que SQL Server la use.
Sebastian Meine
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.