Wie speichert man "unscharfe Daten" in einer Datenbank?


125

Dies ist ein Problem, auf das ich einige Male gestoßen bin. Stellen Sie sich vor, Sie haben einen Datensatz, den Sie in einer Datenbanktabelle speichern möchten. Diese Tabelle enthält eine DateTime-Spalte mit dem Namen "date_created". Dieser eine Datensatz wurde vor langer Zeit erstellt, und Sie sind sich nicht sicher, wann er genau sein soll, aber Sie kennen Jahr und Monat. Andere Aufzeichnungen kennen Sie nur das Jahr. Andere Aufzeichnungen kennen Sie den Tag, den Monat und das Jahr.

Sie können kein DateTime-Feld verwenden, da "Mai 1978" kein gültiges Datum ist. Wenn Sie es in mehrere Spalten aufteilen, verlieren Sie die Abfragefähigkeit. Hat jemand anderes darauf gestoßen, wenn ja, wie sind Sie damit umgegangen?

Um das von mir erstellte System zu verdeutlichen, handelt es sich um ein System, das Archive verfolgt. Einige Inhalte wurden vor langer Zeit produziert und alles was wir wissen ist "Mai 1978". Ich könnte es als 1. Mai 1978 speichern, aber nur mit einem Hinweis darauf, dass dieses Datum nur auf den Monat genau ist. Auf diese Weise bin ich einige Jahre später beim Abrufen dieses Archivs nicht verwirrt, wenn die Daten nicht übereinstimmen.

Für meine Zwecke ist es wichtig, den "unbekannten Tag im Mai 1978" vom "1. Mai 1978" zu unterscheiden. Außerdem möchte ich die Unbekannten nicht als 0 speichern, wie zum Beispiel "May 0, 1978", da die meisten Datenbanksysteme dies als ungültigen Datumswert ablehnen.


14
Ist es wichtig, den "unbekannten Tag im Mai 1978" vom "1. Mai 1978" zu unterscheiden?

5
@MichaelT: ja, es ist wichtig zu unterscheiden.
nbv4


6
@aslum: Die meisten Datenbanksysteme weisen dies als ungültigen Datumswert zurück
nbv4

9
@JimmyHoffa - Sie haben noch nie ein Szenario mit verschwommenen Daten erlebt oder ein Szenario, in dem Sie Daten vergleichen mussten? In beiden Fällen ist eine häufige Anamnese eine Anamnese: Sie erinnern sich, dass die Blinddarmentfernung letztes Jahr am 1. April stattfand, die Mandelentfernung jedoch 1975 und etwas anderes im Mai und Juni eines Jahres. Was ist, wenn Sie wissen möchten, ob ein medizinisches Ereignis vor oder nach einem anderen medizinischen Durchbruch stattgefunden hat? Ist das passiert, bevor oder nachdem sie die Blutversorgung auf HIV überprüft haben?
Donnerstag

Antworten:


148

Speichern Sie alle Daten im normalen DATE-Feld in der Datenbank und geben Sie zusätzlich an, wie genau das DATE-Feld tatsächlich ist.

date_created DATE,
date_created_accuracy INTEGER, 

Erstellungsdatum_genauigkeit: 1 = genaues Datum, 2 = Monat, 3 = Jahr.

Wenn Ihr Datum unscharf ist (z. B. Mai 1980), speichern Sie es zu Beginn des Zeitraums (z. B. 1. Mai 1980). Oder wenn Ihr Datum auf das Jahr (zB 1980) genau ist, speichern Sie es als 1. Januar. 1980 mit entsprechendem Genauigkeitswert.

Auf diese Weise können Sie leicht auf eine etwas natürliche Weise abfragen und wissen immer noch, wie genau die Daten sind. Auf diese Weise können Sie beispielsweise Daten zwischen Jan 1st 1980und abfragen Feb 28th 1981und unscharfe Daten 1980und abrufen May 1980.


1
Sie müssen das Datumsende hier noch anhand der angezeigten Informationen berechnen. Daher ist die Abfrage zwischendurch meiner Meinung nach ziemlich hässlich, da Sie ein berechnetes Feld haben, für das Sie am besten eine Auswahl treffen.
Wyatt Barnett

8
Schöne Antwort, sehr schlau. select * from mytable where date_created between "1980/1/1" and "1981/2/28" and date_created_accuracy <= 2;. Genius.
Naftuli Kay

