it-swarm.com.de

Bevorzugte Methode zum Speichern von DateTime

Wir können Datums- und Uhrzeitinformationen auf verschiedene Arten speichern. Was ist der beste Ansatz zum Speichern von DateTime-Informationen?

Speichern von Datum und Uhrzeit in 2 separaten Spalten oder einer Spalte mit DateTime ?

Können Sie erklären, warum dieser Ansatz besser ist?

(Link zu MySQL-Dokumenten als Referenz, die Frage ist allgemein und nicht spezifisch für MySQL)
Datums- und Uhrzeittypen: Datum und Uhrzeit

19
Julian

Das Speichern der Daten in einer einzelnen Spalte ist der bevorzugte Weg, da sie untrennbar miteinander verbunden sind. Ein Zeitpunkt ist eine einzelne Information, nicht zwei.

Eine übliche Methode zum Speichern von Datums-/Zeitdaten, die von vielen Produkten "hinter den Kulissen" verwendet wird, besteht darin, sie in einen Dezimalwert umzuwandeln, wobei das "Datum" der ganzzahlige Teil des Dezimalwerts und die "Uhrzeit" der Bruchteil ist Wert. Also, 1900-01-01 00:00:00 wird als 0.0 und 20. September 2016 um 9:34:00 als 42631.39861 gespeichert. 42631 ist die Anzahl der Tage seit dem 01.01.1900. 39861 ist der Teil der Zeit, der seit Mitternacht vergangen ist. Verwenden Sie dazu keinen direkten Dezimaltyp, sondern einen expliziten Datums-/Uhrzeittyp. Mein Punkt hier ist nur eine Illustration.

Wenn Sie die Daten in zwei separaten Spalten speichern, müssen Sie beide Spaltenwerte jederzeit kombinieren, um festzustellen, ob ein bestimmter Zeitpunkt früher oder später als der gespeicherte Wert liegt.

Wenn Sie die Werte separat speichern, werden Sie immer auf "Fehler" stoßen, die schwer zu erkennen sind. Nehmen Sie zum Beispiel Folgendes:

IF OBJECT_ID('tempdb..#DT') IS NOT NULL
DROP TABLE #DT;
CREATE TABLE #DT
(
    dt_value DATETIME NOT NULL
    , d_value DATE NOT NULL
    , t_value TIME(0) NOT NULL
);


DECLARE @d DATETIME = '2016-09-20 09:34:00';

INSERT INTO #DT (dt_value, d_value, t_value)
SELECT @d, CONVERT(DATE, @d), CONVERT(TIME(0), @d);

SET @d = '2016-09-20 11:34:00';

INSERT INTO #DT (dt_value, d_value, t_value)
SELECT @d, CONVERT(DATE, @d), CONVERT(TIME(0), @d);

/* show all rows with a date after 2016-07-01 11:00 am */
SELECT *
FROM #DT dt
WHERE dt.dt_value >= '2016-07-01 11:00:00';

/* show all rows with a date after 2016-07-01 11:00 am */
SELECT *
FROM #DT dt
WHERE dt.d_value >= CONVERT(DATE, '2016-07-01')
    AND dt.t_value >= CONVERT(TIME(0), '11:00:00');

Im obigen Code erstellen wir eine Testtabelle, füllen sie mit zwei Werten und führen dann eine einfache Abfrage für diese Daten durch. Das erste SELECT gibt beide Zeilen zurück, das zweite SELECT gibt jedoch nur eine einzelne Zeile zurück, was möglicherweise nicht das gewünschte Ergebnis ist:

