Comprendre les types de date MS SQL Server


8

Considérer ce qui suit:

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

Production:

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

Maintenant, je comprends déjà de la documentation qui datetimea une plage plus petite, et commence à partir de 1753-01-01, datetime2et dateutilise 0001-01-01 comme date de début.

Ce que je ne comprends pas bien, est que datetimesemble être peu endian tout datetime2et datesont big-endian. Si tel est le cas, comment peuvent-ils même être correctement triés?

Considérez si je veux savoir combien de jours entiers sont représentés par un datetype. On pourrait penser que vous pourriez faire ceci:

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

Mais en raison de l'endianisme, vous obtenez 1966080 jours!

Pour obtenir le résultat correct de 30 jours, vous devez l'inverser:

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

Ou bien sûr, vous pouvez le faire:

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

Mais cela signifie en interne quelque part qu'il inverse les octets de toute façon.

Alors pourquoi ont-ils changé d'endianisme?

Je m'en soucie uniquement parce que je travaille sur un UDT personnalisé dans SQLCLR et l'ordre binaire des octets semble y avoir de l'importance, mais ces types intégrés semblent beaucoup plus flexibles. SQL Server a-t-il quelque chose de interne où chaque type peut fournir son propre algorithme de tri? Et si oui, existe-t-il un moyen de puiser dans cela pour mon UDT personnalisé?

Voir aussi, une question connexe (mais différente) sur StackOverflow.


Avez-vous essayé d'implémenter IComparable? Vous ne devriez jamais avoir besoin de fouiller dans la représentation interne des types de données.
Jon Seigel

Selon cela (faites défiler jusqu'à "Implémentation d'un UDT avec un format défini par l'utilisateur"), vous pouvez l' implémenter IComparable, mais il n'est utilisé que côté client. SQL Server l'ignore et désactive l'ordre des octets.
Matt Johnson-Pint

Oh. C'est ennuyeux.
Jon Seigel

@PaulWhite - C'est en effet utile. Au moins, c'est la confirmation de ce que je vis. Merci!
Matt Johnson-Pint

@PaulWhite - La partie qu'il ne traite pas dans cet article est de savoir comment supprimer l'octet de tête pour le null. Pourquoi un int doit-il être stocké sur 5 octets?
Matt Johnson-Pint

Réponses:


2

SQL Server ne s'appuie pas sur l'ordre binaire pour ses «propres» types de données. Pour les types de données CLR, vous pouvez utiliser l'interface iComparable, mais comme @MattJohnson l'a mentionné, SQL Server l'ignore:

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


Microsoft ne publie pas les détails sur la façon dont les différents types de données sont stockés et utilisés. Cependant, Books Online indique explicitement que vous ne pouvez pas compter sur un format binaire spécifique pour un type de données spécifique et que le format qu'ils utilisent peut changer à tout moment. C'est donc une bonne idée de stocker un INT comme cela et non comme VARBINARY, car vous ne pourrez peut-être plus lire vos données après le prochain SP.

Quant au tri: la majeure partie du cœur de SQL Server est écrite en C ++. Je suppose en interne qu'une méthode similaire à un iComparable est utilisée. Mais encore une fois, il n'y a pas de documentation accessible au public à ce sujet. Même si c'était le cas, vous ne seriez probablement pas en mesure de l'exploiter en raison des différences inhérentes entre .NET et C ++.


L'autre numéro de problème mentionné était également informatif. Mais avez-vous des détails sur la façon dont les types internes le font?
Matt Johnson-Pint

@MattJohnson, voir ma mise à jour ci-dessus. J'ai bien peur que ce ne soit pas ce que vous cherchiez ...
Sebastian Meine

Donc, vous recommandez d'utiliser un SQL intcomme champ de support de mon CLR UDT? Avez-vous un exemple de la façon de procéder? L' CREATE TYPEinstruction prendra un base_typeou un assemblage externe - mais pas les deux.
Matt Johnson-Pint

Non, ce n'était qu'un exemple. Ce que je dis, c'est que vous devez trouver un moyen de sérialiser votre UDT afin qu'il puisse être trié en binaire, car il n'existe aucun moyen actuel d'implémenter une interface iComparable (ou similaire) et de faire en sorte que SQL Server l'utilise.
Sebastian Meine
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.