1

こんにちは再びスタックオーバーフロー!

ここ数日、1 週間のスケジュールを 1 時間間隔で保存する適切な方法を考えていました。

スケジュールは次のとおりです。

Monday:
00:00 - 08:00: Sleeping
08:00 - 09:00: Shower & Breakfast
09:00 - 17:00: Work
17:00 - 18:00: Groceries
18:00 - 20:00: Making & Eating dinner
20:00 - 22:00: Relaxing
22:00 - 23:00: Shower & prepare for bed
23:00 - 24:00: Sleeping

そして、これは月曜日から日曜日までずっと、もちろん、曜日ごとに異なる時間と異なることを行います. 週の終わりに、次の週に別のスケジュールがない場合は問題ありませんが、34 週に別のスケジュールがある場合は、ユーザーが現在のスケジュールを取り、調整を維持して「スケジュール」することができます。 34 週目のみの新しいスケジュール。

前述したように、ここ数日、MySQL をセットアップするための適切な方法を考えていましたが、何も考えていませんでした。では、これに適した MySQL のセットアップを考えるのを手伝っていただけませんか?

4

2 に答える 2

3

多分これは物事を始めるでしょう:

days_of_week
+----+-------------------+
| id | name              |
+----+-------------------+
|  1 | Monday            |
|  2 | Tuesday           |
|  3 | Wednesday         |
|  4 | Thursday          |
|  5 | Friday            |
|  6 | Satday            |
|  7 | Sunday            |
+----+-------------------+

users
+----+-------------------+-----
| id | name              | ...
+----+-------------------+-----
|  1 | John              | ...
+----+-------------------+-----


schedules
+----+---------+-------------------+------------+
| id | user_id | name              | is_default |
+----+---------+-------------------+------------+
|  1 |       1 | Weekly Default    |          Y |
|  2 |       1 | Vacation          |          N |
+----+---------+-------------------+------------+

schedule_details
(NULL in day_of_week_id is the schedule for any day that is not explicitly set)
+----+-------------+----------------+-----------+-----------+--------------------------+
| id | schedule_id | day_of_week_id | from_time | thru_time | description              |
+----+-------------+----------------+-----------+-----------+--------------------------+
|  1 |           1 |           NULL |     00:00 |     08:00 | Sleeping                 |
|  2 |           1 |           NULL |     08:00 |     09:00 | Shower & Breakfast       |
|  3 |           1 |           NULL |     09:00 |     17:00 | Work                     |
|  4 |           1 |           NULL |     17:00 |     18:00 | Groceries                |
|  5 |           1 |           NULL |     18:00 |     20:00 | Making & Eating dinner   |
|  6 |           1 |           NULL |     20:00 |     22:00 | Relaxing                 |
|  7 |           1 |           NULL |     22:00 |     23:00 | Shower & prepare for bed |
|  8 |           1 |           NULL |     23:00 |     24:00 | Sleeping                 |
|  9 |           1 |              6 |     00:00 |     10:00 | Sleeping                 |
| 10 |           1 |              6 |     10:00 |     11:00 | Shower & Breakfast       |
| 11 |           1 |              6 |     11:00 |     17:00 | Play Golf                |
| 12 |           1 |              6 |     17:00 |     18:00 | Groceries                |
| 13 |           1 |              6 |     18:00 |     20:00 | Making & Eating dinner   |
| 14 |           1 |              6 |     20:00 |     22:00 | Relaxing                 |
| 15 |           1 |              6 |     22:00 |     23:00 | Shower & prepare for bed |
| 16 |           1 |              6 |     23:00 |     24:00 | Sleeping                 |
| 17 |           1 |              7 |     00:00 |     10:00 | Sleeping                 |
| 18 |           1 |              7 |     10:00 |     11:00 | Shower & Breakfast       |
| 19 |           1 |              7 |     11:00 |     17:00 | Go Sailing               |
| 20 |           1 |              7 |     17:00 |     18:00 | Groceries                |
| 21 |           1 |              7 |     18:00 |     20:00 | Making & Eating dinner   |
| 22 |           1 |              7 |     20:00 |     22:00 | Relaxing                 |
| 23 |           1 |              7 |     22:00 |     23:00 | Shower & prepare for bed |
| 24 |           1 |              7 |     23:00 |     24:00 | Sleeping                 |
| 25 |           2 |           NULL |     00:00 |     10:00 | Sleeping                 |
| 26 |           2 |           NULL |     10:00 |     11:00 | Shower & Breakfast       |
| 27 |           2 |           NULL |     11:00 |     17:00 | Play Golf                |
| 28 |           2 |           NULL |     18:00 |     20:00 | Go out to dinner         |
| 29 |           2 |           NULL |     20:00 |     22:00 | Relaxing                 |
| 30 |           2 |           NULL |     22:00 |     23:00 | Shower & prepare for bed |
| 31 |           2 |           NULL |     23:00 |     24:00 | Sleeping                 |
+----+-------------+----------------+-----------+-----------+--------------------------+

