Şu anda kabul edilen cevap bana çok yardımcı olsa da, sorguları basitleştiren ve performansı artıran bazı yararlı değişiklikleri paylaşmak istedim.
"Basit" Tekrar Olaylar
Düzenli aralıklarla tekrarlanan olayları işlemek, örneğin:
Repeat every other day
veya
Repeat every week on Tuesday
Biri şu şekilde adlandırılan iki tablo oluşturmalısınız events
:
ID NAME
1 Sample Event
2 Another Event
Ve şöyle bir tablo events_meta
:
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
İle repeat_start
hiçbir zaman (20 Mayıs 2.013-1369008000 tekabül) ve bir unix zaman tarih olmak repeat_interval
aralıklarla arasındaki saniyede bir miktarda (604800 7 gündür).
Takvimdeki her günü tekrarlayarak bu basit sorguyu kullanarak tekrarlanan etkinlikler alabilirsiniz:
SELECT EV.*
FROM `events` EV
RIGHT JOIN `events_meta` EM1 ON EM1.`event_id` = EV.`id`
WHERE (( 1299736800 - repeat_start) % repeat_interval = 0 )
Sadece takviminizdeki her tarih için unix-zaman damgasını (1299736800) kullanın.
Modulo (% işareti) kullanımını not edin. Bu sembol normal bölüm gibidir, ancak bölüm yerine '' kalan '' değerini döndürür ve geçerli tarih, repeat_start öğesinin repeat_interval değerinin tam katı olduğunda 0 olur.
Performans karşılaştırması
Bu, daha önce önerilen "meta_keys" tabanlı cevaptan önemli ölçüde daha hızlıdır;
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
Bu sorguyu EXPLAIN çalıştırırsanız, bir birleştirme arabelleği kullanılmasını gerektirdiğini göreceksiniz:
+----+-------------+-------+--------+---------------+---------+---------+------------------+------+--------------------------------+
| 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 |
+----+-------------+-------+--------+---------------+---------+---------+------------------+------+--------------------------------+
Yukarıdaki 1 birleştirmeye sahip çözelti böyle bir tampon gerektirmez.
"Karmaşık" Desenler
Bu tür tekrarlama kurallarını desteklemek için daha karmaşık türler için destek ekleyebilirsiniz:
Event A repeats every month on the 3rd of the month starting on March 3, 2011
veya
Event A repeats second Friday of the month starting on March 11, 2011
Etkinlikler tablonuz tamamen aynı görünebilir:
ID NAME
1 Sample Event
2 Another Event
Sonra bu karmaşık kurallar için destek eklemek için aşağıdaki events_meta
gibi sütunlar ekleyin :
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
Sadece bir belirtmeniz ya gerektiğini Not repeat_interval
veya bir dizi repeat_year
, repeat_month
, repeat_day
, repeat_week
, ve repeat_weekday
veri.
Bu, her iki türün seçimini aynı anda çok basit hale getirir. Her bir güne göz atın ve doğru değerleri girin (7 Haziran 2013 için 1370563200 ve ardından yıl, ay, gün, hafta numarası ve hafta içi günleri aşağıdaki gibi):
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
)
Bu, 2. haftanın Cuma günü yinelenen tüm etkinliklerin yanı sıra her Cuma yinelenen tüm etkinlikleri döndürür, böylece hem etkinlik kimliği 1 hem de 2'yi döndürür:
ID NAME
1 Sample Event
2 Another Event
* Yukarıdaki SQL Sidenote PHP Tarihinin varsayılan hafta içi dizinleri kullandım, bu yüzden Cuma günü "5"
Umarım bu, orijinal cevap bana yardımcı olduğu kadar başkalarına da yardımcı olur!
1299132000
kodlanmış olduğunu açıklayabilir misiniz ? Belirtilen bitiş tarihi için gerçekleşme tarihlerini ve kullanıcıyı almam gerekirse ne yapar?