MySQL Monat in Datenbank speichern

Blandorin

Well-known member
ID: 91067
L
21 April 2006
873
101
Hallo,

verschiedene monatlich anfallende Datensätze möchte ich in einer Datenbank speichern. Neben den Daten selbst möchte ich auch den dazugehörigen Monat speichern.

Soll ich den Monat im Format

1.) daten | monat | jahr

oder

2.) daten | timestamp (z.B. des 1. des Monats)

speichern?

Es ist so eine kleine Sache, aber ich habe schon lange drüber nachgedacht 8)
Mir fallen für beide Strukturen gute Gründe ein.
Grob, damit ich euch nicht die Argumente wegnehme:
1.) speichert genau das, was gespeichert werden soll
2.) ist flexibler

Irgendwelche sinnvollen Kommentare? Ideen, Anregungen, Diskussionen erwünscht!
 
Ohne entscheiden zu wollen, welche Möglichkeit die bessere ist:
Wie siehts mit curdate() aus? Also Quasi
Daten | Date
 
Entweder (TINYINT, SMALLINT) als Monat und Jahr, oder DATE.
Der DATE-Datentyp in MySQL kann auch mit ungültigen Daten ohne Tag, z.B. '2010-01-00' umgehen.

Speicherbedarf is bei beiden Varianten 3 Bytes. Vorteil der Ints, du kannst getrennt Indizes setzen, wenn erforderlich. Vorteil von DATE, dass du einfach die Datumsfunktionen zum Rechnen benutzen kannst.
 
Was ich sonst ganz gerne mach ist ein einfacher Integer mit Ymd oder in deinem Fall Ym. Einfach mit date("Ym", $timestamp) die Zahl erstellen (ja, theHacker ich weiss es ist ein String aber es wird in der Query sowieso als integer interpretiert) und schon hast du ein menschen leserliches Datum, das einfach sortiert werden kann. Ausserdem kann man so sehr simpel kollisionen feststellen (die Spalte als unique deklarieren) und sicherstellen dass immer nur ein eintrag pro monat vorhanden ist.

Ich hab' damit meine gesamten timeseries programmiert so a la:
axis|value|lock
lock ist nicht nur das Datum zum Wert sondern versichert auch dass immer nur exakt ein Wert pro tag gespeichert wird (siehe ON DUPLICATE @ MySQL Docu).

HTH
 
@Snyke:
Ich hab jetzt erst 3x lesen müssen, um überhaupt zu kapieren, was du meinst...

Sehr gefährlich und nicht zu empfehlen 8O Das geht die nächsten 7989 Jahre gut und danach kracht alles zusammen. Du verschwendest Speicherplatz, weil du in deinem Integer die Zehner- und Einer-Stelle nur mit dem Wertebereich 1-12 füllst.

Da kannst du genauso gut zwei Einzelattribute verwenden, wie ich es vorgeschlagen hab. Verschwendet ebenso Speicher, es kracht aber niemals, jemand der den Code warten muss, wird nicht die Hände überm Kopf zusammenschlagen, du kannst ordentliche Abfragen machen, ohne mit Modulo rumrechnen zu müssen und doppelte Daten können ebenfalls per UNIQUE-Index detektiert werden.
 
Also prinzipiell lässt sich das nicht so einfach beantworten, denn es ist abhängig von deinen Bedürfnissen:

1. Möglichkeit:
Du möchtest das Datum einfach nur abspeichern und wieder laden, dann ist die beste Möglichkeit einen MySQL-Timestamp zu nutzen, da du mit diesem auch MySQL-Datums-Funktionen nutzen kannst, du hast also ein perfektes Format für Ein- und Ausgabe mit maximalen Darstellungsmöglichkeiten.

2. Möglichkeit:
Neben dem simplen Abspeichern der Daten möchtest du noch Statistiken generieren wie:
  • Wieviele Einträge habe ich, die im Dezember 2009 erstellt wurden
  • Wieviele Einträge habe ich, die am 1. jeden Monats erstellt wurden