58
Ich möchte Sie ermutigen, die Datumsgenauigkeit einfach als "Tage" zu betrachten. Wobei ein genauer Tag 0 ist. Auf diese Weise können flexiblere Daten "Irgendwann im Sommer" mit einer Datumsgenauigkeit von 90 Tagen ab dem 1. Juni anstelle von fest codierten spezifischen Datumsbereichen verwendet werden. Es könnte auch eine mehrjährige Genauigkeit bewältigen.

1
Du solltest das vielleicht als Antwort einreichen,
MichaelT

1
+1: Eine weitere nette Sache bei dieser Lösung ist, dass Sie dann Anzeigelogik basierend auf dem Feldwert hinzufügen können date_created_accuracy. Sie können "Mai 1980" oder nur "1980" in den Ergebnissen oder in der Benutzeroberfläche anzeigen, wenn dies so genau ist, wie es das Feld angibt.
Kyralessa,

27

Wenn Sie diese Art von Daten nicht als reguläre Datums- / Uhrzeitinformationen verwenden müssen, ist ein einfaches Zeichenfolgenformat ausreichend.

Wenn Sie jedoch die gesamte Funktionalität beibehalten müssen, kann ich mir zwei Problemumgehungen vorstellen, die beide zusätzliche Informationen erfordern, die in der Datenbank gespeichert sind:

  1. Erstellen Sie min dateund max dateFelder, die unterschiedliche Werte für "unvollständige" Daten haben, aber für genaue Daten übereinstimmen.
  2. Erstellen Sie Typen für jede Art von ungenauem Datum (keine _ 0, Datum_abgabe _ 1, Monat_abgabe _ 2, Jahr_abgabe_4 usw. _, damit Sie sie kombinieren können). Fügen Sie typeden Datensätzen ein Feld hinzu, und behalten Sie bei, welche Informationen fehlen.

Min- und Max-Datumsfelder waren auch mein erster Gedanke.
Michael Itzoe

1
Vor langer Zeit mussten wir genau das gleiche Problem lösen. Die Benutzer konnten Geschichten über Ereignisse erzählen, die zu jeder Zeit in der Vergangenheit stattfanden, sodass wir Fuzzy-Daten unterstützen mussten. Nach langem Hin und Her ähnelt die Lösung, zu der wir gekommen sind, am ehesten dem Vorschlag von superM, in dem Datumsangaben als die minimalen und maximalen möglichen Momente gespeichert werden, die das Datum der Story enthalten würden. Beim Melden des Datums kann die Genauigkeit (dh "dieser Datensatz ist auf den Monat / das Jahr / den Tag genau") aus dem Delta zwischen den Min- und Max-Daten extrahiert werden. Es ist nicht erforderlich, ein drittes Feld für die Genauigkeit zu speichern.
Meetamit

4
+1 für min dateund max dateFelder. Ich denke, das ist die flexibelste, aber genaueste und benutzerfreundlichste Lösung.
Supr

1
Anfangs war ich gegen diese Idee. Ich stimme dafür, weil mir klar ist, dass dies der flexibelste Ansatz ist.
Anurag Kalia

Es ist nur natürlich. Sie beschreiben nicht so sehr ein verschwommenes Datum, sondern einen Zeitrahmen, der einen Anfang und ein Ende hat.
Pieter B

20

Dies ist eher eine Anforderungsdefinition als ein technisches Problem. Sie müssen sich auf die Frage konzentrieren, "wie wir die Daten in der Vergangenheit definieren können" und die technische Lösung wird fließen.

Die Zeiten, in denen ich mich so etwas nähern musste, haben wir normalerweise:

  • Definieren Sie, wie Sie Dinge zuordnen möchten - wie MichaelT vorschlägt , entscheiden Sie, dass alles, was als Monat / Tag definiert ist, am 1. des Monats als Mitternacht definiert wird. Dies ist normalerweise für die meisten Zwecke gut genug - wenn das genaue Datum so wichtig wäre, hätten Sie wahrscheinlich 35 Jahre später eine Aufzeichnung davon, oder?
  • Finden Sie heraus, ob Sie dies nachverfolgen müssen - Brauchen Datensätze mit leicht nachgebildeten Erstellungsdaten eine entsprechende Markierung? Oder ist das nur eine Frage der Benutzerschulung, damit die Leute es wissen und entsprechend handeln können.

