[解決済み] カレンダーの繰り返し/繰り返しイベント - 最適な保存方法
質問
カスタムイベントシステムを構築しているのですが、以下のような繰り返しイベントがある場合。
イベントAは2011年3月3日から4日おきに繰り返される
または
イベントBは2011年3月1日から2週間おきに火曜日に開催されます。
どのようにすれば、簡単に検索できるようにデータベースに保存できますか?イベントが大量にあり、カレンダーをレンダリングする際に一つひとつを確認しなければならないような、パフォーマンスの問題は避けたいのです。
どのように解決するのですか?
単純な繰り返しパターンの格納
PHP/MySQLベースのカレンダーでは、繰り返し行われるイベント情報をできるだけ効率的に保存したいと考えました。行の数は多くしたくありませんでしたし、特定の日に行われるすべてのイベントを簡単に調べたいのです。
以下の方法は、毎日、毎正時、毎正時など、一定間隔で発生する繰り返し情報を格納するのに適しています。 n 日、毎週、毎月、毎年、などなど。これは、毎週火曜日と木曜日タイプのパターンも含みます。なぜなら、それらは火曜日から始まる毎週と木曜日から始まる毎週として別々に保存されるからです。
という2つのテーブルがあると仮定します。
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
置き換え
{current_timestamp}
を現在の日付の unix タイムスタンプに置き換えます (時刻を差し引くと、時、分、秒の値は 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
これを上記の方法と組み合わせることで、ほとんどの繰り返し/反復イベントのパターンをカバーすることができます。もし何か見逃していることがあれば、コメントを残してください。
関連
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン