Лучший способ сохранить рабочее время и эффективно запрашивать его - PullRequest
38 голосов
/ 16 декабря 2010

Я планирую хранить рабочее время для магазинов.Мне интересно, что может быть лучшим моделированием для поля рабочего времени, чтобы я мог очень эффективно получить список открытых / закрытых магазинов на текущий момент.

Ответы [ 2 ]

56 голосов
/ 16 декабря 2010

Для хранения часов нормальной работы вам необходимо хранить несколько записей, содержащих:

  • Магазин - INTEGER
  • DayOfWeek - INTEGER (0-6)
  • OpenTime - ВРЕМЯ
  • CloseTime - ВРЕМЯ

Я полагаю, например, что в каждом магазине сокращено количество часов во время национальных праздников или отключены заводы, поэтому вам также необходимо сохранить некоторые записи о переопределениях:

  • Магазин - INTEGER
  • OverrideStartDate - DATE
  • OverrideEndDate - DATE
  • DayOfWeek - INTEGER (0-6)
  • AltOpenTime - ВРЕМЯ
  • AltCloseTime - ВРЕМЯ
  • Закрыто - INTEGER (0, 1)

Найти открытые магазины тривиально, но вам также нужно проверить, есть ли часы переопределения:

SELECT Shop
FROM OverrideHours
WHERE OverrideStartDate <= NOW()
AND OverrideEndDate >= NOW()
AND DayOfWeek = WEEKDAY(NOW())

Если какие-либо записи возвращаются, эти магазины имеют альтернативные часы или закрыты.

Может быть, есть несколько хороших SQL-фу, которые вы можете здесь сделать, но это дает вам основы.

EDIT

Я не проверял это, но это должно приблизить вас:

SELECT Normal.Shop
FROM Normal
LEFT JOIN Override
ON Normal.Shop = Override.Shop
AND Normal.DayOfWeek = Override.DayOfWeek
AND NOW() BETWEEN Override.OverrideStartDate AND Override.OverrideEndDate
WHERE Normal.DayOfWeek = WEEKDAY(NOW())
AND ((Override.Shop IS NULL AND TIME(NOW()) BETWEEN Normal.OpenTime AND Normal.CloseTime)
 OR  (Override.Shop IS NOT NULL AND Override.Closed <> 1 AND TIME(NOW()) BETWEEN Override.AltOpenTime AND Override.AltCloseTime))

EDIT

Что касается эффективности, то она эффективна в том смысле, что вам нужно всего лишь сделать один вызов MySQL, который часто является узким местом, если он находится в сети. Вам придется проверить и посмотреть, соответствует ли это вашим требованиям. Если нет, возможно, вам стоит поиграть с некоторыми индексами.

EDIT

Тестирование. Не полное тестирование, но некоторые.

mysql> select * from Normal;
+------+-----------+----------+-----------+
| Shop | DayOfWeek | OpenTime | CloseTime |
+------+-----------+----------+-----------+
|    1 |         1 | 09:00:00 | 17:00:00  | 
|    1 |         5 | 09:00:00 | 16:00:00  | 
|    2 |         1 | 09:00:00 | 17:00:00  | 
|    2 |         5 | 09:00:00 | 17:00:00  | 
+------+-----------+----------+-----------+
4 rows in set (0.01 sec)

mysql> select * from Override;
+------+-------------------+-----------------+-----------+-------------+--------------+--------+
| Shop | OverrideStartDate | OverrideEndDate | DayOfWeek | AltOpenTime | AltCloseTime | Closed |
+------+-------------------+-----------------+-----------+-------------+--------------+--------+
|    2 | 2010-12-01        | 2010-12-31      |         1 | 09:00:00    | 18:00:00     |      0 | 
|    2 | 2010-12-01        | 2010-12-31      |         5 | 09:00:00    | 18:00:00     |      0 | 
|    1 | 2010-12-01        | 2010-12-31      |         1 | 09:00:00    | 17:00:00     |      1 | 
+------+-------------------+-----------------+-----------+-------------+--------------+--------+
3 rows in set (0.00 sec)

mysql> SET @whenever = TIMESTAMP('2010-11-23 16:05');
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT WEEKDAY(@whenever);
+--------------------+
| WEEKDAY(@whenever) |
+--------------------+
|                  1 | 
+--------------------+
1 row in set (0.00 sec)

