سؤال

نحن نبني تطبيقًا يخزن "ساعات العمل" لمختلف الأنشطة التجارية.ما هي أسهل طريقة لتمثيل هذه البيانات حتى تتمكن بسهولة من التحقق مما إذا كان العنصر مفتوحًا؟

بعض الخيارات:

  • قم بتقسيم الكتل (كل 15 دقيقة) التي يمكنك وضع علامة "مفتوحة/مغلقة".يتضمن التحقق معرفة ما إذا كان البت "المفتوح" مضبوطًا على الوقت المطلوب (يشبه إلى حدٍ ما جدول القطار).
  • تخزين قائمة النطاقات الزمنية (11 صباحًا - 2 مساءً، 5 - 7 مساءً، وما إلى ذلك) والتحقق مما إذا كان الوقت الحالي يقع في أي نطاق محدد (وهذا ما يفعله دماغنا عند تحليل السلاسل أعلاه).

هل لدى أي شخص خبرة في تخزين معلومات الجدول الزمني والاستعلام عنها وأي نصيحة يمكن تقديمها؟

(توجد جميع أنواع الحالات المجنونة مثل "مغلق يوم الثلاثاء الأول من الشهر"، ولكننا سنترك ذلك ليوم آخر).

هل كانت مفيدة؟

المحلول

تخزين كل كتلة زمنية متجاورة كوقت بداية ومدة؛وهذا يجعل من السهل التحقق من الوقت الذي تتجاوز فيه الساعات حدود التاريخ

إذا كنت متأكدًا من أن ساعات العمل لن تتجاوز حدود التاريخ أبدًا (أيلن يكون هناك أبدًا بيع مفتوح طوال الليل أو حدث ماراثون مدته 72 ساعة، وما إلى ذلك) فستكون أوقات البدء/الانتهاء كافية

نصائح أخرى

قد يكون الحل الأكثر مرونة هو استخدام أسلوب مجموعة البتات.هناك 168 ساعة في الأسبوع، أي أن هناك 672 فترة مدة كل منها 15 دقيقة.هذه مساحة تبلغ 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، ولكن ساعات عمل أقصر يوم الأحد.

الاستعلام عما إذا كان مفتوحًا سيكون (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;

إذا كنت بحاجة إلى تخزين حالات الحافة، فما عليك سوى أن يكون لديك 365 إدخالاً، بمعدل إدخال واحد في اليوم... وهذا ليس كثيرًا في المخطط الكبير للأشياء، ضع فهرسًا في عمود اليوم وعمود معرف العمل.

لا تنس تخزين المنطقة الزمنية للأعمال في جدول منفصل (تطبيعها!)، وإجراء تحويل بين وقتك ووقتك قبل إجراء هذه المقارنات.

أعتقد أنني شخصياً سأختار وقت البداية والنهاية، لأن ذلك سيجعل كل شيء أكثر مرونة.السؤال الجيد سيكون:ما هي فرصة أن يتغير حجم الكتلة عند نقطة معينة؟ثم اختر الحل الذي يناسب موقفك (إذا كان قابلاً للتغيير فسأختار الفترات الزمنية بالتأكيد).

يمكنك تخزينها كفترة زمنية، واستخدام المقاطع في تطبيقك.وبهذه الطريقة، يكون لديك مدخلات سهلة باستخدام الكتل، مع الحفاظ على مرونة التغيير في مخزن البيانات الخاص بك.

إضافة إلى ما جوناثان هولاند قال, ، سأسمح بإدخالات متعددة في نفس اليوم.

سأسمح أيضًا بالوقت العشري أو عمود آخر للدقائق.

لماذا؟العديد من المطاعم وبعض الشركات، والعديد من الشركات حول العالم تتناول استراحة الغداء أو بعد الظهر.أيضًا، يتم إغلاق العديد من المطاعم (2 التي أعرفها بالقرب من منزلي) في وقت فردي غير 15 زيادة.يغلق أحدهما عند الساعة 9:40 مساءً في أيام الأحد، ويغلق الآخر عند الساعة 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 مغلق)

