Lưu trữ Giờ làm việc trong Cơ sở dữ liệu


84

Tôi hiện đang cố gắng tìm ra cách tốt nhất để lưu trữ giờ hoạt động của doanh nghiệp trong cơ sở dữ liệu.

Ví dụ:

Doanh nghiệp A có số giờ hoạt động sau

  • Thứ Hai: 9 giờ sáng - 5 giờ chiều
  • Thứ 3: 9 giờ sáng - 5 giờ chiều
  • Thứ 4: 9 giờ sáng - 5 giờ chiều
  • Thứ 5: 9 giờ sáng - 5 giờ chiều
  • Thứ sáu: 9 giờ sáng - 5 giờ chiều
  • Thứ Bảy: 9 giờ sáng - 12 giờ trưa
  • Chủ nhật: Đóng cửa

Hiện tại, tôi có một mô hình dữ liệu tương tự như sau

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

trong đó "ngày" được giới hạn trong sự lựa chọn của 7 ngày trong tuần trong mã (thông qua ORM). Để kiểm tra xem một doanh nghiệp có đóng cửa vào một ngày nhất định hay không, nó sẽ kiểm tra xem open_time và close_time là NULL. Nó liên quan đến doanh nghiệp thông qua một bảng trung gian (Mối quan hệ Nhiều Đến Nhiều).

Có ai có bất kỳ đề xuất cho chương trình cơ sở dữ liệu này? Có điều gì đó về nó dường như không đúng với tôi.


4
Tại sao bạn cần mối quan hệ M-to-M giữa bảng business_hours và bảng doanh nghiệp? Nếu bạn thực sự muốn nhiều doanh nghiệp chia sẻ cùng một bản ghi trong business_hours, tại sao? Về mặt ngữ nghĩa, thực tế là "công ty C làm việc từ T1 đến T2 vào ngày D" đúng hơn là một đối tượng giá trị hơn là một thực thể ... Lý do tốt (?) Duy nhất mà tôi có thể tưởng tượng là tối ưu hóa kích thước lưu trữ (phiên bản RDB của mẫu Flyweight, so to speak) nếu số lượng các doanh nghiệp dự kiến sẽ rất lớn ...
Yarik

2
Giờ nghỉ trưa thì sao? Còn những ngày nghỉ lễ thì sao?
Mawg nói Khôi phục Monica

Câu trả lời:


56

Nhìn chung, tôi thấy không có gì sai với điều này. Ngoại trừ...

  1. Tôi sẽ lưu trữ ngày trong tuần dưới dạng số nguyên bằng cách sử dụng bất kỳ hệ thống đánh số nào mà ngôn ngữ lập trình bản địa của bạn sử dụng (trong các thư viện của nó). Điều này sẽ làm giảm kích thước của cơ sở dữ liệu và loại bỏ các so sánh chuỗi khỏi mã của bạn.

  2. Tôi có lẽ sẽ đặt khóa ngoại cho bảng kinh doanh ngay tại bảng này. Bằng cách đó, bạn sẽ không cần một bảng liên kết.

Vì vậy, tôi đoán tôi sẽ làm:

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
)

Theo logic kinh doanh của tôi, tôi sẽ thực thi một ràng buộc rằng mọi "doanh nghiệp" có ít nhất 7 "giờ làm việc". ( Ít nhất vì Jon Skeet đúng, bạn có thể muốn có giờ nghỉ lễ.) Mặc dù bạn có thể muốn nới lỏng ràng buộc này bằng cách đơn giản là bỏ "giờ làm việc" cho những ngày doanh nghiệp đóng cửa.


1
Bạn sẽ làm như thế nào? Có tất cả các mục nhập cho tất cả các doanh nghiệp ngay cả khi ngày / giờ giống nhau?
Vinko Vrsalovic

7
Tôi sẽ nói có. Nếu không, hãy xem xét điều gì sẽ xảy ra nếu hai doanh nghiệp có cùng giờ làm việc, nhưng sau đó một trong số họ cần thay đổi giờ của họ. Bạn sẽ phải phát hiện sự thật là giờ đã bị thay đổi và tạo một bản ghi mới hoặc chỉnh sửa bản ghi hiện có, tùy thuộc vào việc nó được chia sẻ hay không.
Erik Forbes

3
Tôi hoàn toàn sẽ không chia sẻ các hàng của bảng này giữa các doanh nghiệp. Chia sẻ kiểu đó chỉ dẫn đến đau đớn. Logic nghiệp vụ của ứng dụng chỉ nên thực thi ràng buộc mà mọi doanh nghiệp có ít nhất 7 tham chiếu "business_hours".
Frank Krueger

1
@Vinko: Hãy nhớ rằng mặc dù các giá trị (hiện tại) giống nhau, nhưng giờ mở cửa của hai doanh nghiệp lại khác nhau về mặt ngữ nghĩa.
Draemon

1
Bạn cũng có thể sử dụng một bitmap 7 bit cho "ngày". Bằng cách đó, bạn không phải lặp lại các mục giống nhau Ví dụ tất cả các ngày làm việc có cùng giờ làm việc, một mục nhập là đủ.
ZolaKt

28

Một tình huống không được đề cập trong lược đồ này là một số khoảng thời gian mở trong một ngày. Ví dụ: quán rượu địa phương mở cửa từ 12: 00-14: 30 và 17: 00-23: 00.

