Grundlegendes zu MS SQL Server-Datumstypen

8

Folgendes berücksichtigen:

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

Ausgabe:

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

Jetzt verstehe ich bereits aus der Dokumentation , datetimedie einen kleineren Bereich hat und vom 1753-01-01 beginnt, während datetime2und date0001-01-01 als Startdatum verwendet.

Was ich jedoch nicht verstehe, ist, dass datetimees währenddessen Little-Endian zu sein scheint datetime2und dateBig-Endian ist. Wenn dies der Fall ist, wie können sie dann überhaupt richtig sortiert werden?

Überlegen Sie, ob ich wissen möchte, wie viele ganzzahlige Tage ein dateTyp darstellt. Sie würden denken, Sie könnten dies tun:

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

Aber aufgrund der Endianness erhalten Sie 1966080 Tage!

Um das richtige Ergebnis von 30 Tagen zu erhalten, müssen Sie es umkehren:

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

Oder natürlich können Sie dies tun:

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

Aber das bedeutet intern irgendwo, dass es die Bytes sowieso umkehrt.

Warum haben sie die Endianness gewechselt?

Es ist mir nur wichtig, weil ich an einem benutzerdefinierten UDT in SQLCLR arbeite und die binäre Reihenfolge der Bytes dort eine Rolle zu spielen scheint, aber diese integrierten Typen scheinen viel flexibler zu sein. Verfügt SQL Server über etwas Internes, bei dem jeder Typ seinen eigenen Sortieralgorithmus bereitstellen kann? Und wenn ja, gibt es eine Möglichkeit, diese für meine benutzerdefinierte UDT zu nutzen?

Siehe auch eine verwandte (aber andere) Frage zu StackOverflow.

Matt Johnson-Pint
quelle
Haben Sie versucht zu implementieren IComparable? Sie sollten sich niemals mit der internen Darstellung der Datentypen befassen müssen.
Jon Seigel
Nach diesem (nach unten scrollen , um „einen UDT mit einem benutzerdefinierten Format Implementierung“), Sie können implementieren IComparable, aber es ist nur die clientseitige verwendet. SQL Server ignoriert dies und verlässt die Bytereihenfolge.
Matt Johnson-Pint
Oh. Nun, das ist nervig.
Jon Seigel
@PaulWhite - Das ist in der Tat nützlich. Zumindest ist es eine Bestätigung dessen, was ich erlebe. Vielen Dank!
Matt Johnson-Pint
@PaulWhite - Der Teil, den er in diesem Artikel nicht behandelt, ist das Entfernen des führenden Bytes für die Null. Warum sollte ein int in 5 Bytes gespeichert werden müssen?
Matt Johnson-Pint

Antworten:

2

SQL Server verlässt sich bei seinen "eigenen" Datentypen nicht auf die binäre Reihenfolge. Für CLR-Datentypen können Sie die iComparable-Schnittstelle verwenden, aber wie @MattJohnson erwähnt, ignoriert SQL Server dies:

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


Microsoft veröffentlicht keine Details darüber, wie die verschiedenen Datentypen gespeichert und verarbeitet werden. In Books Online wird jedoch ausdrücklich darauf hingewiesen, dass Sie sich für einen bestimmten Datentyp nicht auf ein bestimmtes Binärformat verlassen können und dass sich das verwendete Format jederzeit ändern kann. Es ist daher eine gute Idee, ein INT als genau das und nicht als VARBINARY zu speichern, da Sie Ihre Daten nach dem nächsten SP möglicherweise nicht mehr lesen können.

Was die Sortierung betrifft: Der größte Teil des SQL Server-Kerns ist in C ++ geschrieben. Ich gehe davon aus, dass intern eine Methode ähnlich einer iComparable verwendet wird. Aber auch hier gibt es keine öffentlich zugängliche Dokumentation dazu. Selbst wenn dies der Fall wäre, könnten Sie es wahrscheinlich aufgrund der inhärenten Unterschiede zwischen .NET und C ++ nicht ausnutzen.

Sebastian Meine
quelle
Die andere dort erwähnte Ausgabenummer war ebenfalls informativ. Aber haben Sie irgendwelche Details darüber, wie die internen Typen es tun?
Matt Johnson-Pint
@ MattJohnson, siehe mein Update oben. Ich fürchte, es ist nicht das, wonach Sie gesucht haben ...
Sebastian Meine
Sie empfehlen also, SQL intals Hintergrundfeld für meine CLR-UDT zu verwenden? Haben Sie ein Beispiel dafür? Die CREATE TYPEAnweisung benötigt eine base_typeoder eine externe Assembly - aber nicht beide.
Matt Johnson-Pint
Nein, das war nur ein Beispiel. Was ich damit sagen möchte, ist, dass Sie einen Weg finden müssen, um Ihr UDT zu serialisieren, damit es binär sortiert werden kann, da es derzeit keine Möglichkeit gibt, eine iComparable-Schnittstelle (oder eine ähnliche) zu implementieren und SQL Server verwenden zu lassen.
Sebastian Meine