وقم بحساب جميع الأيام في العام أو العامين القادمين مسبقًا بمقدار عام أو عامين مقدمًا.لاحظ أنه سيكون لديك 3 أعمدة فقط:int، date/time/bit لذا يجب أن يكون استهلاك البيانات في حده الأدنى.

سيسمح لك هذا أيضًا بتعديل تواريخ محددة للساعات الفردية للأيام الخاصة، كما تصبح معروفة.

كما أنه يعتني بالعبور بعد منتصف الليل، بالإضافة إلى تحويلات 12/24 ساعة.

بل هو أيضا حيادي المنطقة الزمنية.إذا قمت بتخزين وقت البدء والمدة، عند حساب وقت الانتهاء، فهل سيعطيك جهازك الوقت المعدل TZ؟هل هذا ما تريده؟المزيد من التعليمات البرمجية.

بقدر الاستعلام عن الحالة المفتوحة والمغلقة:الاستعلام عن التاريخ والوقت المعني،

select top 1 type from thehours where datetimefield<=somedatetime and businessID = somebusinessid order by datetime desc

ثم انظر إلى "اكتب".إذا كان واحدًا، فهو مفتوح، وإذا كان 0، فهو مغلق.

ملاحظة:لقد كنت في تجارة التجزئة لمدة 10 سنوات.لذلك أنا على دراية بمشاكل ساعات العمل المجنونة في الأعمال الصغيرة.

حسنًا، سأقوم بهذا مقابل ما يستحقه.