Da du dich bei der 2. Statistik auf einen genauen Tag eines Monats beziehst, ist es am sinnvollsten die Datumsinformation so gestückelt zu speichern wie du sie für die Statistik brauchst, also: Tag | Monat | Jahr
Solltest du noch abfragen wollen, wie es mit Montagen aussieht, erweiterst du dein Datum noch um die Wochentagsinfo: Wochentag | Tag | Monat | Jahr.
Für diesen Anwendungsfall ist dies die beste Art der Speicherung.

@ Synke: Tut mir leid, aber das ist die dämlichste Art der Datumspeicherung, die ich je gehört habe. Nimm einen MySQL-Timestamp und lese ihn mit den Datumsfunktionen in einem Format aus, wie es dir beliebt, aber jedem der mir so ein Modell für die Datumsspeicherung vorgelegt hätte, hätte ich das Papier auf dem es geschrieben steht um die Ohren gehauen.
 
Vielen Dank fuer eure "konstruktive" Kritik, ich find meine Methode durchaus mehr als gueltig.
  1. @theHacker: erstmal herzlichen Glueckwunsch dass du das Gefuehl hast dein Code werde in 7989 jahren noch verwendet, es hat niemand gesagt dass es auf 6 stellen limitiert sein muss, und es hat niemand behauptet integers muessten immer konsekutiv durchnummeriert werden.
  2. Speicherplatz wird keiner verschwendet weil MySQL alle Integer auf eine ganze bytezahl padded (siehe Filesysteme unter Linux).
  3. Hoechstens wird dadurch dass du ein unique constraint ueber zwei felder erstreckst, und dadurch ein index aufgebaut wird, mehr speicherplatz verschwendet, aber das ist auch wieder im zweistelligen bitbereich.
  4. @ice-breaker: mein Ziel ist es in erster Linie kollisionen bei mehreren eintraegen pro monat/tag hervorzurufen, und somit doppelte datensaetze zu vermeiden. Dein Ansatz erst mit Datumsfunktionen auf ein gemeinsames Format zu konvertieren um dann damit zu vergleichen ist zwar wesentlich schoener, hat aber ein riesen problem denn um diese vergleiche machen zu koennen muessen erstmal alle werte materialisiert werden oder du machst range anfragen (z.B.: 2010/01/20 00:00:00 - 2010/01/20 23:59:59) was die queries ungleich laenger machen. So oder so wird toll mit Zahlen jongliert.
  5. Jeder mit etwas gesundem menschenverstand kann meine Daten lesen, wobei ich bezweifle dass du auf einen Blick erkennst dass 1264037690 fuer das heutige Datum steht.
  6. Mit strtotime() kann man easy meine Daten in timestamps umwandeln und dann damit spielen.
Und ja in jedem anderen Fall haette ich auch unix timestamps verwendet, nur dass diese dann nicht die obengenannten kollisionen hervorrufen.
 
Ich habe mich in dem entsprechenden Fall für die Abspeicherung des Monats und des Jahres in zwei getrennten Spalten entschieden. Die statistische Auswertung ist in solch einem Fall vermutlich am einfachsten. (Beispiel: Gehaltszahlungen pro Monat. Auswertung: laufende Ausgaben, Ausgaben im Monat X)

In einem anderen Fall ist es schwieriger: User können sich einmal im Monat einen Bonus einlösen. Ich würde später gerne herausfinden, in welchem Monat wieviel Bonus eingelöst wurde. Dies spräche erneut für die getrennte Speicherung von Monat und Jahr.
Allerdings möchte ich in diesem Fall auch wissen, wann der User den Bonus eingelöst hat. Also muss der Timestamp gespeichert werden. Die zusätzliche Speicherung des Monats scheint dann nicht mehr sinnvoll, so dass ich hier also nur den Timestamp speichere und bei der Auswertung etwas mehr Aufwand benötige.