Manchmal muss man so etwas tun, wie die Daten unscharf zu machen - zum Beispiel, dass ein Datum möglicherweise im Mai 1978 auf eine Anfrage nach irgendetwas antworten muss Die Tage verteilen sich entsprechend, neue erhalten 2 identische Werte.


1
+1 - Ich habe daran gearbeitet, eine Antwort mit dem Double-Date-Ansatz zu formulieren. Deine Antwort kam zuerst hierher.

2
+1, Es ist hässlich und erzeugt eine Menge unnützer Zusatzinformationen für die neuen Einträge, für die es nicht erforderlich ist. Andererseits werden die Abfragen dadurch viel einfacher als sonst. Wir verwenden bereits seit einiger Zeit eine ähnliche Lösung für ein ähnliches Problem.
Izkata

3
@Izkata - Guter Punkt, aber wie elegant können Sie werden, wenn Sie etwas machen müssen, das ein einziger Zeitpunkt im Monat sein sollte. Sicher schöner, als den Anfang und das Ende von Abfragen irgendwo im Fluge berechnen zu müssen.
Wyatt Barnett

1
+1 für die Fähigkeit, willkürliche Granularität ohne eine Explosion von Aufzählungswerten zu bezeichnen.
Dan Neely

18

Der einfachste Weg, um anzuzeigen, ob das Datum korrekt ist, besteht darin, ein Genauigkeitsfeld INT (1) mit dem Standardwert NULL zu erstellen

Wenn das Datum korrekt ist, speichern Sie die Datums- / Uhrzeitangabe in "date_created" und lassen Sie die Genauigkeit NULL

Wenn das Datum nur auf den Monat genau ist, speichern Sie Datum und Uhrzeit als 1. des Monats mit dem Genauigkeitswert 1

Wenn das Datum nur für das Jahr korrekt ist, speichern Sie das Datum und die Uhrzeit am 1. Januar mit dem Genauigkeitswert 2

Sie können verschiedene Zahlen verwenden, um verschiedene Werte wie das erste Quartal usw. Zu speichern


Fragen werden wirklich haarig, wenn Sie das tun.
Blrfl

3
Dies hat Schwierigkeiten mit Daten, die nicht an einer sauberen Monatsgrenze liegen, wie "Q2 1991" und "Winter 1978-1979".

1
OP möchte auf irgendeine Weise anzeigen, dass dieses Datum nur auf den Monat genau ist.
David Strachan

7
Sie missbrauchen hier die Bedeutung von NULL. NULL bedeutet "unbekannt". Wenn also das Datum korrekt ist, kann die Genauigkeit nicht NULL sein. Es kann "1" sein.
Konerak

@Konerak Semantisch ja. Da die meisten Datumsangaben jedoch korrekt sind, müssen nur die Sonderfälle identifiziert werden, und hier wird standardmäßig NULL verwendet.
David Strachan

17

In der Vergangenheit habe ich Datumsangaben mit Genauigkeit als Start- und Enddatum gespeichert. Der Tag 21.05.2012 würde als Start = 12.00 Uhr, 21.05.2012 und Ende = 12.00 Uhr, 22.05.2012 dargestellt. Das Jahr 2012 wird als Start = 12.00 Uhr, 1. Januar 2012 und Ende = 12.00 Uhr, 1. Januar 2013 dargestellt.

Ich bin mir nicht sicher, ob ich diesen Ansatz empfehlen würde. Wenn Sie dem Benutzer die Informationen anzeigen, müssen Sie richtig erkennen, dass ein Datumsbereich genau einen Tag abdeckt, um "25. Mai" anstelle von zwei überbestimmten Endpunkten anzuzeigen (was bedeutet, dass Sie sich mit Sommerzeit usw. befassen müssen).

Wenn Sie jedoch nicht versuchen, in eine menschliche Sprache zu übersetzen, ist das Programmieren mit den Endpunkten viel einfacher als mit der Genauigkeit von center +. Sie haben nicht viele Fälle. Das ist ziemlich nett.


Tatsächlich muss es nicht so schwierig sein, zu bestimmen, wie ein Bereich dargestellt werden soll, wenn der Bereich immer als UTC gespeichert ist. Als UTC-Zeitstempel haben jeder Tag, jede Woche, jeder Monat, jedes Jahr - auch Jahreszeiten und Quartale - zwei konstante, globale, eindeutige und leicht bestimmbare Zahlen, die den Beginn und das Ende des Zeitraums darstellen. Die Logik wird einfach zu ein paar if-Anweisungen, um festzustellen, ob die beiden Daten am Anfang und am Ende eines bestimmten Zeitraums liegen. Keine komplizierten mathematischen oder
zeitzonenbezogenen Aufgaben

