私はカスタム イベント システムを構築していますが、次のような繰り返しイベントがあるとします。
イベント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
これを上記の方法と組み合わせると、ほとんどの繰り返し/反復イベント パターンをカバーできます。何か見落としがあれば、コメントを残してください。