weekly_schedules
+----+---------+---------+-------------+
| id | user_id | week_no | schedule_id |
+----+---------+---------+-------------+
|  1 |       1 |      34 |           2 |
+----+---------+---------+-------------+

毎週のスケジュールの選択:

SELECT dow.id
      ,dow.name
      ,sd.from_time
      ,sd.thru_time
      ,sd.description

  FROM days_of_week      dow

  JOIN users             u
    ON u.id              = :user_id

  LEFT OUTER
  JOIN weekly_schedules  ws
    ON ws.user_id        = u.id
   AND ws.week_no        = :week_no

  JOIN schedules         s
    ON s.user_id         = u.id
   AND ( (ws.week_no IS NULL AND s.is_default = 'Y')
      OR (ws.week_no IS NOT NULL AND s.id = ws.schedule_id)
       )

  LEFT OUTER
  JOIN (SELECT DISTINCT schedule_id, day_of_week_id
          FROM schedules        ss
          JOIN schedule_details sds
            ON ss.user_id       = :user_id
           AND sds.schedule_id  = ss.id
           AND sds.day_of_week_id IS NOT NULL
       ) sdow
    ON sdow.schedule_id    = s.id
   AND sdow.day_of_week_id = dow.id

  JOIN schedule_details  sd
    ON sd.schedule_id      = s.id
   AND ( (sdow.day_of_week_id IS NOT NULL AND sd.day_of_week_id = sdow.day_of_week_id)
      OR (sdow.day_of_week_id IS NULL AND sd.day_of_week_id IS NULL)
       )

 ORDER BY dow.id, sd.from_time

SQLFiddle: http://sqlfiddle.com/#!2/7fc91/8AND ws.week_no = 22に変更してテストしAND ws.week_no = 34ます。

ユーザーは任意の数の「スケジュール」を持つことができ、そのうちの 1 つが必要であり、1 つだけが既定のスケジュールになることができます。デフォルトのスケジュールは、明示的なスケジュールのオーバーライドがない週に使用されます。

各スケジュールには、1 週間を通して実行されるアクティビティを識別する、任意の数の schedule_details を含めることができます。

各スケジュールの詳細には、1 つのデフォルト日 (day_of_week_id 列の NULL で識別される) と、その日の任意の数のアクティビティを含めることができます。明示的に定義されていない日は、デフォルトの日のスケジュールを使用します。

更新しました

過去のスケジュールを保持できるようにする場合は、デフォルトのスケジュールを有効にする必要があります。schedules.is_default 列を削除し、別のテーブルに置き換えます。

schedule_defaults
+---------+------------+-------------+
| user_id |schedule_id | eff_week_no |
+---------+------------+-------------+
|       1 |          1 |          18 |
+---------+------------+-------------+

次に、それに応じて SELECT を調整します。