@Supr Die Bestimmung, ob eine bestimmte Sekunde an der Grenze einer bestimmten menschlichen Periode liegt, ist an sich ein schwieriges Problem. Besonders auf lange Sicht, wenn die Erdrotation langsamer wird und endlose kleine Änderungen an der menschlichen Definition der lokalen Zeit eintreten.
Craig Gidney

14

Warum nicht zwei Daten speichern.

Created_After und Created_Before. Die eigentliche Semantik wird "erstellt am oder nach" und "erstellt am oder vor"

Wenn Sie also das genaue Datum kennen, sind Created_After und Created_Before dasselbe Datum.

Wenn Sie wissen, dass es die erste Woche im Mai 2000 war, sind Created_After = '2000-05-01' und Created_Before = '2000-05-07'.

Wenn Sie nur den Mai 1999 kennen, sind die Werte '1999-05-01' und '1999-05-30'.

Wenn es "Summer of '42" ist, lauten die Werte "1942-06-01" und "1942-08-31".

Dieses Schema ist mit normalem SQL einfach abzufragen und für einen nicht technischen Benutzer recht einfach zu befolgen.

So finden Sie beispielsweise alle Dokumente, die möglicherweise im Mai 2001 erstellt wurden:

SELECT * FROM DOCTAB WHERE Created_After < '2001-05-31' And Created_Before > 2001-05-01;

Umgekehrt finden Sie alle Dokumente, die definitiv im Mai 2001 erstellt wurden:

SELECT * FROM DOCTAB WHERE Created_After > '2001-05-01' And Created_Before < 2001-05-31;

1
Ich denke, das ist die eleganteste Lösung.
Pieter B

Dies entspricht den Antworten von superM und Strilanc. +1, um dies deutlicher zu erklären und zu zeigen, wie einfach die Abfrage wäre.
Supr

9

Das Datums- und Uhrzeitformat nach ISO 8601 wird mit einer Definition der Dauer geliefert, z

2012-01-01P1M (lesen Sie: 2012, 1. Januar, Zeitraum: 1 Monat) ist das, was "im Januar 2012" sein sollte.

Ich würde dies verwenden, um die Daten zu speichern . Möglicherweise benötigen Sie dazu ein Datenbankfeld vom Typ String. Es ist ein anderes Thema, wie man eine vernünftige Suche danach durchführt.


+1 für die Idee, aber -1 für die
Nichtverwendung

Kommt auf die Datenbank an. Dies kann jedoch eine Basis für die Erweiterung sein, aber die Frage ist: Befindet sich das Dokument in der Ergebnismenge, wenn Sie in diesem Fall alle Dokumente durchsuchen, die neuer als der 12. Januar sind, oder nicht? Es ist nicht trivial. Hier stellte sich die Frage, wie Fuzzy-Daten gespeichert werden sollen .
Matthias Ronge

3

Im Allgemeinen speichere ich sie immer noch als Datum für allgemeine Abfragen. Dies ist immer noch möglich, auch wenn dies etwas weniger genau ist.

Wenn es wichtig ist, die Genauigkeit zu kennen, habe ich in der Vergangenheit entweder ein Genauigkeits- "Fenster" als +/- Dezimalzahl oder als Nachschlag (Tag, Monat, Jahr usw.) gespeichert. In anderen Fällen speichere ich anstelle des Fensters nur den ursprünglichen Datumswert als Zeichenfolge und konvertiere, was ich kann, in eine Datums- / Uhrzeitangabe, möglicherweise 1978-05-01 00:00:00 und "Mai 1978" für Ihr gegebenes Beispiel.


3

Wenn Sie es in mehrere Spalten aufteilen, verlieren Sie die Abfragefähigkeit.

Sagt wer? Folgendes machst du:

  1. Haben Sie 3 Spalten, Tag, Monat, Jahr, jede vom Typ int und eine vierte Spalte vom Typ TheDate of DateTime.
  2. Verwenden Sie einen Trigger, der die 3 Spalten Tag, Monat und Jahr verwendet, um TheDate zu erstellen, wenn TheDate null bleibt, aber eines oder mehrere der Felder Tag, Monat und Jahr einen Wert haben.
  3. Haben Sie einen Auslöser, der die Felder "Tag", "Monat" und "Jahr" ausfüllt, wenn das Datum angegeben wird, diese Felder jedoch nicht.

