Speichern von Geschäftszeiten in einer Datenbank

83

Ich versuche derzeit, den besten Weg zu finden, um die Betriebsstunden eines Unternehmens in einer Datenbank zu speichern.

Zum Beispiel:

Geschäft A hat die folgenden Betriebsstunden

  • Montag: 9 bis 17 Uhr
  • Dienstag: 9 - 17 Uhr
  • Mittwoch: 9 bis 17 Uhr
  • Donnerstag: 9 - 17 Uhr
  • Freitag: 9 - 17 Uhr
  • Samstag: 9 - 12 Uhr
  • Sonntag: Geschlossen

Derzeit habe ich ein Datenmodell ähnlich dem folgenden

CREATE TABLE "business_hours" (
    "id" integer NOT NULL PRIMARY KEY,
    "day" varchar(16) NOT NULL,
    "open_time" time,
    "close_time" time
)

wobei der "Tag" auf eine Auswahl der 7 Wochentage im Code beschränkt ist (über das ORM). Um zu testen, ob ein Unternehmen an einem bestimmten Tag geschlossen ist, wird überprüft, ob open_time und close_time NULL sind. Es ist über eine Zwischentabelle (Many To Many Relationship) mit dem Geschäft verbunden.

Hat jemand Vorschläge für dieses Datenbankschema? Etwas daran scheint mir nicht richtig zu sein.

user128000
quelle
4
Warum benötigen Sie eine M-zu-M-Beziehung zwischen der Tabelle business_hours und der Tabelle business? Wenn Sie wirklich mehrere Unternehmen dazu bringen möchten, denselben Datensatz in business_hours zu teilen, warum? Semantisch gesehen ist die Tatsache, dass "Unternehmen C am Tag D von T1 bis T2 arbeitet" eher ein Wertobjekt als eine Entität ... Der einzige gute (?) Grund, den ich mir vorstellen kann, ist die Optimierung der Speichergröße (RDB-Version des Flyweight-Musters, sozusagen) wenn die Anzahl der Unternehmen voraussichtlich riesig sein wird ...
Yarik
2
Was ist mit Mittagspausen? Was ist mit Feiertagen?
Mawg sagt, Monica wieder

Antworten:

56

Insgesamt sehe ich daran nichts auszusetzen. Außer...

  1. Ich würde den Wochentag als Ganzzahl speichern, indem ich das Nummerierungssystem verwende, das Ihre native Programmiersprache verwendet (in ihren Bibliotheken). Dadurch wird die Größe der Datenbank verringert und Zeichenfolgenvergleiche aus Ihrem Code entfernt.

  2. Ich würde wahrscheinlich den Fremdschlüssel hier in dieser Tabelle in den Business-Tisch einfügen. Auf diese Weise benötigen Sie keine Verknüpfungstabelle.

Also würde ich wohl tun:

CREATE TABLE "business_hours" (
     "id" integer NOT NULL PRIMARY KEY,
     "business_id" integer NOT NULL FOREIGN KEY REFERENCES "businesses",
     "day" integer NOT NULL,
     "open_time" time,
     "close_time" time
)

In meiner Geschäftslogik würde ich eine Einschränkung erzwingen, dass jedes "Geschäft" mindestens 7 "Geschäftsstunden" hat. ( Zumindest, weil Jon Skeet Recht hat, möchten Sie vielleicht Ferienzeiten.) Obwohl Sie diese Einschränkung lockern möchten, indem Sie einfach die "Geschäftszeiten" für Tage weglassen, an denen das Geschäft geschlossen ist.

