データベースに営業時間を保存する


84

私は現在、営業時間をデータベースに保存するための最良の方法を模索しています。

例えば:

ビジネスAの営業時間は次のとおりです

  • 月曜日:午前9時〜午後5時
  • 火曜日:午前9時〜午後5時
  • 水曜日:午前9時〜午後5時
  • 木曜日:午前9時〜午後5時
  • 金曜日:午前9時〜午後5時
  • 土曜日:午前9時〜正午
  • 日曜日:休業

現在、私は次のようなデータモデルを持っています

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

ここで、「日」はコード内の7日間の選択に制限されています(ORMを介して)。ビジネスが特定の日に休業しているかどうかをテストするために、open_timeとclose_timeがNULLであるかどうかを確認します。これは、中間テーブル(多対多の関係)を介してビジネスに関連しています。

このデータベーススキームについて何か提案はありますか?それについての何かが私には正しくないようです。


4
business_hoursテーブルとbusinesssテーブルの間にM-to-M関係が必要なのはなぜですか?本当に複数の企業がbusiness_hoursで同じレコードを共有するようにする場合、なぜですか?意味的には、「C社はD日目にT1からT2まで機能する」という事実は、エンティティというよりはむしろ値オブジェクトです...私が想像できる唯一の良い(?)理由は、ストレージサイズの最適化です(FlyweightパターンのRDBバージョン、いわば)企業の数が膨大になると予想される場合
...– Yarik

2
昼休みはどうですか?祝日はどうですか?
Mawgは、2017

回答:


56

全体として、これには何の問題もありません。を除いて...

  1. ネイティブプログラミング言語が使用するナンバリングシステム(ライブラリ内)を使用して、曜日を整数として格納します。これにより、データベースのサイズが小さくなり、コードから文字列の比較が削除されます。

  2. 私はおそらく、このテーブルのビジネステーブルに外部キーを配置します。そうすれば、リンクテーブルは必要ありません。

だから私はそうするだろうと思います:

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
)

私のビジネスロジックでは、すべての「ビジネス」に少なくとも7つの「営業時間」があるという制約を適用します。(少なくともJon Skeetが正しいので、休日の時間が必要な場合があります。)ただし、営業時間が休業している日の「営業時間」を単に省略して、この制約を緩和することもできます。


1
どのように2をしますか?日時が同じでも、すべてのビジネスのすべてのエントリがありますか?
Vinko Vrsalovic 2009年

7
はいと思います。それ以外の場合は、2つのビジネスが同じ時間を共有しているが、そのうちの1つが時間を変更する必要がある場合はどうなるかを検討してください。時間が変更されたことを検出し、共有されているかどうかに応じて、新しいレコードを作成するか、既存のレコードを編集する必要があります。
Erik Forbes

3
このテーブルの行を企業間で共有することは絶対にありません。そのような共有はただ苦痛につながります。アプリのビジネスロジックは、すべてのビジネスに少なくとも7つの「business_hours」参照があるという制約を適用する必要があります。
フランククルーガー

1
@Vinko:は(現在)同じですが、2つのビジネスの営業時間は意味的に異なることに注意してください。
draemon 2010

1
「日」に7ビットのビットマップを使用することもできます。そうすれば、同じエントリを繰り返す必要はありません。例すべての営業日は同じ営業時間であり、1つのエントリで十分です。
zolaKt 2013

28

このスキーマでカバーされていない状況の1つは、1日に複数の営業期間があることです。たとえば、地元のパブの営業時間は12:00〜14:30と17:00〜23:00です。

たぶん、劇場の興行収入はマチネと夜の公演のために開いています。

その時点で、同じ日に複数のエントリを含めることができるかどうか、または同じ行で異なる時間を表す必要があるかどうかを決定する必要があります。

真夜中を横切る営業時間はどうですか。バーの営業時間は19:00-02:00だとします。開始時間と終了時間をテストしたい時間と比較することはできません。


@JordanFeldsteinが提案したようなことをすることになった。変化(オープンまたはクローズ)、曜日、時刻を含む「状態変化」の配列を格納します。私は、ビジネスごとに、そして毎日、好きなだけ「変更」を行うことができます。ビジネスは、ある日は開いて次の日は閉じることができ、1日2回(またはx回)開いて、24時間開いていても、月曜日は閉じています。実装するのは難しいですが、非常に柔軟性があります。
ironcito 2018

ベストアンサーアプローチに従って、business_hoursbreak_timeとに2つの列を追加したいと思いますbreak_duration。同じ日に2回休憩することは本当にまれです。
Frondor

12

それは、保存する必要があるものと、実際のデータがどのように見えるかによって異なります。
ある時点でビジネスが開いているかどうかを判断できる必要がある場合は、レイアウトどおりにスキームを照会するのは少し厄介かもしれません。ただし、もっと重要なのは、次のとおりです。正午の閉鎖に対応する必要がありますか。

いくつかのオプションが含まれます。

  • あなたが持っているもののようなスキームですが、同じ日に複数の期間を持つオプションがあります。昼休みには対応しますが、ユーザーへのプレゼンテーションなど、特定の日の営業時間を指定するクエリを実行するのは面倒です。
  • ビットマップスタイルのアプローチ。9-5の場合は「000000000111111110000000」。このアプローチの欠点は、特定の粒度、つまり1時間または30分、あるいは実際には数分を選択する必要があることです。粒度が細かいほど、人間がデータを読み取るのが難しくなります。ビット単位の演算子を使用して、この値を整数の文字列ではなく単一の数値として格納できますが、やはり読みやすさが損なわれます。

11

Googleデータマークアップにデータを認識させたい場合は、次のガイドラインに従う必要があることを学びました。

https://schema.org/openingHours

http://schema.org/OpeningHoursSpecification「有効な日付」が含まれています。これは一部のビジネスに非常に役立ちます。

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

企業が結合テーブルと同じ時間を共有することを許可しない限り、主キーがなくても問題ありません。興味深いことに、最終的には組み合わせの数が有限になります。いくつになるかわかりません:p

私のプロジェクトの1つで、列を使用しました。

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

OpeningHoursSpecificationをサポートする場合は、validFromとvalidThroughを追加する必要があります。

時間範囲は次のようにフォーマットされます:hh:mm-hh:mm

これを解析する関数を次に示します。DB内で別々の列として保持している場合は、この関数を変更して、単一の開閉のみを解析することもできます。

私の経験から、1日に複数回許可するか、その日に明示的に閉鎖されているか、24時間または24時間年中無休で開いているかを判断する方法を許可することをお勧めします。私は、DBに欠落している日があった場合、その日は営業を終了したと言っていました。

/**
 * 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;
}

1

ほとんどの結果は特定のシナリオで正常に機能しますが、複数日にわたる期間がある場合はそれほど効果的ではありません。午前8時から午前2時までは、複数期間の設計を使用することをお勧めします。

   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 }
         ]
      ]

0

月/日/月の週に追加のフィールドを含めることで、休日を考慮に入れることを考えるかもしれません。月の週には、「最後」のマイナーな微妙な点がいくつかあります。たとえば、年に応じて4週目または5週目です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.