Wenn ich also ein Insert wie: insert into thistable (Day, Month, Year) values (-1, 2, 2012);mache, wird TheDate zum 01.02.2013, aber ich weiß, dass das Datum in 2/2012 wirklich unbestimmt ist, da im Feld „-1“ ein Tag steht.

Wenn ich insert into thistable (TheDate) values ('2/5/2012');dann Tag 5 bin , Monat 2 ist und Jahr 2012 ist und weil keiner von ihnen -1 ist, weiß ich, dass dies das genaue Datum ist.

Ich verliere nicht die Fähigkeit zur Abfrage, da der Einfüge- / Aktualisierungs-Trigger sicherstellt, dass meine 3 Felder (Tag, Monat, Jahr) immer einen DateTime-Wert in TheDate erzeugen, der abgefragt werden kann.


3

Eine andere Möglichkeit wäre, die Daten als ganze Zahlen des Formulars zu speichern YYYYMMDD.

  • Sie wissen nur, dass das Jahr 1951 ist: Speichern unter 19510000
  • Sie kennen den Monat und das Jahr März 1951: Speichern unter 19510300
  • Sie wissen, dass das vollständige Datum der 14. März 1951 ist: Speichern unter 19510314
  • Ein völlig unbekanntes Datum: Speichern unter 0

Leistungen

Sie können Ihr unscharfes Datum in einem Feld anstelle von zwei Datumsfeldern oder einem Datum und einer Genauigkeit speichern, wie in vielen anderen Antworten vorgeschlagen.

Fragen sind immer noch einfach:

  • alle Rekorde für das Jahr 1951 - SELECT * FROM table WHERE thedate>=19510000 and thedate<19520000
  • alle Rekorde für März 1951 - SELECT * FROM table where thedate>=19510300 and thedate<19510400
  • alle Aufzeichnungen vom 14. März 1951 - SELECT * FROM table where thedate=19510314

ANMERKUNGEN

  • Ihre GUI würde eine benötigen, GetDateString(int fuzzyDate)die ziemlich einfach zu implementieren ist.
  • Das Sortieren ist mit dem int-Format einfach. Sie sollten wissen, dass unbekannte Daten an erster Stelle stehen. Sie können dies umkehren, indem Sie 99anstelle des 00Monats oder des Tages das Auffüllen verwenden .

Wie stellen Sie das unscharfe Datum des "Winters von 1941-1942" dar? Es könnte Dezember 1941 oder Januar 1942 sein.

1
Ihre Frage bezieht sich auf einen allgemeinen Lösungsfall. In der ursprünglichen Frage wird dies nicht als Problem aufgeführt. Anhand der gestellten Frage ist manchmal das vollständige Datum bekannt, manchmal nur das Jahr und der Monat und manchmal nur das Jahr. Die Angabe eines unscharfen Datumsbereichs ist nicht erforderlich. Ich würde zustimmen, dass Sie zwei Daten benötigen, wenn Sie dieses Problem lösen müssen (obwohl das Speichern des Bereichs als zwei "unscharfe Datumsangaben" mehr Flexibilität bieten könnte als das Speichern von zwei "harten" Daten).
Rick

1

ISO 8601 spezifiziert auch eine Syntax für "Fuzzy-Daten". 12. Februar 2012 um 15 Uhr wäre "2012-02-12T15" und Februar 2012 könnte einfach "2012-02" sein. Dies lässt sich mit der lexikografischen Standardsortierung gut erweitern:

$ (echo "2013-03"; echo "2013-03"; echo "2012-02-12T15"; echo "2012-02"; echo "2011") | sort
2011
2012
2012-02
2012-02-12T15
2013-03

0

Hier ist meine Meinung dazu:

Vom unscharfen Datum zum Datum / Uhrzeit-Objekt wechseln (das in eine Datenbank passt)

import datetime
import iso8601