(enter image description here

Die richtige Methode zum Filtern eines Datums-/Zeitbereichs, in dem sich die Werte in diskreten Spalten befinden, wie von @ypercube in Kommentaren angegeben, ist:

WHERE dt.d_value > CONVERT(DATE, '2016-07-01') /* note there is no time component here */
    OR (
        dt.d_value = CONVERT(DATE, '2016-07-01') 
        AND dt.t_value >= CONVERT(TIME(0), '11:00:00')
    )

Wenn Sie die Zeitkomponente für zur Analyse trennen möchten, können Sie eine berechnete, persistente Spalte für den Zeitteil des Werts hinzufügen:

ALTER TABLE #DT
ADD dt_value_time AS CONVERT(TIME(0), dt_value) PERSISTED;

SELECT *
FROM #dt;

(enter image description here

Die persistierte Spalte könnte dann indiziert werden, um schnelle Sortierungen usw. nach Tageszeit zu ermöglichen.

Wenn Sie erwägen, Datum und Uhrzeit zu Anzeigezwecken in zwei Felder aufzuteilen, sollten Sie sich darüber im Klaren sein, dass die Formatierung auf dem Client und nicht auf dem Server erfolgen sollte.

23
Max Vernon

Ich werde den anderen Antworten eine abweichende Meinung geben.

Wenn sowohl die Datums- als auch die Uhrzeitkomponente zusammen benötigt werden, dh ein Eintrag ungültig ist, wenn er eine, aber nicht die andere enthält (oder in einer, aber nicht in der anderen NULL ist), ist das Speichern in einer einzelnen Spalte aus den in anderen angegebenen Gründen sinnvoll Antworten.

Es kann jedoch vorkommen, dass eine oder beide Komponenten einzeln optional sind. In diesem Fall wäre es falsch, es in einer einzelnen Spalte zu speichern. Dies würde Sie zwingen, NULL-Werte auf beliebige Weise darzustellen, z. Speichern der Uhrzeit als 00:00:00.

Hier einige Beispiele:

  • Sie erfassen Fahrzeugfahrten für Meilensteuerabzüge. Die genaue Zeit der Reise zu kennen, wäre nützlich, aber wenn ein Mitarbeiter sie nicht notiert und vergessen hat, sollte das Datum immer noch selbst aufgezeichnet werden (erforderliches Datum, optionale Zeit).

  • Sie führen eine Umfrage durch, um herauszufinden, wann die Leute zu Mittag essen, und Sie bitten die Teilnehmer, ein Formular mit einer Stichprobe ihrer Mittagspausen einschließlich der Daten auszufüllen. Einige geben das Datum nicht ein, und Sie möchten die Daten nicht verwerfen, da dies die Zeiten sind, die Ihnen wirklich wichtig sind (optionales Datum, erforderliche Zeit).

Siehe diese verwandte Frage für alternative Ansätze.

11
JBentley

Ich werde es immer vorziehen, das als einzelne Spalte zu speichern, es sei denn, es gibt eine bestimmte Geschäfts-/Anwendungsanforderung. Unten sind meine Punkte -

  • Das Extrahieren der Zeit aus dem Zeitstempel ist kein Problem
  • Warum nur für die Zeit eine zusätzliche Spalte hinzufügen, wenn wir beide zusammen speichern können?
  • Um zu vermeiden, dass bei jeder Abfrage Datum und Uhrzeit hinzugefügt werden.
5
Ashwini Mohan

In SQL Server ist es am besten, DataTime als ein Feld zu speichern. Wenn Sie einen Index für die DataTime-Spalte erstellen, kann dieser als Datumssuche und als DateTime-Suche verwendet werden. Wenn Sie daher alle Datensätze einschränken müssen, die für das jeweilige Datum vorhanden sind, können Sie den Index weiterhin verwenden, ohne etwas Besonderes tun zu müssen. Wenn Sie nach dem Zeitanteil abfragen müssen, können Sie nicht denselben Index verwenden. Wenn Sie also einen Business Case haben, bei dem Ihnen die Uhrzeit wichtiger ist als DateTime, sollten Sie ihn separat speichern, da Sie ihn erstellen müssen einen Index darauf und verbessern die Leistung.

3

Schade, dass es dafür keinen Standard-DBMS-übergreifenden Typ gibt (wie INT und VARCHAR für Ganzzahlen und Zeichenfolgenwerte). Die beiden datenbankübergreifenden Ansätze, die ich bisher kennengelernt habe, verwenden VARCHAR/CHAR-Spalten, um DataTime-Werte als Zeichenfolgen zu speichern, die gemäß dem ISO 8601-Standard (bequemer, für Menschen lesbar) formatiert sind, und BIGINT, um sie als POSIX-Zeitstempel zu speichern (mehr gespeichert) effizient, schneller und einfacher mathematisch zu manipulieren).

1
Ivan

Nach dem Lesen einiger Dinge scheint die UTC-Unix-Zeit in BIGINT die optimale Lösung zu sein. TZDB timesone ID in VARCHAR für die Speicherung von Zeitzonen, falls erforderlich. Einige Argumente:

  1. TIMESTAMP und DATETIME führen im Hintergrund eine Reihe kniffliger Konvertierungen durch, die komplex und unklar zu sein scheinen. Der Server wechselt manchmal von der Ortszeit zur UTC oder zur Serverzeit und zurück oder nicht. Eine Menge versteckter Gemeinkosten für jede Funktion.

  2. BIGINT (8 KB) ist mindestens so leicht oder leichter als DECIMAL, das für die Speicherung im Format xxxxxx.xxxxxx erforderlich ist. Dies ist praktisch als zwei INTs + etwas von MySQL gespeichert . Und es reicht aus, um Jahrhunderte vor uns zu lagern.

  3. Nahezu alle gängigen Programmiersprachen verfügen über Bibliotheken mit Standardfunktionen für die Arbeit mit Unix-Zeit.

  4. Mathematische Operationen mit BIGINT sollten so schnell oder schneller sein als alles andere auf jeder Hardware.

All dies ist natürlich für große internationale Projekte relevant. Für etwas Kleines scheint es gut genug zu sein, das Standardformat des gewählten Frameworks zu verwenden.

0
Arthur Tarasov