SELECT u.name
      ,dow.id
      ,dow.name
      ,sd.from_time
      ,sd.thru_time
      ,sd.description

  FROM days_of_week      dow

  JOIN users             u
    ON u.id              = :user_id

  LEFT OUTER
  JOIN weekly_schedules  ws
    ON ws.user_id        = u.id
   AND ws.week_no        = :week_no

  JOIN schedule_defaults sdef
    ON sdef.user_id      = u.id
   AND sdef.eff_week_no  = (SELECT MAX(eff_week_no)
                              FROM schedule_defaults
                             WHERE user_id      = :user_id
                               AND eff_week_no <= :week_no
                           )

  JOIN schedules         s
    ON s.user_id         = u.id
   AND ( (ws.week_no IS NULL AND s.id = sdef.schedule_id)
      OR (ws.week_no IS NOT NULL AND s.id = ws.schedule_id)
       )

  LEFT OUTER
  JOIN (SELECT DISTINCT schedule_id, day_of_week_id
          FROM schedules        ss
          JOIN schedule_details sds
            ON ss.user_id       = :user_id
           AND sds.schedule_id  = ss.id
           AND sds.day_of_week_id IS NOT NULL
       ) sdow
    ON sdow.schedule_id    = s.id
   AND sdow.day_of_week_id = dow.id

  JOIN schedule_details  sd
    ON sd.schedule_id      = s.id
   AND ( (sdow.day_of_week_id IS NOT NULL AND sd.day_of_week_id = sdow.day_of_week_id)
      OR (sdow.day_of_week_id IS NULL AND sd.day_of_week_id IS NULL)
       )

 ORDER BY dow.id, sd.from_time

履歴を保持するための SQLFiddle: http://sqlfiddle.com/#!2/e721c/10

于 2013-09-14T22:51:39.287 に答える
0

あなたの質問に対する「最良の」答えはないと思います。いくつかのスキーマを提供しますが、同様に良い回答が他にもある可能性があります。

shedule_map          schedule       activity
------------------------------------------------
id                    id             id
user_id               schedule_id    schedule_id  
default_schedule_id   user_id        date
                      startOfWeek    start_hour
                                     end_hour
                                     activity_description

「Schedule」テーブルは毎週、ユーザーごとに 1 つのエントリを取得します。ユーザーが「スケジュール」テーブルで現在の週のデフォルト スケジュールを選択すると、schedule_id が schedule_map から取得されます。その他の場合、schedule_id = MAX(schedule_id) + 1 であり、この新しいスケジュールの新しいアクティビティが作成されます。user_id = 10 のスキーマから今日のアクティビティを取得します。

SELECT act.start_hour, act.end_hour, act.activity_descripton
FROM activity act
INNER JOIN schedule s
USING (schedule_id)
WHERE s.startOfWeek = (
  SELECT MAX(startOfWeek)
  FROM schedule
  WHERE startOfWeek < NOW()
)
AND s.user_id = 10
ORDER BY act.start_hour

私は主にORMを使用していますが、サブクエリに問題があるため、startOfWeekは他のクエリから取得できる現在の日付に適しています。

ユーザーごとに 1 週​​間に 1 つの追加エントリが問題になることはないと思います。ただし、そうであると思われる場合は、ユーザーがデフォルトのスケジュールを選択した場合に、「custom_schedule_id」を NULL に設定して「schedule_map」テーブル列に追加できます。ただし、ユーザーがカスタム スケジュールを使用するかどうか、またはより複雑なクエリが必要になるかどうかを最初に判断する必要があります。例

SELECT act.start_hour, act.end_hour, act.activity_descripton
FROM activity act
INNER JOIN schedule s
ON act.schedule_id = s.schedule_id
INNER JOIN schedule_map sm
ON sm.user_id = s.user_id 
AND sm.custom_schedule_id = s.schedule_id
WHERE s.user_id = 10
ORDER BY act.start_hour
UNION ALL
SELECT act.start_hour, act.end_hour, act.activity_descripton
FROM activity act
INNER JOIN schedule s
ON act.schedule_id = s.schedule_id
INNER JOIN schedule_map sm
ON sm.user_id = s.user_id 
AND sm.default_schedule_id = s.schedule_id 
AND sm.custom_schedule_id IS NULL
WHERE s.user_id = 10
ORDER BY act.start_hour
于 2013-09-14T23:23:15.027 に答える