def fuzzy_to_datetime(fuzzy):
    flen = len(fuzzy)
    if flen == 4 and fuzzy.isdigit():
        dt = datetime.datetime(year=int(fuzzy), month=1, day=1, microsecond=111111)

    elif flen == 7:
        y, m = fuzzy.split('-')
        dt = datetime.datetime(year=int(y), month=int(m), day=1, microsecond=222222)

    elif flen == 10:
        y, m, d = fuzzy.split('-')
        dt = datetime.datetime(year=int(y), month=int(m), day=int(d), microsecond=333333)

    elif flen >= 19:
        dt = iso8601.parse_date(fuzzy)

    else:
        raise ValueError("Unable to parse fuzzy date: %s" % fuzzy)

    return dt

Und dann eine Funktion, die das datetime-Objekt aufnimmt und es in ein unscharfes Datum zurückverschiebt.

def datetime_to_fuzzy(dt):
    ms = str(dt.microsecond)
    flag1 = ms == '111111'
    flag2 = ms == '222222'
    flag3 = ms == '333333'

    is_first = dt.day == 1
    is_jan1 = dt.month == 1 and is_first

    if flag1 and is_jan1:
        return str(dt.year)

    if flag2 and is_first:
        return dt.strftime("%Y-%m")

    if flag3:
        return dt.strftime("%Y-%m-%d")

    return dt.isoformat()

Und dann ein Unit Test. Habe ich irgendwelche Fälle verpasst?

if __name__ == '__main__':
    assert fuzzy_to_datetime('2001').isoformat() == '2001-01-01T00:00:00.111111'
    assert fuzzy_to_datetime('1981-05').isoformat() == '1981-05-01T00:00:00.222222'
    assert fuzzy_to_datetime('2012-02-04').isoformat() == '2012-02-04T00:00:00.333333'
    assert fuzzy_to_datetime('2010-11-11T03:12:03Z').isoformat() == '2010-11-11T03:12:03+00:00'

    exact = datetime.datetime(year=2001, month=1, day=1, microsecond=231)
    assert datetime_to_fuzzy(exact) == exact.isoformat()

    assert datetime_to_fuzzy(datetime.datetime(year=2001, month=1, day=1, microsecond=111111)) == '2001'
    assert datetime_to_fuzzy(datetime.datetime(year=2001, month=3, day=1, microsecond=222222)) == '2001-03'
    assert datetime_to_fuzzy(datetime.datetime(year=2001, month=6, day=6, microsecond=333333)) == '2001-06-06'

    assert datetime_to_fuzzy(fuzzy_to_datetime('2002')) == '2002'
    assert datetime_to_fuzzy(fuzzy_to_datetime('2002-05')) == '2002-05'
    assert datetime_to_fuzzy(fuzzy_to_datetime('2002-02-13')) == '2002-02-13'
    assert datetime_to_fuzzy(fuzzy_to_datetime('2010-11-11T03:12:03.293856+00:00')) == '2010-11-11T03:12:03.293856+00:00'

Es gibt einen Eckfall, in dem ein Ereignis, das zwar genau 2001-01-01T00:00:00.333333zum Zeitpunkt des Ereignisses eingetreten ist , vom System jedoch nur als "2001" interpretiert wird, dies jedoch sehr unwahrscheinlich erscheint.


0

Ich arbeite für einen Verlag, der sich mit vielen alten Büchern beschäftigt, bei denen wir oft nicht die genauen Daten für die Dinge bekommen. Wir haben normalerweise zwei Felder für einen bestimmten Datumseintrag, das Datum und einen circa- Booleschen Wert:

date date
dateCirca enum('Y', 'N')

Wir verwenden das Datumsfeld, um das Datum eines Ereignisses anzugeben, oder ein Datum, das "nah genug" ist, falls wir das wahre Datum nicht kennen. Für den Fall, dass wir das wahre Datum nicht kennen, markieren wir das dateCircaFeld als Yund geben ein Datum an, das nah genug ist und als "1." gekennzeichnet ist, wie z

1st March, 2013  // We don't know the day of the month
1st January, 2013  // We don't know the month/day of the year
1st January, 2000  // We don't know the month/day/year, we only know the century

0

Überblick

