営業時間をどのように保存および照会しますか?
-
02-07-2019 - |
質問
「営業時間」を保存するアプリを構築していますさまざまなビジネス向け。アイテムが開いているかどうかを簡単に確認できるように、このデータを表す最も簡単な方法は何ですか?
いくつかのオプション:
- 「開く/閉じる」とマークできるブロックをセグメント化します(15分ごと)。チェックには、「開く」かどうかの確認が含まれます。ビットは希望の時間に設定されます(列車のスケジュールのようなビット)。
- 時間範囲(午前11時から午後2時、午後5時から7時など)のリストを保存し、現在の時刻が指定された範囲内にあるかどうかを確認します(上記の文字列を解析するときに脳が行うことです)。
時刻表情報やアドバイスを保存および照会した経験はありますか?
(「月の第1火曜日は休業」など、あらゆる種類のクレイジーコーナーケースがありますが、別の日に残します。)
解決
各連続する時間ブロックを開始時間と期間として保存します。これにより、時間が日付の境界を越えるときを簡単に確認できます
営業時間が営業時間を超えないことが確実な場合(つまり、24時間営業のセールや72時間のマラソンイベントなどは決してありません)、開始/終了時間で十分です
他のヒント
最も柔軟なソリューションは、ビットセットアプローチを使用することです。 1週間に168時間あるため、15分の期間が672あります。これはたった84バイトのスペースであり、許容範囲内です。
次のようなテーブルを使用します:
BusinessID | weekDay | OpenTime | CloseTime
---------------------------------------------
1 1 9 13
1 2 5 18
1 3 5 18
1 4 5 18
1 5 5 18
1 6 5 18
1 7 5 18
ここでは、通常の営業時間は5〜6時間ですが、日曜日は営業時間が短くなっています。
openが(psuedo-sql)であるかどうかのクエリ
SELECT @isOpen = CAST
(SELECT 1 FROM tblHours
WHERE BusinessId = @id AND weekDay = @Day
AND CONVERT(Currentime to 24 hour) IS BETWEEN(OpenTime,CloseTime)) AS BIT;
エッジケースを保存する必要がある場合は、1日に1つずつ365のエントリを作成します。これは、物事の大まかなスキームではあまりないので、インデックスをday列とbusinessId列に配置します。
ビジネスのタイムゾーンを別のテーブルに保存することを忘れずに(正規化!)、これらの比較を行う前に時間と時間の変換を実行してください。
個人的には、開始時間と終了時間に行くと思います。これにより、すべてがより柔軟になります。良い質問は次のとおりです:ブロックサイズが特定のポイントで変更される可能性は何ですか?次に、状況に最適なソリューションを選択します(変更が必要な場合は、間違いなくタイムスパンに進みます)。
タイムスパンとして保存し、アプリケーションでセグメントを使用できます。そうすれば、データストアの変更の柔軟性を維持しながら、ブロックを使用して簡単に入力できます。
ジョナサン・ホランドに追加するには言った、同じ日に複数のエントリを許可します。
10進数の時間、または別の列の分も許可します。
なぜですか?多くのレストランやいくつかのビジネス、そして世界中の多くのビジネスでは、昼休みや午後の休憩があります。また、多くのレストラン(私の家の近くで知っている2つは、15単位以外の奇数時間に閉まります。1つは日曜日の午後9時40分に閉まり、もう1つは午前1時40分に閉まります。
たとえば、感謝祭の日に早めに閉店するなど、休日の時間の問題もあるため、カレンダーベースのオーバーライドが必要です。
おそらく、次のような日付/時刻のオープン、日付と時刻のクローズが可能です:
businessID | datetime | type
==========================================
1 10/1/2008 10:30:00 AM 1
1 10/1/2008 02:45:00 PM 0
1 10/1/2008 05:15:00 PM 1
1 10/2/2008 02:00:00 AM 0
1 10/2/2008 10:30:00 AM 1
など(タイプ:1は開いており、0は閉じている)
また、今後1〜2年のすべての日を1〜2年前に事前計算しておきます。 int、date / time / bitの3つの列しかないため、データの消費は最小限に抑える必要があります。
これにより、特別な日が知られるようになると、特別な日の奇数時間の特定の日付を変更できます。
また、深夜0時の通過と12/24時間の変換も処理します。
また、タイムゾーンに依存しません。開始時間と継続時間を保存する場合、終了時間を計算するときに、マシンはTZ調整時間を提供しますか?それはあなたが望むものですか?より多くのコード。
オープンクローズステータスのクエリに関する限り:問題の日時のクエリ、
select top 1 type from thehours where datetimefield<=somedatetime and businessID = somebusinessid order by datetime desc
「タイプ」を見てください。 1つの場合は開いており、0の場合は閉じています。
PS:私は10年間小売業をしていました。だから私は中小企業のクレイジーアワーの問題に精通しています。
OK、これに価値があるものを投入します。
かなり多くのことを処理する必要があります。
- 高速/パフォーマンスクエリ
- 時間の増分、9:01 PM、12:14など。
- 国際(?)-これがタイムゾーンでも問題であるかどうかはわかりません。少なくとも私の場合は、ここに詳しい人は気軽に声をかけてください
- オープン-翌日までのクローズ(正午にオープン、午前2:00にクローズ)
- 複数の期間/日
- 特定の日(休日など)を上書きする機能
- オーバーライドを繰り返し実行する機能
- 任意の時点を照会し、ビジネスをオープンにする能力(現在、未来、過去)
- すぐに閉店するビジネスの結果を簡単に除外する機能(30分で閉店するビジネスをフィルターします。ユーザーを「食品/飲料業界で閉店する5分前に表示されるユーザー」にしたくない)
私は提示されたアプローチの多くが好きで、それらのいくつかから借りています。私のウェブサイト、プロジェクトでは、考慮に入れる必要があるものは何百万ものビジネスがあるかもしれませんし、ここでのアプローチのいくつかは個人的にはうまくスケールしないようです。
これがアルゴリズムと構造について提案するものです。
私たちは、いつでも、どこでも、世界中でいくつかの具体的な仮定をしなければなりません。 週に7日あります。 1日は1440分です。 開いている/閉じている時間の順列の数には限りがあります。
具体的ではなく、適切な仮定: 営業時間/休業日の多くの順列が企業間で共有されるため、実際に保存される順列の合計が減少します。 私の人生にはこのアプローチの実際の可能な組み合わせを簡単に計算できる時間がありましたが、誰かがそれを支援/考えることができれば便利だと思います。
3つのテーブルを提案します。 読み取りを停止する前に、実世界ではこれらのテーブルのうち2つが十分に小さいキャッシュであることを考慮してください。このアプローチは、UIをデータモデルに解釈し、必要に応じて元に戻すために必要なコードが非常に複雑であるため、すべての人に適しているわけではありません。走行距離とニーズは異なる場合があります。これは、意味が何であれ、合理的な「エンタープライズ」レベルのソリューションの試みです。
HoursOfOperationsテーブル
ID | OPEN(一日の分)| CLOSE(一日の分)
1 | 360 | 1020(例:午前9時から午後5時)
2 | 365 | 1021(例:エッジケース9:05 AM-5:01 PM(weirdos))
etc。
HoursOfOperationsは、何日目かを気にせず、開いたり閉じたりするだけで、一意性を保ちます。オープン/クローズの組み合わせごとに1つのエントリしか存在できません。現在、環境に応じて、このテーブル全体をキャッシュすることも、現在の時間などにキャッシュすることもできます。いずれにしても、すべての操作でこのテーブルをクエリする必要はありません。ストレージソリューションによっては、この表のすべての列がパフォーマンスのためにインデックス付けされていると想定しています。時間が経過するにつれて、このテーブルはおそらくINSERTの指数関数的に逆の尤度を持ちます。ただし、実際には、このテーブルの処理は主にインプロセス操作(RAM)である必要があります。
Business2HoursMap
注:私の例では、「日」を保存しています。ビットフラグフィールド/列として。これは主に、私のニーズとC#のLINQ / Flags Enumsの進歩によるものです。これを7ビットフィールドに拡張することを妨げるものは何もありません。両方のアプローチは、ストレージロジックとクエリアプローチの両方で比較的類似している必要があります。
別の注:「すべてのテーブルにPK ID列が必要」というセマンティクスの引数を入力していません。別のフォーラムを見つけてください。
BusinessID | HoursID |日(または、月曜日にBIT、火曜日にBITに分割したい場合)
1 | 1 | 1111111(このビジネスは毎日9時から5時まで営業しています)
2 | 2 | 1111110(このビジネスは9:05-5:01 Mに営業しています
セグメントブロックの方が優れています。ユーザーに簡単に設定できるようにしてください。クリックしてドラッグするのが良いです。
他のシステム(範囲など)は、真夜中の境界を越えると本当に迷惑になります。
それらをどのように保存するかについては、C ++のビットフィールドでおそらく最適です。他のほとんどの言語では、配列の方が優れている場合があります(多くの無駄なスペースがありますが、実行速度が速く、理解しやすいでしょう)。
これらのエッジケースについては、基本構成に加えて、オーバーレイまたはオープン時間などの完全な静的ストレージがあるかどうかを通知するので、少し考えます。
非常に多くの例外があります-定期的に(雪の日、イースターのような不規則な休日、聖金曜日など)、これが現実の信頼できる表現であると予想される場合(推測とは対照的に)、すぐにアーキテクチャで対処する必要があります。
このようなものはどうですか:
営業時間表
Business_id (int)
Start_Time (time)
End_Time (time)
Condition varchar/string
Open bit
'Condition'はラムダ式( 'where'句のテキスト)です。クエリを動的に作成します。そのため、特定のビジネスでは、すべての営業時間/営業時間を選択します
Let Query1 = select count(open) from store_hours where @t between start_time and end_time and open = true and business_id = @id and (.. dynamically built expression)
Let Query2 = select count(closed) from store_hours where @t between start_time and end_time and open = false and business_id = @id and (.. dynamically built expression)
そのため、次のような終了を終了します。
select cast(Query1 as bit) & ~cast(Query2 as bit)
最後のクエリの結果が1の場合、ストアは時刻tに開かれ、そうでない場合は閉じられます。
ここで、where句(ラムダ式)を生成できる使いやすいインターフェイスが必要です。
私が考えることができる他の唯一のコーナーケースは、ある日は午前7時から午前2時まで営業しているが、翌日は午後11時に閉店した場合に起こることです。システムは、2日間の時間を賢く分割することで、同様にそれを処理できるはずです。
ここでメモリを節約する必要は確かにありませんが、おそらくクリーンでわかりやすいコードが必要です。 「ビット調整」私見、行く方法ではありません。
ここには、任意の数の一意のアイテムを保持し、アイテムがメンバーであるかどうかをすばやく簡単に判断できるセットコンテナが必要です。セットアップには注意が必要ですが、日常的に単純に理解されたコードの1行を使用して、開いているか閉じているかを判断します
コンセプト: たとえば、日曜日の真夜中から15分ごとにインデックス番号を割り当てます。
初期化: 開いているときに15分ごとのブロックのインデックス番号をセットに挿入します。 (開いている時間は閉じている時間より短いと仮定します。)
使用: 興味深い時間(分単位、前の日曜日の真夜中)から減算し、15で除算します。この数値がセットに含まれている場合は、開いています。