Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
667 views
in Technique[技术] by (71.8m points)

mysql - Repeating calendar events and some final maths

I am trying to have a go at the infamous repeating events on calendars using PHP/MySQL. I've finally found something that seems to work. I found my answer here but I'm having a little difficulty finishing it off.

My first table 'events'.

ID    NAME
1     Sample Event
2     Another Event

My second table 'events_meta that stores the repeating data.

ID    event_id      meta_key           meta_value
1     1             repeat_start       1336312800 /* May 7th 2012 */
2     1             repeat_interval_1  432000 /* 5 days */

With repeat_start being a date with no time as a unix timestamp, and repeat_interval an amount in seconds between intervals (432000 is 5 days).

I then have the following MySQL which I modified slightly from the above link. The timestamp used below (1299132000 which is 12th May 2012) is the current day with no time.

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 ( 1336744800 - EM1.`meta_value` )
            WHEN 0
              THEN 1
            ELSE ( 1336744800 - EM1.`meta_value` ) / EM2.`meta_value`
          END
        )
    ) = 1

In the above MySQL, the following code deducts the repeat_start field (EM1.'meta_value') from the current date and then divides it by the repeat interval field (EM2.'meta_value').

ELSE ( 1336744800 - EM1.`meta_value` ) / EM2.`meta_value`

OR

TODAYS DATE - START DATE / 5 DAYS

So here's the maths:

1336744800 - 1336312800 = 432000
432000 / 432000 = 1

Now that works perfect. But if I change the current timestamp 5 days ahead to 1336312800 which is 17th Mat 2012, it looks a bit like this:

1336312800 - 1336312800 = 864000
86400 / 432000 = 2

Which doesn't work because it equals 2 and in the MySQL it needs to equal 1. So I guess my question is, how do I get the MySQL to recognise a whole number rather than having to do this?

...
WHERE EM1.meta_key = 'repeat_start'
    AND (
        ( CASE ( 1336744800 - EM1.`meta_value` )
            WHEN 0
              THEN 1
            ELSE ( 1336744800 - EM1.`meta_value` ) / EM2.`meta_value`
          END
        )
    ) = IN (1,2,3,4,5,6,7,8,....)

Hope I'm making sense and I hope it's just a simple maths thing or a function that MySQL has that will help :) Thanks for your help!

EDIT: THE ANSWER

Thanks to @eggypal below, I found my answer and of course it was simple!

SELECT EV.*
FROM elvanto_calendars_events AS EV
RIGHT JOIN elvanto_calendars_events_meta AS EM1 ON EM1.`event_id` = EV.`id`
RIGHT JOIN elvanto_calendars_events_meta AS EM2 ON EM2.`meta_key` = CONCAT( 'repeat_interval_', EM1.`id` )
WHERE EM1.meta_key = 'repeat_start'
AND ( ( 1336744800 - EM1.`meta_value` ) % EM2.`meta_value`) = 0
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

It's not entirely clear what you want your query to do, but the jist of your question makes me lean toward suggesting that you look into modular arithmetic: in SQL, a % b returns the remainder when a is divided by b - if there is no remainder (i.e. a % b = 0), then a must be an exact multiple of b.

In your case, I think you're trying to find events where the time between the event start and some given literal is an exact multiple of the event interval: that is, (literal - event_start) % event_interval = 0. If it's non-zero, the value is the time to the next occurrence after literal (and, therefore, to determine whether that next occurrence occurs within some period of time, say a day, one would test to see if the remainder is less than such constant e.g. (literal - event_start) % event_interval < 86400).

If this isn't what you're after, please clarify exactly what your query is trying to achieve.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...