Es gibt viele mögliche Darstellungen und damit Datenbankschemata zum Speichern von unscharfen Datums- und Uhrzeitangaben (oder auch nur unscharfen Datumsangaben):

  1. Datum, Uhrzeit und Code für die Genauigkeit
  2. Datum, Uhrzeit und Intervall, bei denen es mehrere Möglichkeiten gibt, ein Intervall darzustellen:
    1. Stellen Sie alle Intervalle als Ganzzahl (oder andere numerische Größe) einer festen Einheit dar, z. B. Tage, Minuten, Nanosekunden.
    2. Stellen Sie ein Intervall sowohl als Ganzzahl (oder andere numerische Größe) als auch als Code dar, der die Einheiten angibt.
  3. Start- und Enddatum
  4. String
  5. Wahrscheinlichkeitsverteilung:
    1. Dezimal- oder Gleitkommazahlen für die Parameter, die eine bestimmte Verteilung in einer bestimmten Familie angeben, z. B. Mittelwert und Standardabweichung einer Normalverteilung.
    2. Wahrscheinlichkeitsverteilungsfunktion, z. B. als (Nachschlage-) Code (möglicherweise mit Parametern bestimmter Werte) oder als Ausdruck in einer ausreichend aussagekräftigen Sprache, Format oder Darstellung.

[1], [2] und [3] sind alle (implizit) einheitliche Intervalle, dh eine Menge von (gleich) möglichen Zeitpunkten.

[4] ist am ausdrucksstärksten, dh wenn mögliche (oder zumindest willkürlich lange) geschriebene Sprachsätze oder -phrasen zugelassen werden. Aber es ist auch am schwierigsten, damit zu arbeiten. Im Grenzfall müsste AI auf menschlicher Ebene mit beliebigen Werten umgehen. In der Praxis müsste der Bereich möglicher Werte stark eingeschränkt werden, und alternative "strukturierte" Werte wären wahrscheinlich für viele Operationen, z. B. Sortieren, Suchen, vorzuziehen.

[5] ist wahrscheinlich die allgemeinste kompakte Darstellung, die (etwas) praktisch ist.

Einheitliche Intervalle

Einheitliche Intervalle sind die einfachste kompakte Möglichkeit, eine Reihe von (möglichen) Datums- / Uhrzeitwerten darzustellen.

Bei [1] werden Teile des Datum-Uhrzeit-Werts ignoriert, dh die Teile, die Einheiten entsprechen, die feiner als die angegebene Genauigkeit oder Genauigkeit sind. Andernfalls entspricht dies [2], und der Genauigkeitscode entspricht einem Intervall mit denselben Einheiten (und einer implizierten Menge von 1).

[2] und [3] sind ausdrücklich gleichwertig. [1] ist strikt weniger aussagekräftig als beide, da es effektive Intervalle gibt, die nicht durch [1] dargestellt werden können, z. Eine unscharfe Datums- / Uhrzeitangabe, die einem 12-Stunden-Intervall entspricht, das sich über eine Datumsgrenze erstreckt.

[1] ist für Benutzer einfacher einzugeben als jede andere Darstellung und sollte im Allgemeinen (zumindest geringfügig) weniger Eingaben erfordern. Wenn Datums- und Uhrzeitangaben in verschiedenen Textdarstellungen eingegeben werden können, z. B. "2013", "2014-3", "2015-5-2", "7/30/2016 11p", "2016-07-31 18:15" kann die Präzision oder Genauigkeit auch automatisch aus der Eingabe abgeleitet werden.

Die Genauigkeit oder Präzision von [1] ist auch am einfachsten in ein Formular umzuwandeln, das den Benutzern übermittelt werden soll, z. (Beachten Sie, dass letztere sowieso nicht durch [1] dargestellt werden können).

Streicher

In der Praxis müssen Zeichenfolgenwerte in andere Darstellungen konvertiert werden, um mehrere Werte abzufragen, zu sortieren oder auf andere Weise zu vergleichen. Während also jede geschriebene natürliche (menschliche) Sprache strikt aussagekräftiger ist als [1], [2], [3] oder [5], verfügen wir noch nicht über die Mittel, um weit über Standardtextdarstellungen oder -formate hinauszugehen. Angesichts dessen ist dies wahrscheinlich die am wenigsten nützliche Darstellung für sich .

Ein Vorteil dieser Darstellung ist, dass Werte in der Praxis für Benutzer so wie sie sind darstellbar sein sollten und keine Transformation erfordern, um leicht verständlich zu sein.

Wahrscheinlichkeitsverteilungen

Wahrscheinlichkeitsverteilungen verallgemeinern die einheitlichen Intervalldarstellungen [1], [2], [3] und sind (wohl) der (allgemeinen) Zeichenfolgendarstellung [4] äquivalent.