أحتاج إلى التعامل مع عدد قليل من الأشياء.

  • استعلام سريع / الأداء
  • أي زيادات في الوقت، 9:01 مساءً، 12:14، إلخ.
  • دولي (؟) - لست متأكدًا مما إذا كانت هذه مشكلة حتى مع المناطق الزمنية، على الأقل في حالتي ولكن شخصًا أكثر دراية هنا لا تتردد في المشاركة
  • مفتوح - إغلاق يمتد إلى اليوم التالي (مفتوح عند الظهر، ويغلق عند الساعة 2:00 صباحًا)
  • فترات زمنية متعددة / يوم
  • القدرة على تجاوز أيام محددة (العطلات، أيا كان)
  • القدرة على التجاوزات لتكون متكررة
  • القدرة على الاستعلام عن أي وقت وفتح الأعمال (الآن، في المستقبل، في الماضي)
  • القدرة على استبعاد نتائج الشركات التي ستغلق قريبًا بسهولة (تصفية الشركات التي ستغلق خلال 30 دقيقة، فأنت لا تريد أن تجعل المستخدمين لديك "الشخص الذي يظهر قبل 5 دقائق من الإغلاق في صناعة الأغذية/المشروبات)

تعجبني الكثير من الأساليب المقدمة وأستعير القليل منها.في موقع الويب الخاص بي، أو المشروع، مهما كان ما أحتاج إلى أخذه في الاعتبار، فقد يكون لدي ملايين الشركات وبعض الأساليب هنا لا يبدو أنها تناسبني شخصيًا.

إليك ما أقترحه للخوارزمية والبنية.

علينا أن نضع بعض الافتراضات الملموسة، في جميع أنحاء العالم، في أي مكان وفي أي وقت:هناك 7 أيام في الأسبوع.هناك 1440 دقيقة في اليوم الواحد.هناك عدد محدود من التباديل الممكنة لدقائق الفتح/الإغلاق.

افتراضات ليست ملموسة ولكنها لائقة:سيتم مشاركة العديد من التباديل للدقائق المفتوحة/المغلقة عبر الشركات مما يقلل إجمالي التباديل المخزن بالفعل.كان هناك وقت في حياتي كان بإمكاني بسهولة حساب المجموعات الفعلية الممكنة لهذا النهج، ولكن إذا كان بإمكان شخص ما المساعدة/التفكير في أنه سيكون مفيدًا، فسيكون ذلك رائعًا.

أقترح 3 جداول:قبل أن تتوقف عن القراءة، ضع في اعتبارك أن اثنين من هذه الجداول في العالم الحقيقي سيكونان صغيرين بما يكفي لذاكرة التخزين المؤقت بشكل أنيق.لن يكون هذا النهج مناسبًا للجميع أيضًا بسبب التعقيد الهائل للتعليمات البرمجية المطلوبة لتفسير واجهة المستخدم لنموذج البيانات والعودة مرة أخرى إذا لزم الأمر.قد تختلف المسافة المقطوعة واحتياجاتك.وهذه محاولة لإيجاد حل معقول على مستوى "المؤسسة"، مهما كان معنى ذلك.

جدول ساعات العمل

معرف | مفتوح (دقيقة من اليوم) | إغلاق (دقيقة من اليوم)


1 | 360 | 1020 (مثال:9 صباحًا - 5 مساءً)

2 | 365 | 1021 (مثال:حالة الحافة 9:05 صباحًا - 5:01 مساءً (غريب الأطوار))

إلخ.

لا تهتم HoursOfOperations بالأيام، فقط الفتح والإغلاق والتفرد.يمكن أن يكون هناك إدخال واحد فقط لكل مجموعة فتح/إغلاق.الآن، اعتمادًا على البيئة الخاصة بك، يمكن تخزين هذا الجدول بأكمله مؤقتًا أو يمكن تخزينه مؤقتًا للساعة الحالية من اليوم، وما إلى ذلك.على أية حال، لن تحتاج إلى الاستعلام عن هذا الجدول لكل عملية.اعتمادًا على حل التخزين الخاص بك، أتصور أن كل عمود في هذا الجدول مفهرس للأداء.مع مرور الوقت، من المحتمل أن يكون لهذا الجدول احتمالية عكسية مضاعفة لـ INSERT(s).ومع ذلك، فإن التعامل مع هذا الجدول يجب أن يكون في الغالب عملية قيد التشغيل (RAM).

Business2HoursMap

ملحوظة:في المثال الخاص بي، أقوم بتخزين "اليوم" كحقل/عمود ذو علامة بت.ويرجع ذلك إلى حد كبير إلى احتياجاتي والتقدم في LINQ / Flags Enums في C#.لا يوجد ما يمنعك من توسيع هذا إلى حقول 7 بت.يجب أن يكون كلا النهجين متشابهين نسبيًا في كل من منطق التخزين ونهج الاستعلام.

ملاحظة أخرى:أنا لا أدخل في جدال دلالي حول "كل جدول يحتاج إلى عمود معرف PK"، يرجى العثور على منتدى آخر لذلك.

BusinessId | ساعة | اليوم (أو ، إذا كنت تفضل الانقسام إلى:بت الاثنين، بت الثلاثاء، ...)


1 | 1 | 1111111 (هذا العمل مفتوح 9-5 كل يوم من أيام الأسبوع)

2 | 2 | 1111110 (هذا العمل مفتوح 9:05 - 5:01 M -SAT (الاثنين = اليوم 1)

السبب وراء سهولة الاستعلام عن ذلك هو أنه يمكننا دائمًا تحديد MOTD (دقيقة اليوم) التي نسعى إليها بسهولة تامة.إذا كنت أرغب في معرفة ما هو مفتوح في الساعة 5 مساءً غدًا، فسأحصل على جميع معرفات HoursOfOperations حيث يتم الإغلاق> = 1020.ما لم أبحث عن نطاق زمني، يصبح الفتح غير مهم.إذا كنت لا ترغب في إظهار إغلاق الشركات خلال نصف الساعة التالية، فما عليك سوى ضبط وقت الوارد وفقًا لذلك (ابحث عن 5:30 مساءً (1050)، وليس 5:00 مساءً (1020).من الطبيعي أن يكون الاستعلام الثاني هو "أعطني كل الأعمال باستخدام HoursID IN (1، 2، 3، 4، 5)، وما إلى ذلك".ربما ينبغي أن يثير هذا علامة حمراء نظرًا لوجود قيود على هذا النهج.ومع ذلك، إذا تمكن شخص ما من الإجابة على سؤال التباديل الفعلي أعلاه، فقد نتمكن من سحب العلم الأحمر للأسفل.لنفترض أننا نحتاج فقط إلى التباديل المحتمل على أي جانب من المعادلة في وقت واحد، سواء كان مفتوحًا أو مغلقًا.

نظرًا لأن لدينا جدولنا الأول مخبأ، فهذه عملية سريعة.العملية الثانية هي الاستعلام عن هذا الجدول الذي يحتمل أن يكون كبيرًا ولكننا نبحث عن أعمدة صغيرة جدًا (SMALLINT) نأمل أن تكون مفهرسة.

الآن، ربما ترى التعقيد من ناحية التعليمات البرمجية للأشياء.أنا أستهدف في الغالب الحانات في مشروعي الخاص، لذلك سيكون من الآمن جدًا افتراض أنه سيكون لدي عدد كبير من الأنشطة التجارية بساعات عمل مثل "11:00 صباحًا - 2:00 صباحًا (اليوم التالي)".سيكون هذا بالفعل إدخالين في كل من جدول HoursOfOperations بالإضافة إلى جدول Business2HoursMap.على سبيل المثالالشريط المفتوح من 11:00 صباحًا إلى 2:00 صباحًا سيحتوي على مرجعين لجدول ساعات العمل 660 - 1440 (11:00 صباحًا - منتصف الليل) و0 - 120 (منتصف الليل - 2:00 صباحًا).ستنعكس هذه المراجع في الأيام الفعلية في جدول Business2HoursMap كإدخالين في حالتنا المبسطة، إدخال واحد = مرجع ساعات جميع الأيام رقم 1، ومرجع آخر لجميع الأيام رقم 2.آمل أن يكون هذا منطقيًا، لقد كان يومًا طويلًا.

التجاوز في الأيام الخاصة / العطلات / أيا كان.تتم التجاوزات بطبيعتها، وتعتمد على التاريخ، وليس على أساس يوم من أيام الأسبوع.أعتقد أن هذا هو المكان الذي تحاول فيه بعض الأساليب دفع الوتد الدائري الذي يضرب به المثل في حفرة مربعة.نحن بحاجة إلى طاولة أخرى.

ساعة | BusinessId | يوم | شهر | سنة

1 | 2 | 1 | 1 | باطل

من المؤكد أن هذا يمكن أن يصبح أكثر تعقيدًا إذا كنت بحاجة إلى شيء مثل "في كل يوم ثلاثاء ثانٍ، تذهب هذه الشركة للصيد لمدة 4 ساعات".ومع ذلك، فإن ما سيسمح لنا بذلك بسهولة تامة هو السماح بـ 1 - التجاوزات، 2 - التجاوزات المتكررة المعقولة.على سبيل المثال.إذا كانت السنة فارغة، فكل عام في يوم رأس السنة الجديدة، يكون هذا الشريط الغريب مفتوحًا من الساعة 9:00 صباحًا حتى 5:00 مساءً بما يتماشى مع أمثلة البيانات المذكورة أعلاه.أي.- إذا تم تحديد العام فهو لعام 2013 فقط.إذا كان الشهر فارغًا، فهو أول يوم من الشهر.مرة أخرى، لن يتعامل هذا مع كل سيناريو جدولة بواسطة أعمدة NULL وحدها، ولكن من الناحية النظرية، يمكنك التعامل مع أي شيء تقريبًا من خلال الاعتماد على تسلسل طويل من التواريخ المطلقة إذا لزم الأمر.

مرة أخرى، سأقوم بتخزين هذا الجدول مؤقتًا على أساس يومي متجدد.لا أستطيع أن أرى بشكل واقعي أن صفوف هذا الجدول في لقطة ليوم واحد كبيرة جدًا، على الأقل بالنسبة لاحتياجاتي.أود أن أتحقق من هذا الجدول أولاً لأنه يعد تجاوزًا وسيحفظ استعلامًا مقابل جدول Business2HoursMap الأكبر بكثير على جانب التخزين.

مشكلة مثيرة للاهتمام.أنا مندهش حقًا أن هذه هي المرة الأولى التي أحتاج فيها حقًا إلى التفكير في هذا الأمر.كما هو الحال دائمًا، حريص جدًا على الرؤى أو الأساليب أو العيوب المختلفة في نهجي.

تعد كتل المقاطع أفضل، فقط تأكد من منح المستخدم طريقة سهلة لتعيينها.النقر والسحب أمر جيد.

سيكون أي نظام آخر (مثل النطاقات) مزعجًا للغاية عند عبور حدود منتصف الليل.

أما بالنسبة لكيفية تخزينها، فمن المحتمل أن تكون حقول البت في لغة C++ هي الأفضل.في معظم اللغات الأخرى، قد يكون المصفوفة أفضل (يوجد الكثير من المساحة المهدرة، ولكن سيتم تشغيلها بشكل أسرع وأسهل في الفهم).

سأفكر قليلاً في حالات الحافة هذه في الوقت الحالي، لأنها ستخبرك ما إذا كان لديك تكوين أساسي بالإضافة إلى تراكب أو تخزين ثابت كامل لأوقات العمل أو أي شيء آخر.

هناك العديد من الاستثناءات - وعلى أساس منتظم (مثل أيام الثلج، والعطلات غير المنتظمة مثل عيد الفصح، والجمعة العظيمة)، إذا كان من المتوقع أن يكون هذا تمثيلًا موثوقًا للواقع (على عكس التخمين الجيد)، فستحتاج لمعالجتها قريبا جدا في الهندسة المعمارية.

ماذا عن شيء مثل هذا:

جدول ساعات عمل المتجر

Business_id (int)
Start_Time (time)
End_Time (time)
Condition varchar/string
Open bit

"الشرط" هو تعبير لامدا (نص لجملة "حيث").إنشاء الاستعلام بشكل حيوي.لذلك، بالنسبة لشركة معينة، يمكنك تحديد جميع أوقات الفتح/الإغلاق

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، وإلا فسيتم إغلاقه.

الآن تحتاج فقط إلى واجهة سهلة الاستخدام يمكنها إنشاء عبارات المكان (تعبيرات لامدا) لك.

الحالة الزاوية الأخرى الوحيدة التي يمكنني التفكير فيها هي ما يحدث إذا كان المتجر مفتوحًا من الساعة 7 صباحًا حتى 2 صباحًا على سبيل المثال في تاريخ واحد ولكنه يغلق الساعة 11 مساءً في التاريخ التالي.يجب أن يكون نظامك قادرًا على التعامل مع ذلك أيضًا عن طريق تقسيم الأوقات بين اليومين بذكاء.

بالتأكيد ليست هناك حاجة للحفاظ على الذاكرة هنا، ولكن ربما هناك حاجة إلى تعليمات برمجية نظيفة ومفهومة."التلاعب قليلا" ليس، IMHO، هو الطريق الصحيح.

نحن بحاجة إلى مجموعة حاوية هنا، والتي تحتوي على أي عدد من العناصر الفريدة ويمكنها تحديد ما إذا كان العنصر عضوًا أم لا بسرعة وسهولة.يتطلب الإعداد الاهتمام، ولكن في الاستخدام الروتيني، يحدد سطر واحد من التعليمات البرمجية المفهومة ببساطة ما إذا كنت مفتوحًا أم مغلقًا

مفهوم:قم بتعيين رقم فهرس لكل كتلة مدتها 15 دقيقة، بدءًا من منتصف ليل الأحد على سبيل المثال.

التهيئة:أدخل في مجموعة رقم الفهرس لكل كتلة مدتها 15 دقيقة عندما تكون مفتوحًا.(بافتراض أنك مفتوح لساعات أقل مما تكون مغلقًا.)

يستخدم:اطرح من الوقت المثير للاهتمام، بالدقائق، منتصف ليل الأحد السابق واقسمه على 15.إذا كان هذا الرقم موجودا في المجموعة، فأنت مفتوح.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top