ในขณะที่คำตอบที่ได้รับการยอมรับในขณะนี้เป็นสิ่งที่ช่วยฉันได้มากฉันต้องการแบ่งปันการดัดแปลงที่มีประโยชน์ซึ่งทำให้การสืบค้นง่ายขึ้นและเพิ่มประสิทธิภาพการทำงาน
ทำซ้ำเหตุการณ์ "ธรรมดา"
เมื่อต้องการจัดการเหตุการณ์ที่เกิดขึ้นในช่วงเวลาปกติเช่น:
Repeat every other day
หรือ
Repeat every week on Tuesday
คุณควรสร้างสองตารางหนึ่งที่เรียกว่าevents
:
ID NAME
1 Sample Event
2 Another Event
และตารางที่เรียกว่า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
ด้วยrepeat_start
การเป็นวันที่ประทับเวลา unix โดยไม่มีเวลา (1369008000 ตรงกับวันที่ 20 พฤษภาคม 2013) และrepeat_interval
จำนวนเป็นวินาทีระหว่างช่วงเวลา (604800 คือ 7 วัน)
ด้วยการวนลูปในแต่ละวันในปฏิทินคุณสามารถรับเหตุการณ์ที่เกิดซ้ำได้โดยใช้แบบสอบถามง่ายๆนี้:
SELECT EV.*
FROM `events` EV
RIGHT JOIN `events_meta` EM1 ON EM1.`event_id` = EV.`id`
WHERE (( 1299736800 - repeat_start) % repeat_interval = 0 )
เพียงแทนที่ในยูนิกซ์ - เวลา (1299736800) สำหรับแต่ละวันในปฏิทินของคุณ
สังเกตการใช้งานโมดูโล (เครื่องหมาย%) สัญลักษณ์นี้เป็นเหมือนส่วนปกติ แต่ส่งกลับ '' เศษเหลือ '' แทนความฉลาดและเป็น 0 เมื่อใดก็ตามที่วันที่ปัจจุบันเป็นพหุคูณที่แน่นอนของ repeat_interval จาก repeat_start
การเปรียบเทียบประสิทธิภาพ
สิ่งนี้เร็วกว่าคำตอบ "meta_keys" ที่แนะนำก่อนหน้านี้อย่างมากซึ่งมีดังต่อไปนี้:
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
หากคุณเรียกใช้อธิบายแบบสอบถามนี้คุณจะทราบว่าจำเป็นต้องใช้บัฟเฟอร์การเข้าร่วม:
+----+-------------+-------+--------+---------------+---------+---------+------------------+------+--------------------------------+
| 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 |
+----+-------------+-------+--------+---------------+---------+---------+------------------+------+--------------------------------+
โซลูชันที่มีการรวม 1 รายการข้างต้นไม่จำเป็นต้องใช้บัฟเฟอร์
รูปแบบ "ซับซ้อน"
คุณสามารถเพิ่มการสนับสนุนสำหรับประเภทที่ซับซ้อนมากขึ้นเพื่อสนับสนุนกฎการทำซ้ำประเภทเหล่านี้:
Event A repeats every month on the 3rd of the month starting on March 3, 2011
หรือ
Event A repeats second Friday of the month starting on March 11, 2011
ตารางกิจกรรมของคุณมีลักษณะเหมือนกันทุกประการ:
ID NAME
1 Sample Event
2 Another Event
จากนั้นเพื่อเพิ่มการสนับสนุนสำหรับกฎที่ซับซ้อนเหล่านี้เพิ่มคอลัมน์ที่events_meta
ชอบ
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
โปรดทราบว่าคุณก็ต้องทำอย่างใดอย่างหนึ่งระบุrepeat_interval
หรือชุดของrepeat_year
, repeat_month
, repeat_day
, repeat_week
และrepeat_weekday
ข้อมูล
ทำให้การเลือกทั้งสองประเภทพร้อมกันนั้นง่ายมาก เพียงวนซ้ำในแต่ละวันและกรอกค่าที่ถูกต้อง (1370563200 สำหรับวันที่ 7 มิถุนายน 2013 จากนั้นปีเดือนวันสัปดาห์และวันทำงานดังต่อไปนี้):
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
)
สิ่งนี้จะส่งคืนกิจกรรมทั้งหมดที่ทำซ้ำในวันศุกร์ของสัปดาห์ที่ 2 รวมถึงกิจกรรมใด ๆ ที่ทำซ้ำทุกวันศุกร์ดังนั้นจึงส่งคืนทั้งรหัสเหตุการณ์ 1 และ 2:
ID NAME
1 Sample Event
2 Another Event
* Sidenote ใน SQL ข้างต้นฉันใช้ดัชนีวันธรรมดาเริ่มต้นของ PHP Dateดังนั้น "5" สำหรับวันศุกร์
หวังว่านี่จะช่วยผู้อื่นได้มากเท่ากับคำตอบดั้งเดิมที่ช่วยฉัน!
1299132000
ได้ไหมว่าทำไมฮาร์ดโค้ดมาถึง จะทำอย่างไรถ้าฉันต้องการรับวันเกิดและผู้ใช้สำหรับวันที่สิ้นสุดที่กำหนด