जबकि वर्तमान में स्वीकृत उत्तर मेरे लिए बहुत बड़ी मदद थी, मैं कुछ उपयोगी संशोधनों को साझा करना चाहता था जो प्रश्नों को सरल बनाती हैं और प्रदर्शन को भी बढ़ाती हैं।
"सरल" घटनाओं को दोहराएं
नियमित अंतराल पर होने वाली घटनाओं को संभालने के लिए, जैसे:
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
ही समय (मई 20 वीं 2013 करने के लिए १३६९००८००० मेल खाती है), और के साथ एक यूनिक्स टाइमस्टैम्प तारीख जा रहा है repeat_interval
अंतराल के बीच की राशि सेकंड में (604,800 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 होता है जब भी वर्तमान तिथि रिपीट_स्टार्ट से रिपीट_एंटरवल का एक सटीक एकाधिक होता है।
प्रदर्शन की तुलना
यह पहले से सुझाए गए "मेटा_कीज़" की तुलना में काफी तेज है, जो कि इस प्रकार है:
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
डेटा।
इससे दोनों प्रकारों का चयन एक साथ बहुत सरल हो जाता है। बस प्रत्येक दिन के माध्यम से लूप करें और सही मान भरें, (7 जून 2013 के लिए 1370563200, और फिर वर्ष, माह, दिन, सप्ताह संख्या और सप्ताह का दिन निम्नानुसार है):
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
* उपरोक्त एसक्यूएल में मैंने PHP दिनांक के डिफ़ॉल्ट कार्यदिवस सूचकांक का उपयोग किया , इसलिए शुक्रवार के लिए "5"
आशा है कि यह दूसरों की मदद करता है जितना कि मूल उत्तर ने मेरी मदद की!
1299132000
हार्डकोड क्यों है? अगर मुझे दी गई अंतिम तिथि के लिए पश्चात की तारीख और उपयोगकर्ता प्राप्त करने की आवश्यकता है तो यह क्या करेगा?