Frank Krueger
quelle
1
Wie würdest du 2 machen? Haben Sie alle Einträge für alle Unternehmen, auch wenn Tag / Uhrzeit gleich sind?
Vinko Vrsalovic
7
Ich würde Ja sagen. Überlegen Sie andernfalls, was passieren würde, wenn zwei Unternehmen dieselben Stunden teilen, aber dann muss eines von ihnen seine Stunden ändern. Sie müssten die Tatsache erkennen, dass die Stunden geändert werden, und entweder einen neuen Datensatz erstellen oder den vorhandenen bearbeiten, je nachdem, ob er freigegeben ist oder nicht.
Erik Forbes
3
Ich würde die Zeilen dieser Tabelle absolut nicht zwischen Unternehmen teilen. Diese Art des Teilens führt nur zu Schmerzen. Die Geschäftslogik der App sollte nur die Einschränkung erzwingen, dass jedes Unternehmen mindestens 7 "business_hours" -Referenzen hat.
Frank Krueger
1
@Vinko: Denken Sie daran, dass die Öffnungszeiten für zwei Unternehmen semantisch unterschiedlich sind , obwohl die Werte (derzeit) gleich sind.
Draemon
1
Sie können auch eine Bitmap mit 7 Bits für "Tag" verwenden. Auf diese Weise müssen Sie nicht dieselben Einträge wiederholen. Beispiel: Alle Arbeitstage haben dieselben Geschäftszeiten. Ein Eintrag ist ausreichend.
ZolaKt
27

Eine Situation, die von diesem Schema nicht abgedeckt wird, sind mehrere Öffnungsperioden an einem Tag. Zum Beispiel ist die lokale Kneipe von 12:00 bis 14:30 Uhr und von 17:00 bis 23:00 Uhr geöffnet.

Vielleicht ist eine Theaterkasse für eine Matinee und eine Abendvorstellung geöffnet.

An diesem Punkt müssen Sie entscheiden, ob Sie mehrere Einträge für denselben Tag haben können oder ob Sie verschiedene Stunden in derselben Zeile darstellen müssen.

Was ist mit Öffnungszeiten, die Mitternacht überschreiten? Angenommen, eine Bar ist von 19:00 bis 02:00 Uhr geöffnet. Sie können die Öffnungs- und Schließzeiten nicht einfach mit der Zeit vergleichen, die Sie testen möchten.

Davidsheldon
quelle
Am Ende habe ich etwas gemacht, wie es @JordanFeldstein vorgeschlagen hat. Ich speichere Arrays von "Statusänderungen", einschließlich der Änderung (Öffnen oder Schließen), des Wochentags und der Tageszeit. Ich kann für jedes Unternehmen und jeden Tag so viele "Änderungen" vornehmen, wie ich möchte. Ein Unternehmen kann an einem Tag öffnen und am nächsten schließen, zweimal (oder xmal) pro Tag öffnen, 24 Stunden geöffnet sein, aber montags geschlossen sein, was auch immer. Die Implementierung ist schwierig, aber sehr flexibel.
Ironcito
Nach dem Ansatz der besten Antwort möchte ich lieber zwei Spalten zu business_hours: break_timeund hinzufügen break_duration. Es ist wirklich selten, 2 Pausen am selben Tag zu haben.
Frondor
12

Es hängt davon ab, wofür Sie es speichern müssen und wie die realen Daten aussehen könnten.
Wenn Sie feststellen müssen, ob das Unternehmen zu einem bestimmten Zeitpunkt geöffnet ist, kann es etwas umständlich sein, das Schema wie beschrieben abzufragen. Wichtiger ist jedoch: Würden Sie jemals für eine Mittagspause sorgen müssen?

Einige Optionen umfassen;

  • Ein Schema wie das, was Sie haben, aber mit der Option, mehrere Perioden für denselben Tag zu haben. Es würde für die Mittagspause sorgen, aber es würde umständlich sein, eine Abfrage auszuführen, die Ihnen die Öffnungszeiten für einen bestimmten Tag angibt, beispielsweise für die Präsentation vor einem Benutzer.
  • Ein Bitmap-Ansatz; "000000000111111110000000" für 9-5. Der Nachteil dieses Ansatzes besteht darin, dass Sie eine bestimmte Granularität auswählen müssen, dh ganze Stunden oder halbe Stunden oder sogar Minuten. Je feiner die Granularität, desto schwieriger ist es, die Daten für einen Menschen zu lesen. Sie können bitweise Operatoren verwenden, um diesen Wert als einzelne Zahl anstatt als Folge von Ganzzahlen zu speichern, aber auch dies beeinträchtigt die Lesbarkeit.
