Noções básicas sobre tipos de data do MS SQL Server

8

Considere o seguinte:

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

Resultado:

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

Agora, eu já entendem a partir da documentação que datetimetem um alcance menor, e começa a partir de 1753/01/01, enquanto datetime2e dateusar 0001-01-01 como sua data de início.

O que eu não entendo, porém, é que datetimeparece ser um pouco endian enquanto datetime2e dateé um big end. Se for esse o caso, como eles podem ser classificados adequadamente?

Considere se eu quero saber quantos dias inteiros são representados por um datetipo. Você pensaria que poderia fazer isso:

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

Mas devido à persistência, você recebe 1966080 dias!

Para obter o resultado correto de 30 dias, é necessário revertê-lo:

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

Ou, é claro, você pode fazer isso:

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

Mas isso significa que internamente em algum lugar está invertendo os bytes de qualquer maneira.

Então, por que eles trocaram endianness?

Só me importo porque estou trabalhando em um UDT personalizado no SQLCLR e a ordem binária dos bytes parece importar lá, mas esses tipos internos parecem muito mais flexíveis. O SQL Server tem algo interno onde cada tipo obtém para fornecer seu próprio algoritmo de classificação? E, em caso afirmativo, existe uma maneira de aproveitar isso para o meu UDT personalizado?

Consulte também uma pergunta relacionada (mas diferente) no StackOverflow.

Matt Johnson-Pint
fonte
Você já tentou implementar IComparable? Você não precisa se aprofundar na representação interna dos tipos de dados.
21813 Jon Seigel
De acordo com isso (role para baixo até "Implementando uma UDT com um formato definido pelo usuário"), você pode implementar IComparable, mas ele é usado apenas no lado do cliente. O SQL Server o ignora e sai da ordem dos bytes.
Matt Johnson-Pint
Oh. Bem, isso é chato.
22813 Jon Seigel
@PaulWhite - Isso é realmente útil. Pelo menos é a confirmação do que estou experimentando. Obrigado!
Matt Johnson-Pint
@PaulWhite - A parte que ele não aborda nesse artigo é como remover o byte principal do nulo. Por que um int precisa ser armazenado em 5 bytes?
Matt Johnson-Pint

Respostas:

2

O SQL Server não depende da ordem binária para seus tipos de dados "próprios". Para tipos de dados CLR, você pode usar a interface iComparable, mas como o @MattJohnson mencionou, o SQL Server a ignora:

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


A Microsoft não publica os detalhes sobre como os diferentes tipos de dados são armazenados e trabalhados. No entanto, o Books Online afirma explicitamente que você não pode confiar em um formato binário específico para um tipo de dados específico e que o formato que eles usam pode mudar a qualquer momento. Portanto, é uma boa idéia armazenar uma INT apenas isso e não como VARBINÁRIO, porque talvez você não consiga ler mais seus dados após o próximo SP.

Quanto à classificação: a maior parte do núcleo do SQL Server é escrita em C ++. Presumo internamente que um método semelhante a um iComparable seja usado. Porém, novamente, não há documentação publicamente acessível sobre isso disponível. Mesmo que fosse, você provavelmente não seria capaz de explorá-lo devido às diferenças inerentes entre o .NET e o C ++.

Sebastian Meine
fonte
O outro número de questão mencionado também foi informativo. Mas você tem algum detalhe sobre como os tipos internos fazem isso?
Matt Johnson-Pint
@MattJohnson, veja minha atualização acima. Receio que não é o que você estava procurando ...
Sebastian Meine
Então, você está recomendando o uso de SQL intcomo o campo de apoio do meu CLR UDT? Você tem um exemplo de como fazer isso? A CREATE TYPEdeclaração terá base_typeuma montagem, ou uma montagem externa - mas não ambas.
Matt Johnson-Pint
Não, isso foi apenas um exemplo. O que estou dizendo é que você precisa encontrar uma maneira de serializar sua UDT para que ela possa ser classificada em binário, pois não existe uma maneira atual de implementar uma interface iComparable (ou similar) e que o SQL Server a utilize.
Sebastian Meine