Có thể phòng vé ở rạp chiếu phim mở cửa cho một buổi biểu diễn matinee và buổi tối.

Tại thời điểm đó, bạn cần quyết định xem bạn có thể có nhiều mục nhập cho cùng một ngày hay bạn cần thể hiện các giờ khác nhau trong cùng một hàng.

Còn về thời gian mở cửa kéo dài đến nửa đêm. Giả sử một quán bar mở cửa 19: 00-02: 00. Bạn không thể chỉ so sánh thời gian mở và đóng cửa với thời gian bạn muốn kiểm tra.


Tôi đã kết thúc việc làm như @JordanFeldstein đã đề xuất. Tôi lưu trữ các mảng "trạng thái thay đổi", bao gồm thay đổi (mở hoặc đóng), ngày trong tuần và thời gian trong ngày. Tôi có thể có nhiều "thay đổi" như tôi muốn cho mỗi doanh nghiệp và mỗi ngày. Một doanh nghiệp có thể mở cửa một ngày và đóng cửa ngày hôm sau, mở cửa hai lần (hoặc x lần) mỗi ngày, mở cửa 24 giờ nhưng đóng cửa vào Thứ Hai, tùy ý. Thật khó để thực hiện, nhưng rất linh hoạt.
ironcito

Theo cách tiếp cận câu trả lời tốt nhất, tôi muốn thêm hai cột vào business_hours: break_timebreak_duration. Thực sự hiếm khi có 2 lần nghỉ giải lao trong cùng một ngày.
Frondor

12

Nó phụ thuộc vào việc bạn cần lưu trữ nó để làm gì và dữ liệu trong thế giới thực có thể trông như thế nào.
Nếu bạn cần xác định xem doanh nghiệp có mở cửa tại một thời điểm nhất định hay không thì có thể hơi khó xử khi truy vấn sơ đồ như đã trình bày. Tuy nhiên, quan trọng hơn là: Bạn có bao giờ cần phục vụ cho việc đóng cửa giữa ngày không?

Một số tùy chọn bao gồm;

  • Một sơ đồ giống như những gì bạn có, nhưng với tùy chọn có nhiều khoảng thời gian trong cùng một ngày. Nó sẽ phục vụ cho giờ nghỉ trưa, nhưng sẽ gây khó khăn khi chạy một truy vấn cung cấp cho bạn giờ mở cửa của một ngày nhất định, chẳng hạn như trình bày cho người dùng.
  • Cách tiếp cận kiểu bitmap; "000000000111111110000000" cho ngày 9-5. Nhược điểm của phương pháp này là bạn phải chọn một mức độ chi tiết cụ thể, tức là cả giờ hoặc nửa giờ hoặc thực tế là vài phút. Độ chi tiết càng tốt, thì con người càng khó đọc dữ liệu. Bạn có thể sử dụng toán tử bitwise để lưu trữ giá trị này dưới dạng một số duy nhất chứ không phải là một chuỗi số nguyên, nhưng một lần nữa, điều này làm ảnh hưởng đến tính dễ đọc.

11

Tôi đã biết rằng nếu bạn muốn đánh dấu dữ liệu của Google nhận ra dữ liệu của bạn, bạn nên làm theo các nguyên tắc sau:

https://schema.org/openingHours

http://schema.org/OpeningHoursSpecification Chứa "ngày hợp lệ", rất hữu ích cho một số doanh nghiệp.

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

Bạn sẽ ổn nếu không có khóa chính, trừ khi bạn cho phép các doanh nghiệp chia sẻ cùng giờ với bảng tham gia - thú vị là cuối cùng bạn sẽ có một số lượng kết hợp hữu hạn; Tôi không chắc đó sẽ là bao nhiêu: p

Với một trong những dự án của mình, tôi đã sử dụng các cột:

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

Nếu bạn muốn hỗ trợ OpeningHoursSpecification thì bạn sẽ cần thêm validFrom và validThrough.

Phạm vi thời gian được định dạng như sau: hh: mm-hh: mm

Đây là một hàm phân tích cú pháp nó, bạn cũng có thể sửa đổi hàm này để phân tích cú pháp chỉ một lần mở / đóng duy nhất, nếu bạn giữ chúng dưới dạng các cột riêng biệt trong DB.

Theo kinh nghiệm của tôi, tôi khuyên bạn nên cho phép nhiều lần trong một ngày, cho phép một cách để biết liệu họ có đóng cửa rõ ràng vào ngày đó hay mở cửa 24 giờ hoặc 24/7. Tôi đã nói rằng nếu thiếu một ngày trong DB thì ngày đó doanh nghiệp đã đóng cửa.

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

Hầu hết các kết quả đều hoạt động tốt cho tình huống đã cho, nhưng nó sẽ không hiệu quả nếu bạn có kinh nguyệt kéo dài nhiều ngày, chẳng hạn. 8:00 sáng ~ 2:00 sáng, thì tôi khuyên bạn nên sử dụng thiết kế nhiều giai đoạn.

   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

Có thể suy nghĩ về bao thanh toán trong các ngày lễ bằng cách bao gồm các trường bổ sung cho tháng trong năm / ngày của tháng / tuần trong tháng. Tuần trong tháng có một số phụ nhỏ "cuối cùng", ví dụ có thể là tuần 4 hoặc 5 tùy thuộc vào năm.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.