Sementara jawaban yang diterima saat ini sangat membantu saya, saya ingin berbagi beberapa modifikasi berguna yang menyederhanakan pertanyaan dan juga meningkatkan kinerja.
Acara Ulangi "Sederhana"
Untuk menangani acara yang berulang secara berkala, seperti:
Repeat every other day
atau
Repeat every week on Tuesday
Anda harus membuat dua tabel, yang disebut events
seperti ini:
ID NAME
1 Sample Event
2 Another Event
Dan sebuah tabel bernama events_meta
seperti ini:
ID event_id repeat_start repeat_interval
1 1 1369008000 604800 -- Repeats every Monday after May 20th 2013
1 1 1369008000 604800 -- Also repeats every Friday after May 20th 2013
Dengan repeat_start
menjadi tanggal cap waktu unix tanpa waktu (1369008000 sesuai dengan 20 Mei 2013), dan repeat_interval
jumlah dalam detik antar interval (604800 adalah 7 hari).
Dengan mengulang setiap hari di kalender, Anda bisa mendapatkan acara berulang menggunakan kueri sederhana ini:
SELECT EV.*
FROM `events` EV
RIGHT JOIN `events_meta` EM1 ON EM1.`event_id` = EV.`id`
WHERE (( 1299736800 - repeat_start) % repeat_interval = 0 )
Cukup gantikan dengan cap waktu unix (1299736800) untuk setiap tanggal di kalender Anda.
Perhatikan penggunaan modulo (tanda%). Simbol ini seperti pembagian reguler, tetapi mengembalikan '' sisa '' alih-alih hasil bagi, dan dengan demikian adalah 0 setiap kali tanggal saat ini adalah kelipatan dari repeat_interval dari repeat_start.
Perbandingan Kinerja
Ini jauh lebih cepat daripada jawaban berbasis-meta_keys yang disarankan sebelumnya, yaitu sebagai berikut:
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
Jika Anda menjalankan EXPLAIN kueri ini, Anda akan mencatat bahwa itu mengharuskan penggunaan buffer gabungan:
+----+-------------+-------+--------+---------------+---------+---------+------------------+------+--------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+--------+---------------+---------+---------+------------------+------+--------------------------------+
| 1 | SIMPLE | EM1 | ALL | NULL | NULL | NULL | NULL | 2 | Using where |
| 1 | SIMPLE | EV | eq_ref | PRIMARY | PRIMARY | 4 | bcs.EM1.event_id | 1 | |
| 1 | SIMPLE | EM2 | ALL | NULL | NULL | NULL | NULL | 2 | Using where; Using join buffer |
+----+-------------+-------+--------+---------------+---------+---------+------------------+------+--------------------------------+
Solusi dengan 1 bergabung di atas tidak memerlukan buffer seperti itu.
Pola "Kompleks"
Anda dapat menambahkan dukungan untuk jenis yang lebih kompleks untuk mendukung jenis aturan berulang ini:
Event A repeats every month on the 3rd of the month starting on March 3, 2011
atau
Event A repeats second Friday of the month starting on March 11, 2011
Tabel acara Anda dapat terlihat persis sama:
ID NAME
1 Sample Event
2 Another Event
Kemudian untuk menambahkan dukungan untuk aturan-aturan kompleks ini tambahkan kolom events_meta
seperti:
ID event_id repeat_start repeat_interval repeat_year repeat_month repeat_day repeat_week repeat_weekday
1 1 1369008000 604800 NULL NULL NULL NULL NULL -- Repeats every Monday after May 20, 2013
1 1 1368144000 604800 NULL NULL NULL NULL NULL -- Repeats every Friday after May 10, 2013
2 2 1369008000 NULL 2013 * * 2 5 -- Repeats on Friday of the 2nd week in every month
Catatan bahwa Anda hanya perlu baik menentukan repeat_interval
atau satu set repeat_year
, repeat_month
, repeat_day
, repeat_week
, dan repeat_weekday
data.
Ini membuat pemilihan kedua jenis secara bersamaan sangat sederhana. Lewati saja setiap hari dan isi nilai yang benar, (1370563200 untuk 7 Juni 2013, lalu tahun, bulan, hari, nomor minggu, dan hari kerja sebagai berikut):
SELECT EV.*
FROM `events` EV
RIGHT JOIN `events_meta` EM1 ON EM1.`event_id` = EV.`id`
WHERE (( 1370563200 - repeat_start) % repeat_interval = 0 )
OR (
(repeat_year = 2013 OR repeat_year = '*' )
AND
(repeat_month = 6 OR repeat_month = '*' )
AND
(repeat_day = 7 OR repeat_day = '*' )
AND
(repeat_week = 2 OR repeat_week = '*' )
AND
(repeat_weekday = 5 OR repeat_weekday = '*' )
AND repeat_start <= 1370563200
)
Ini mengembalikan semua peristiwa yang berulang pada hari Jumat minggu ke-2, serta setiap peristiwa yang berulang setiap hari Jumat, sehingga mengembalikan kedua peristiwa ID 1 dan 2:
ID NAME
1 Sample Event
2 Another Event
* Sidenote dalam SQL I di atas menggunakan indeks hari kerja default Tanggal PHP , jadi "5" untuk hari Jumat
Semoga ini bisa membantu orang lain sebanyak jawaban asli membantu saya!
1299132000
hardcoded? Apa yang akan dilakukan jika saya perlu mendapatkan tanggal dan pengguna untuk tanggal akhir tertentu?