mysql> SELECT Normal.Shop FROM Normal LEFT JOIN Override ON Normal.Shop = Override.Shop AND Normal.DayOfWeek = Override.DayOfWeek AND @whenever BETWEEN Override.OverrideStartDate AND Override.OverrideEndDate WHERE Normal.DayOfWeek = WEEKDAY(@whenever) AND ((Override.Shop IS NULL AND TIME(@whenever) BETWEEN Normal.OpenTime AND Normal.CloseTime)  OR  (Override.Shop IS NOT NULL AND Override.Closed <> 1 AND TIME(@whenever) BETWEEN Override.AltOpenTime AND Override.AltCloseTime));
+------+
| Shop |
+------+
|    1 | 
|    2 | 
+------+
2 rows in set (0.00 sec)

mysql> SET @whenever = TIMESTAMP('2010-11-23 17:05');
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT Normal.Shop FROM Normal LEFT JOIN Override ON Normal.Shop = Override.Shop AND Normal.DayOfWeek = Override.DayOfWeek AND @whenever BETWEEN Override.OverrideStartDate AND Override.OverrideEndDate WHERE Normal.DayOfWeek = WEEKDAY(@whenever) AND ((Override.Shop IS NULL AND TIME(@whenever) BETWEEN Normal.OpenTime AND Normal.CloseTime)  OR  (Override.Shop IS NOT NULL AND Override.Closed <> 1 AND TIME(@whenever) BETWEEN Override.AltOpenTime AND Override.AltCloseTime));
Empty set (0.01 sec)

mysql> SET @whenever = TIMESTAMP('2010-12-25 16:05');
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT Normal.Shop FROM Normal LEFT JOIN Override ON Normal.Shop = Override.Shop AND Normal.DayOfWeek = Override.DayOfWeek AND @whenever BETWEEN Override.OverrideStartDate AND Override.OverrideEndDate WHERE Normal.DayOfWeek = WEEKDAY(@whenever) AND ((Override.Shop IS NULL AND TIME(@whenever) BETWEEN Normal.OpenTime AND Normal.CloseTime)  OR  (Override.Shop IS NOT NULL AND Override.Closed <> 1 AND TIME(@whenever) BETWEEN Override.AltOpenTime AND Override.AltCloseTime));
+------+
| Shop |
+------+
|    2 | 
+------+
1 row in set (0.00 sec)

mysql> SET @whenever = TIMESTAMP('2010-11-23 17:05');
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT WEEKDAY(@whenever);
+--------------------+
| WEEKDAY(@whenever) |
+--------------------+
|                  1 | 
+--------------------+
1 row in set (0.00 sec)

mysql> SELECT Normal.Shop FROM Normal LEFT JOIN Override ON Normal.Shop = Override.Shop AND Normal.DayOfWeek = Override.DayOfWeek AND @whenever BETWEEN Override.OverrideStartDate AND Override.OverrideEndDate WHERE Normal.DayOfWeek = WEEKDAY(@whenever) AND ((Override.Shop IS NULL AND TIME(@whenever) BETWEEN Normal.OpenTime AND Normal.CloseTime)  OR  (Override.Shop IS NOT NULL AND Override.Closed <> 1 AND TIME(@whenever) BETWEEN Override.AltOpenTime AND Override.AltCloseTime));
Empty set (0.00 sec)
9 голосов
/ 16 декабря 2010

Давайте рассмотрим, что все часы работы одинаковы каждую неделю.А как насчет следующей таблицы:

  • shop_id - INTEGER (или любой уникальный идентификатор магазина)
  • week_day - INTEGER (0 = понедельник - 6 = воскресенье)
  • opens_at - ВРЕМЯ (используйте ваш местный часовой пояс)
  • closes_at - ВРЕМЯ (используйте ваш местный часовой пояс)

Составьте таблицу для магазинов, обозначенных shop_id, а затем укажите часы работы, то есть:

  • 1, 0, 8:00, 17: 00
  • ...
  • 1, 5, 8:00, 12: 00
  • 2, 0, 7:30, 12: 30
  • 2, 0, 13:30, 17: 30
  • 2, 1, 7:30, 12:30
  • 2, 1, 13:30, 17: 30
  • ...

и затем ВЫБРАТЬ:

SELECT shop_id
FROM opening_hours
WHERE WEEKDAY(NOW()) = week_day
AND TIME(NOW()) BETWEEN opens_at AND closes_at
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...