Ein Vorteil von Wahrscheinlichkeitsverteilungen gegenüber Zeichenfolgen besteht darin, dass erstere eindeutig sind.

[5-1] ist für Werte geeignet, die (meistens) mit einer vorhandenen Verteilung übereinstimmen, z. B. ein Datums- / Zeitwert, der von einem Gerät ausgegeben wird, für das bekannt ist, dass Messungen mit einer bestimmten Verteilung übereinstimmen (oder angenommen werden).

[5-2] ist wahrscheinlich die beste (etwas) praktische Möglichkeit, beliebige "Fuzzy-Datetime" -Werte kompakt darzustellen. Natürlich ist die Berechenbarkeit der verwendeten spezifischen Wahrscheinlichkeitsverteilungen von Bedeutung und es gibt definitiv interessante (und möglicherweise unmögliche) Probleme, die beim Abfragen, Sortieren oder Vergleichen verschiedener Werte zu lösen sind, aber vieles davon ist wahrscheinlich bereits bekannt oder irgendwo in der vorhandenen gelöst Die mathematische und statistische Literatur steht also definitiv für eine äußerst allgemeine und eindeutige Darstellung.


-1

Die Lösung von James Anderson gefällt mir sehr gut. Durch genaues Eingrenzen der Daten erhalten Sie die flexibelste Abfragestruktur. Eine andere Möglichkeit, dies zu erreichen, ist die Verwendung eines Start-, End- oder sogar eines Zentrums dateplus eines interval(zumindest in PostgreSQL , Oracle und SQLAlchemy verfügbar ).


-2

In deinem Fall brauchst du nur Jahr, Monat und Tag. Jahr und Monat sind erforderlich, Tag ist optional. Ich würde so etwas benutzen:

year smallint not null,
month smallint not null,
day smallint

Außerdem können Sie Indizes immer noch sehr effektiv verwenden. Die (tiny = minus, queires werden etwas "komplizierter" (länger).


1
Dies bedeutet jedoch, dass dieser Ansatz fehlschlägt, wenn die Unschärfe auch den Monatsteil verschlingt.
Anurag Kalia

1
@AnuragKalia - so machen Sie das Monatsfeld nullbar. Kein Grund, dass dies zu einem späteren Zeitpunkt nicht neu konfiguriert werden konnte.
JeffO

Das war nur ein Beispiel. Die Lösung muss allgemein genug sein, um zukünftigen Problemen Rechnung zu tragen. Wenn der von Ihnen angegebene Bereich zwischen dem 15. März 2013 und dem 22. März 2013 liegt, funktioniert dieser Ansatz nicht. Die obige Min-Max-Antwort ist die bisher allgemeinste.
Anurag Kalia

1
Haben Sie eine solche Anforderung in OPs Post gefunden oder ist es nur Ihre Phantasie?
Danubian Sailor

Wenn Sie den Monat auf null setzen, können Sie einen Tag, aber keinen Monat angeben. Macht auch keinen Sinn. Wann war 1978-??-31?
MSalters

-2

Ich würde einfach die genaue Zeit für normale Daten speichern und den Zeitanteil des Fuzzy-Datums generisch auf 00:00:00 setzen. Ich würde dann alle unscharfen Daten zum 1. des Monats machen.

Wenn Sie abfragen, Sie

  1. Suche nach Datumsbereichen, in denen die Zeit auch gleich 00:00:00 ist (unscharf)
  2. Auf Datumsbereiche prüfen, in denen die Zeit NICHT gleich 00:00:00 (real) ist
  3. Auf Datumsbereiche prüfen, aber den Zeitanteil ignorieren (kombiniert)

Es gibt bessere Lösungen als diese, aber ich persönlich hasse Metadaten (Daten über meine Daten). Es hat nur die Angewohnheit, nach einer Weile außer Kontrolle zu geraten.


2
Wie würde dies mit einem realen Datum mit einer Zeit von 00:00:00 umgehen?
Mücke

Es ist zwar theoretisch möglich, ein echtes Datum mit dieser Zeit hinzuzufügen, dies wird jedoch nicht passieren. Ich habe Tabellen mit Millionen von Zeilen gesehen und keine einzige davon hatte einen Datums- / Uhrzeitwert, bei dem die Zeit 00:00:00 war. Pragmatismus übertrifft Konvention.
Captain Kenpachi
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.