Frans
quelle
11

Ich habe erfahren, dass Sie die folgenden Richtlinien befolgen sollten, wenn Google Data Markup Ihre Daten erkennen soll:

https://schema.org/openingHours

http://schema.org/OpeningHoursSpecification Enthält "gültige Daten", was für einige Unternehmen sehr nützlich ist.

https://schema.org/docs/search_results.html#q=hours

Sie sollten ohne Primärschlüssel in Ordnung sein, es sei denn, Sie erlauben Unternehmen, dieselben Stunden mit der Join-Tabelle zu teilen - interessanterweise hätten Sie schließlich eine begrenzte Anzahl von Kombinationen. Ich bin mir nicht sicher, wie viele das sein würden: p

Bei einem meiner Projekte habe ich die Spalten verwendet:

[uInt] business_id, [uTinyInt] day, [char (11)] timeRange

Wenn Sie OpeningHoursSpecification unterstützen möchten, müssen Sie validFrom und validThrough hinzufügen.

Der Zeitbereich ist wie folgt formatiert: hh: mm-hh: mm

Hier ist eine Funktion, die es analysiert. Sie können diese Funktion auch so ändern, dass nur ein einzelnes Öffnen / Schließen analysiert wird, wenn Sie sie als separate Spalten in der Datenbank behalten.

Aus meiner Erfahrung heraus würde ich empfehlen, dass Sie mehrere Male innerhalb eines Tages zulassen, eine Möglichkeit angeben, um festzustellen, ob sie an diesem Tag explizit geschlossen oder 24 Stunden oder 24/7 geöffnet sind. Ich habe sagen lassen, dass das Geschäft an diesem Tag geschlossen wurde, wenn ein Tag in der DB fehlte.

/**
 * parseTimeRange
 * parses a time range in the form of
 * '08:55-22:00'
 * @param $timeRange 'hh:mm-hh:mm' '08:55-22:00'
 * @return mixed ['hourStart'=>, 'minuteStart'=>, 'hourEnd'=>, 'minuteEnd'=>]
 */
function parseTimeRange($timeRange)
{
    // no validating just parsing
    preg_match('/(?P<hourStart>\d{1,2}):(?P<minuteStart>\d{2})-(?P<hourEnd>\d{1,2}):(?P<minuteEnd>\d{2})/', $timeRange, $matches);

    return $matches;
}
CTS_AE
quelle
1

Die meisten Ergebnisse funktionieren für das gegebene Szenario einwandfrei, sind jedoch nicht so effektiv, wenn Sie Zeiträume haben, die mehrere Tage dauern, z. 8:00 bis 02:00 Uhr, dann empfehle ich die Verwendung eines mehrperiodischen Designs.

   0: [
         id: 1,
         business_id: 1,
         open: true,
         day: 1,
         periods: [
             0: { open: 08:00, close: 23:59 }
         ]
      ],
   1: [
         id: 2,
         business_id: 1,
         open: true,
         day: 2,
         periods: [
             0: { open: 00:00, close: 02:00 }
             1: { open: 08:00, close: 23:59 }
         ]
      ]
Mahmoud Ali Kassem
quelle
0

Denken Sie möglicherweise daran, Feiertage zu berücksichtigen, indem Sie zusätzliche Felder für Monat des Jahres / Tag des Monats / Woche des Monats einfügen. Woche des Monats hat einige kleinere Feinheiten "letzte" könnte zum Beispiel Woche 4 oder 5 sein, je nach Jahr.

Einstein
quelle