カレンダーの繰り返しイベント - 最適な保存方法 質問する

カレンダーの繰り返しイベント - 最適な保存方法 質問する

私はカスタム イベント システムを構築していますが、次のような繰り返しイベントがあるとします。

イベントAは2011年3月3日から4日ごとに繰り返されます

または

イベント B は、2011 年 3 月 1 日から 2 週間ごとに火曜日に繰り返されます。

それをデータベースに保存して、簡単に検索できるようにするにはどうすればよいでしょうか。イベントが多数あり、カレンダーをレンダリングするときに 1 つ 1 つ確認しなければならない場合にパフォーマンス上の問題が発生しないようにしたいです。

ベストアンサー1

「単純な」繰り返しパターンを保存する

PHP/MySQL ベースのカレンダーでは、繰り返し/定期的なイベント情報をできるだけ効率的に保存したいと考えていました。行数を多くしたくないし、特定の日付に行われるすべてのイベントを簡単に検索したいと考えていました。

以下の方法は、毎日、 n日ごと、毎週、毎月、毎年など、定期的に発生する繰り返し情報を保存するのに最適です。これには毎週火曜日と木曜日のパターンも含まれます。これは、毎週火曜日から始まる週と毎週木曜日から始まる週として別々に保存されるためです。

2 つのテーブルがあり、そのうちの 1 つはevents次のように呼び出されると仮定します。

ID    NAME
1     Sample Event
2     Another Event

そして、次のようなテーブルがありますevents_meta:

ID    event_id      meta_key           meta_value
1     1             repeat_start       1299132000
2     1             repeat_interval_1  432000

repeat_start は、UNIX タイムスタンプとして時間のない日付であり、repeat_interval は間隔間の秒数です (432000 は 5 日)。

repeat_interval_1 は、ID 1 の repeat_start と連動します。したがって、毎週火曜日と毎週木曜日に繰り返すイベントがある場合、repeat_interval は 604800 (7 日) になり、2 つの repeat_start と 2 つの repeat_interval が存在します。テーブルは次のようになります。

ID    event_id      meta_key           meta_value
1     1             repeat_start       1298959200 -- This is for the Tuesday repeat
2     1             repeat_interval_1  604800
3     1             repeat_start       1299132000 -- This is for the Thursday repeat
4     1             repeat_interval_3  604800
5     2             repeat_start       1299132000
6     2             repeat_interval_5  1          -- Using 1 as a value gives us an event that only happens once

次に、毎日ループしてその日のイベントを取得するカレンダーがある場合、クエリは次のようになります。

SELECT EV.*
FROM `events` EV
RIGHT JOIN `events_meta` EM1 ON EM1.`event_id` = EV.`id`
RIGHT JOIN `events_meta` EM2 ON EM2.`meta_key` = CONCAT( 'repeat_interval_', EM1.`id` )
WHERE EM1.meta_key = 'repeat_start'
    AND (
        ( CASE ( 1299132000 - EM1.`meta_value` )
            WHEN 0
              THEN 1
            ELSE ( 1299132000 - EM1.`meta_value` )
          END
        ) / EM2.`meta_value`
    ) = 1
LIMIT 0 , 30

現在の日付の UNIX タイムスタンプに置き換えます{current_timestamp}(時刻をマイナスするため、時間、分、秒の値は 0 に設定されます)。

これが他の誰かの助けになれば幸いです!


「複雑な」繰り返しパターンを保存する

この方法は、次のような複雑なパターンを保存するのに適しています。

Event A repeats every month on the 3rd of the month starting on March 3, 2011

または

Event A repeats Friday of the 2nd week of the month starting on March 11, 2011

柔軟性を最大限に高めるには、これを上記のシステムと組み合わせることをお勧めします。このテーブルは次のようになります。

ID    NAME
1     Sample Event
2     Another Event

そして、次のようなテーブルがありますevents_meta:

ID    event_id      meta_key           meta_value
1     1             repeat_start       1299132000 -- March 3rd, 2011
2     1             repeat_year_1      *
3     1             repeat_month_1     *
4     1             repeat_week_im_1   2
5     1             repeat_weekday_1   6

repeat_week_im現在の月の週を表します。1 から 5 までの範囲になります。repeat_weekday曜日の場合は 1 から 7 までになります。

ここで、日/週をループしてカレンダーに月表示を作成すると仮定すると、次のようなクエリを作成できます。

SELECT EV . *
FROM `events` AS EV
JOIN `events_meta` EM1 ON EM1.event_id = EV.id
AND EM1.meta_key = 'repeat_start'
LEFT JOIN `events_meta` EM2 ON EM2.meta_key = CONCAT( 'repeat_year_', EM1.id )
LEFT JOIN `events_meta` EM3 ON EM3.meta_key = CONCAT( 'repeat_month_', EM1.id )
LEFT JOIN `events_meta` EM4 ON EM4.meta_key = CONCAT( 'repeat_week_im_', EM1.id )
LEFT JOIN `events_meta` EM5 ON EM5.meta_key = CONCAT( 'repeat_weekday_', EM1.id )
WHERE (
  EM2.meta_value =2011
  OR EM2.meta_value = '*'
)
AND (
  EM3.meta_value =4
  OR EM3.meta_value = '*'
)
AND (
  EM4.meta_value =2
  OR EM4.meta_value = '*'
)
AND (
  EM5.meta_value =6
  OR EM5.meta_value = '*'
)
AND EM1.meta_value >= {current_timestamp}
LIMIT 0 , 30

これを上記の方法と組み合わせると、ほとんどの繰り返し/反復イベント パターンをカバーできます。何か見落としがあれば、コメントを残してください。

おすすめ記事