カレンダーの定期的/繰り返しイベント-最適な保存方法


311

私はカスタムイベントシステムを構築しています。次のような繰り返しイベントがある場合:

イベントAは2011年3月3日から4日ごとに繰り返されます

または

イベントBは、2011年3月1日から火曜日に2週間ごとに繰り返されます

簡単に検索できるようにデータベースに保存するにはどうすればよいですか。多数のイベントがある場合はパフォーマンスの問題が発生したくないので、カレンダーをレンダリングするときにすべてのイベントを実行する必要があります。


なぜ1299132000 ハードコーディングされているのですか?指定された終了日の発生日とユーザーを取得する必要がある場合、これはどうなりますか?
Murali Murugesan 2013年

@Murali Boyこれは古いですが、1299132000が現在の日付であるはずです。
Brandon Wamboldt 2013年

@BrandonWamboldt、私はSQL Serverであなたのアイデアを試しました。stackoverflow.com/questions/20286332/display-next-event-dateC#バージョンの
Billa

回答:


211

「単純な」繰り返しパターンの保存

PHP / MySQLベースのカレンダーでは、繰り返し/繰り返しのイベント情報をできるだけ効率的に保存したいと考えていました。行数を多くしたくなかったので、特定の日付に発生するすべてのイベントを簡単に検索したいと思いました。

以下の方法は、毎日、n日ごと、毎週、毎月など、定期的に発生する繰り返し情報を格納するのに最適です。これには、毎週火曜日と木曜日のタイプのパターンも含まれます。毎週火曜日から始まり、毎週木曜日から始まります。

2つのテーブルがあるとすると、1つは次のeventsように呼び出されます。

ID    NAME
1     Sample Event
2     Another Event

そして、次のevents_metaようなテーブル:

ID    event_id      meta_key           meta_value
1     1             repeat_start       1299132000
2     1             repeat_interval_1  432000

repeat_startはUNIXタイムスタンプとして時間のない日付であり、repeat_intervalは間隔(432000は5日)間の秒数です。

repeat_interval_1はID 1のrepeat_startと連動します。したがって、毎週火曜日と毎週木曜日に繰り返すイベントがある場合、repeat_intervalは604800(7日)になり、2つのrepeat_startsと2つのrepeat_intervalsがあります。テーブルは次のようになります。

ID    event_id      meta_key           meta_value
1     1             repeat_start       1298959200 -- This is for the Tuesday repeat
2     1             repeat_interval_1  604800
3     1             repeat_start       1299132000 -- This is for the Thursday repeat
4     1             repeat_interval_3  604800
5     2             repeat_start       1299132000
6     2             repeat_interval_5  1          -- Using 1 as a value gives us an event that only happens once

次に、毎日ループするカレンダーがあり、その日のイベントを取得する場合、クエリは次のようになります。

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
LIMIT 0 , 30

{current_timestamp}現在の日付のUNIXタイムスタンプに置き換えます(時間をマイナスするため、時間、分、秒の値は0に設定されます)。

うまくいけば、これは他の誰かにも役立つでしょう!


「複雑な」繰り返しパターンの保存

この方法は、次のような複雑なパターンを保存するのに適しています。

Event A repeats every month on the 3rd of the month starting on March 3, 2011

または

Event A repeats Friday of the 2nd week of the month starting on March 11, 2011

これを上記のシステムと組み合わせて、最も柔軟性を高めることをお勧めします。このためのテーブルは次のようになります。

ID    NAME
1     Sample Event
2     Another Event

そして、次のevents_metaようなテーブル:

ID    event_id      meta_key           meta_value
1     1             repeat_start       1299132000 -- March 3rd, 2011
2     1             repeat_year_1      *
3     1             repeat_month_1     *
4     1             repeat_week_im_1   2
5     1             repeat_weekday_1   6

repeat_week_im現在の月の週を表します。1から5の間の可能性があります。repeat_weekday曜日、1-7。

ここで、日/週をループしてカレンダーに月ビューを作成すると想定すると、次のようなクエリを作成できます。

SELECT EV . *
FROM `events` AS EV
JOIN `events_meta` EM1 ON EM1.event_id = EV.id
AND EM1.meta_key = 'repeat_start'
LEFT JOIN `events_meta` EM2 ON EM2.meta_key = CONCAT( 'repeat_year_', EM1.id )
LEFT JOIN `events_meta` EM3 ON EM3.meta_key = CONCAT( 'repeat_month_', EM1.id )
LEFT JOIN `events_meta` EM4 ON EM4.meta_key = CONCAT( 'repeat_week_im_', EM1.id )
LEFT JOIN `events_meta` EM5 ON EM5.meta_key = CONCAT( 'repeat_weekday_', EM1.id )
WHERE (
  EM2.meta_value =2011
  OR EM2.meta_value = '*'
)
AND (
  EM3.meta_value =4
  OR EM3.meta_value = '*'
)
AND (
  EM4.meta_value =2
  OR EM4.meta_value = '*'
)
AND (
  EM5.meta_value =6
  OR EM5.meta_value = '*'
)
AND EM1.meta_value >= {current_timestamp}
LIMIT 0 , 30

これを上記の方法と組み合わせると、ほとんどの繰り返し/繰り返しイベントパターンをカバーするように組み合わせることができます。何か見逃した場合はコメントを残してください。


1
私はあなたの「シンプルな」繰り返しパターンを保存しようとしています。毎週火曜日に繰り返す必要がある場合、repeat_startを変更するか、最後の日付で新しいレコードを作成する必要がありますか。または最初のrepeat_startに基づいて毎週繰り返す方法はありますか???
loo

1
私はこの記事の後に私の答えを見つけた...あなたの答えは、大きな助けと@roguecoderだったが、それはかなりバットをオフに動作しませんでした:stackoverflow.com/questions/10545869/...
ベン・シンクレア

1
これAND ( ( CASE ( 1299132000 - EM1.meta_value ) WHEN 0 THEN 1 ELSE ( 1299132000 - EM1.meta_value) END ) / EM2.meta_value ) = 1/ EM2.meta_value間違って配置されていますか?
Murali Murugesan 2013年

1
これは非常に役立ちます。たとえば、個々のイベントにコメントやチェックインが必要な場合、これらを個々のレコードとしてアクセスすることをどのように提案しますか?
ジョンリーズ2014年

26
86400夏時間を考慮しないため、ハードコードされた値を繰り返し間隔(1日の秒数)に使用しないでください。それはその場で動的にこれらの事を計算し、代わりに格納することがより適切だinterval = dailyinterval_count = 1interval = monthlyinterval_count = 1
Corey Ballou 2014

185

現在受け入れられている答えは私にとって大きな助けでしたが、クエリを簡素化し、パフォーマンスを向上させるいくつかの有用な変更を共有したいと思いました。


「単純な」繰り返しイベント

次のような定期的に繰り返されるイベントを処理するには、

Repeat every other day 

または

Repeat every week on Tuesday 

次のeventsように呼ばれる2つのテーブルを作成する必要があります。

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時間がない(5月20日2013から1369008000に相当)と、UNIXタイムスタンプの日付であること、および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 )

カレンダーの各日付をunix-timestamp(1299736800)に置き換えてください。

モジュロ(%記号)の使用に注意してください。この記号は通常の除算に似ていますが、商の代わりに「剰余」を返します。したがって、現在の日付がrepeat_startからのrepeat_intervalの正確な倍数である場合は常に0になります。

性能比較

これは、以前に提案された「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

このクエリをEXPLAINして実行すると、結合バッファを使用する必要があることがわかります。

+----+-------------+-------+--------+---------------+---------+---------+------------------+------+--------------------------------+
| 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_yearrepeat_monthrepeat_dayrepeat_week、およびrepeat_weekdayデータ。

これにより、両方のタイプを同時に選択することが非常に簡単になります。毎日ループし、正しい値を入力します(2013年6月7日の場合は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週の金曜日に繰り返されるすべてのイベントと、毎週金曜日に繰り返されるすべてのイベントを返すため、イベントID 1と2の両方を返します。

ID    NAME
1     Sample Event
2     Another Event

*上記のSQLの補足説明では、PHP Dateのデフォルトの平日のインデックスを使用したため、金曜日は「5」


これが元の答えが私を助けたのと同じくらい他の人を助けてくれることを願っています!


6
これは素晴らしいです、ありがとう!「第1月曜日の2か月ごと」または「第1月曜日の3か月ごと」などをどのようにエンコードするか考えていますか?
ジョーダンレフ

6
これは素晴らしいことだと思います。しかし、私はジョーダンレフと同じジレンマに遭遇しました。repeat_intervalフィールドは、一部の月が他の月より長いため、繰り返しの月には適していません。また、定期的な予定の期間をどのように制限しますか。つまり、最初の月曜日の2か月ごとに8か月間。テーブルには、ある種の終了日が必要です。
Abinadi 2013年

11
これは素晴らしい答えです。repeat_intervalを削除してrepeat_endの日付を追加しましたが、この回答は非常に役に立ちました。
Iain Collins

3
ヒント:複雑なパターンの場合、repeat_interval列を削除して後続の列(つまりrepeat_year、など)で表すことができます。最初の行では、2013年5月20日以降の毎週月曜日を繰り返す状況は、1をrepeat_weekday*他の列に。
musubi 2014年

3
@OlivierMATROT @milosアイデアは、修正したいフィールドを明示的に設定し、残りをワイルドカードに設定することです*。したがって、「毎月3日」の場合は3に設定repeat_dayし、残りのrepeatフィールドを*(repeat_intervalnullのまま)に設定して、2011年3月3日のUNIXタイムコードにrepeat_startをアンカー日付に設定します。
ahoffner

28

機能強化:タイムスタンプを日付に置き換えます

後にahoffnerによって洗練された、受け入れられた回答に対する小さな拡張として-タイムスタンプではなく日付形式を使用することが可能です。利点は次のとおりです。

  1. データベース内の読み取り可能な日付
  2. 2038年以上とタイムスタンプで問題なし
  3. 削除は、季節調整された日付に基づくタイムスタンプに注意する必要があります。つまり、英国では、6月28日は12月28日より1時間早く開始されるため、日付からタイムスタンプを取得すると、再帰アルゴリズムが壊れる可能性があります。

これを行うには、DB repeat_startを「日付」タイプとして格納されるように変更し、repeat_interval秒ではなく日を保持するようにします。つまり、7日間の繰り返しの場合は7。

sql行を変更します。

WHERE (( 1370563200 - repeat_start) % repeat_interval = 0 )

に:

WHERE ( DATEDIFF( '2013-6-7', repeat_start ) % repeat_interval = 0)

他はすべて同じままです。シンプル!


では、イベントを毎年繰り返す場合はどうすればよいでしょうか。repeat_intervalは365日保存する必要がありますか?彼らが年に366日ある場合はどうなりますか?
TGeorge

3
@ George02イベントが年次の場合、repeat_intervalをNULLにして、repeat_yearを*のままにして、繰り返しの種類に応じて、repeat_monthとrepeat_dayを設定します。
jerrygarciuh

25

私はこのガイドに従います:https : //github.com/bmoeskau/Extensible/blob/master/recurrence-overview.md

また、iCal形式を使用して、ホイールを再発明せず、ルール#0を覚えておいて ください。個々の定期的なイベントインスタンスをデータベースの行として保存しないでください。


2
特定のインスタンスに参加した追跡ユーザーをどのようにモデル化しますか?この場合、ルール#0から違反することは理にかなっていますか?
ダニーサリバン

2
@DannySullivan私の頭の上から、私は別のエンティティattendedEventbaseInstanceId持ちますinstanceStartDate- そしてそれはたとえば、定期的なルールのカレンダービューを作成し、開始日を使用してその特定のインスタンスに関する情報を指定する基本イベントである場合、このエンティティも以下のようなもの持っているattendedListIdの別のテーブルへのリードをidattendedUserId
ギャルBracha

@DannySullivan質問してからしばらく経ちました。ただし、前のコメントの外では、常に逆ルックアップを実行して、そのユーザーがイベント繰り返しパターンの一部であるかどうかを確認できます。それは彼らが少なくともイベントのためにスケジュールされたかどうかを教えてくれます。彼らが実際に参加したかどうかは別の話であり、DannySullivanのコメントに沿ったものになるでしょう。
BRogers

24

これに興味のあるすべての人にとって、今すぐコピーして貼り付けるだけで数分で開始できます。私はできる限りコメントでアドバイスを受けました。何か不足している場合はお知らせください。

「複雑なバージョン」:

イベント

+ ---------- + ---------------- +
| ID | NAME |
+ ---------- + ---------------- +
| 1 | サンプルイベント1 |
| 2 | 2番目のイベント|
| 3 | 3番目のイベント|
+ ---------- + ---------------- +

events_meta

+ ---- + ---------- + -------------- + ------------------ + ------------- + -------------- + ------------ + ------- ------ + ---------------- +
| ID | event_id | repeat_start | repeat_interval | repeat_year | repeat_month | repeat_day | repeat_week | repeat_weekday |
+ ---- + ---------- + -------------- + ------------------ + ------------- + -------------- + ------------ + ------- ------ + ---------------- +
| 1 | 1 | 2014-07-04 | 7 | NULL | NULL | NULL | NULL | NULL |
| 2 | 2 | 2014-06-26 | NULL | 2014 | * | * | 2 | 5 |
| 3 | 3 | 2014-07-04 | NULL | * | * | * | * | 5 |
+ ---- + ---------- + -------------- + ------------------ + ------------- + -------------- + ------------ + ------- ------ + ---------------- +

SQLコード:

CREATE TABLE IF NOT EXISTS `events` (
  `ID` int(11) NOT NULL AUTO_INCREMENT,
  `NAME` varchar(255) NOT NULL,
  PRIMARY KEY (`ID`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=7 ;

--
-- Dumping data for table `events`
--

INSERT INTO `events` (`ID`, `NAME`) VALUES
(1, 'Sample event'),
(2, 'Another event'),
(3, 'Third event...');

CREATE TABLE IF NOT EXISTS `events_meta` (
  `ID` int(11) NOT NULL AUTO_INCREMENT,
  `event_id` int(11) NOT NULL,
  `repeat_start` date NOT NULL,
  `repeat_interval` varchar(255) NOT NULL,
  `repeat_year` varchar(255) NOT NULL,
  `repeat_month` varchar(255) NOT NULL,
  `repeat_day` varchar(255) NOT NULL,
  `repeat_week` varchar(255) NOT NULL,
  `repeat_weekday` varchar(255) NOT NULL,
  PRIMARY KEY (`ID`),
  UNIQUE KEY `ID` (`ID`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=6 ;

--
-- Dumping data for table `events_meta`
--

INSERT INTO `events_meta` (`ID`, `event_id`, `repeat_start`, `repeat_interval`, `repeat_year`, `repeat_month`, `repeat_day`, `repeat_week`, `repeat_weekday`) VALUES
(1, 1, '2014-07-04', '7', 'NULL', 'NULL', 'NULL', 'NULL', 'NULL'),
(2, 2, '2014-06-26', 'NULL', '2014', '*', '*', '2', '5'),
(3, 3, '2014-07-04', 'NULL', '*', '*', '*', '*', '1');

MySQLエクスポートとしても利用可能(アクセスを容易にするため)

PHPのサンプルコードindex.php:

<?php
    require 'connect.php';    

    $now = strtotime("yesterday");

    $pushToFirst = -11;
    for($i = $pushToFirst; $i < $pushToFirst+30; $i++)
    {
        $now = strtotime("+".$i." day");
        $year = date("Y", $now);
        $month = date("m", $now);
        $day = date("d", $now);
        $nowString = $year . "-" . $month . "-" . $day;
        $week = (int) ((date('d', $now) - 1) / 7) + 1;
        $weekday = date("N", $now);

        echo $nowString . "<br />";
        echo $week . " " . $weekday . "<br />";



        $sql = "SELECT EV.*
                FROM `events` EV
                RIGHT JOIN `events_meta` EM1 ON EM1.`event_id` = EV.`id`
                WHERE ( DATEDIFF( '$nowString', repeat_start ) % repeat_interval = 0 )
                OR ( 
                    (repeat_year = $year OR repeat_year = '*' )
                    AND
                    (repeat_month = $month OR repeat_month = '*' )
                    AND
                    (repeat_day = $day OR repeat_day = '*' )
                    AND
                    (repeat_week = $week OR repeat_week = '*' )
                    AND
                    (repeat_weekday = $weekday OR repeat_weekday = '*' )
                    AND repeat_start <= DATE('$nowString')
                )";
        foreach ($dbConnect->query($sql) as $row) {
            print $row['ID'] . "\t";
            print $row['NAME'] . "<br />";
        }

        echo "<br /><br /><br />";
    }
?>

PHPのサンプルコードconnect.php:

<?
// ----------------------------------------------------------------------------------------------------
//                                       Connecting to database
// ----------------------------------------------------------------------------------------------------
// Database variables
$username = "";
$password = "";
$hostname = ""; 
$database = ""; 

// Try to connect to database and set charset to UTF8
try {
    $dbConnect = new PDO("mysql:host=$hostname;dbname=$database;charset=utf8", $username, $password);
    $dbConnect->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

} catch(PDOException $e) {
    echo 'ERROR: ' . $e->getMessage();
}
// ----------------------------------------------------------------------------------------------------
//                                      / Connecting to database
// ----------------------------------------------------------------------------------------------------
?>

また、phpコードはここにあります(読みやすくするため):
index.php

connect.php
これを設定すると、数分かかるはずです。時間ではありません。:)


2
クエリを実行して、日付範囲内のすべての繰り返しイベントを取得する方法。つまり、2014-10-01から2014-12-30までのすべての繰り返しイベントを取得する方法です。投稿ありがとう
Well Wisher

@Wellwisher -繰り返し...までは、一時テーブル stackoverflow.com/questions/34407833/...
ブラッド・ケント

1
@Alex繰り返しイベントから1つのインスタンスオカレンスを削除するには
プガジェンティ

1
私はこれが古いスレッドであることを知っていますが、なぜrepeat_ *列のvarcharタイプですか?'*'の代わりに整数と負の値を使用できませんか?
Olivier MATROT 2017年

1
コードをありがとう。ただし、db / queriesの実装はやや煩わしく、非常に非効率的です。たとえば、そのような単純な列にvarchar(255)を使用する理由(@OlivierMATROTで述べたように、整数を使用できますが、そうでない場合でも、なぜ255ですか?)。また、クエリを30回繰り返す場合は、ステートメントまたはプロシージャを使用してみませんか?誰かがこれを実装しようとしている場合のために言っています。
ロニー

15

提案されたソリューションが機能している間、私はフルカレンダーを使用して実装しようとしており、ビューごとに90以上のデータベース呼び出しが必要になります(現在、前、および次の月が読み込まれるため)。

再帰ライブラリを見つけましたhttps://github.com/tplaner/Whenデータベースにルールを保存し、1つのクエリで関連するすべてのルールをプルする場合。

私が良い解決策を見つけるために何時間も費やしたので、うまくいけば、これは他の誰かを助けるでしょう。

編集:このライブラリはPHP用です


フルカレンダーも使いたいです。ライブラリはどのように役立ちますか?推進者イベントを抽出する方法は?
piernik 2016年

@piernik-ライブラリをドキュメントのようにセットアップします。特定の問題が発生している場合は、セットアップしたコードと発生している問題について、stackoverflowで新しい質問を開きます。メンバーの皆さんにそんなに努力してもらえると助かります。
Tim Ramsey

つまり、Whenすべての定期的な日付をデータベースに保存するか、すべての定期的なイベントを取得して、データベースのphp noで日付を生成する必要があります。私は正しいですか?
piernik 2016年

@piernik最初の日付とルールをデータベースにWhen保存し、それを使用してすべての日付を生成します-これは、最初に保存された日付/ルールから読み込まれます。
Tim Ramsey

それも良くありません-1つのmysqlコマンドで正しいイベントを取得することはできません-そのためにはPHPを使用する必要があります。とにかくありがとう
piernik 2016年

14

Apache cronジョブと同様のメカニズムを使用しないのはなぜですか?http://en.wikipedia.org/wiki/Cron

calendar \ schedulingの場合、[ビット]に少し異なる値を使用して、標準のカレンダーの繰り返しイベントに対応します-[曜日(0-7)、月(1-12)、日(1-31)、時間(0-23)、分(0-59)]

-[年(N年ごとに繰り返す)、月(1-12)、日(1-31)、月の週(1-5)、曜日(0-7)などを使用します]

お役に立てれば。


6
曜日の選択肢が多すぎると思います。1-7または0-6のどちらかがより正確に思われます。
Abinadi 2013年

2
繰り返しを保存するためにcronを使用するのは良いことです。しかし問題は、検索するのが非常に難しいことです。
ストーニー2014年

@Vladimir 2火曜日ごと(火曜日の2週間ごと)にどのように保存しますか
julestruong

@julestruongこのウェブサイトは答えがあるように見えます:coderwall.com/p/yzzu5a/running-a-cron-job-every-other-week
Ashton Wiersdorf

cronは表現力が限られています。これはステートレスであるため(単に現在/異常な日付/時刻をパターンと比較するため)、「3日ごと」や「7時間ごと」などの一般的なビジネス/人間のパターンを表すことができないためです。最後の発生を覚えておく必要があります。これは明白ではありません。crontabで「day / 3」または「hour / 7」と言うだけだと思う​​かもしれませんが、月/日の終わりに、3または7未満の「残り」の日/時間があります。破滅的な結果となる可能性があります。
ハイメゲレーロ

5

私はこのケースのためだけに難解なプログラミング言語を開発しました。それについての最も良い部分は、それがスキーマレスでプラットフォームに依存しないことです。あなたはあなたのスケジュールのためにセレクタプログラムを書く必要があります、その構文はここで説明されているルールのセットによって制約されています-

https://github.com/tusharmath/sheql/wiki/Rules

ルールは拡張可能であり、スキーマの移行などを心配することなく、実行する繰り返しロジックの種類に基づいてあらゆる種類のカスタマイズを追加できます。

これは完全に異なるアプローチであり、独自の欠点があるかもしれません。


4

システムテーブルに格納されているMySQLイベントとよく似ています。構造を見て、不要な列を特定できます。

   EVENT_CATALOG: NULL
    EVENT_SCHEMA: myschema
      EVENT_NAME: e_store_ts
         DEFINER: jon@ghidora
      EVENT_BODY: SQL
EVENT_DEFINITION: INSERT INTO myschema.mytable VALUES (UNIX_TIMESTAMP())
      EVENT_TYPE: RECURRING
      EXECUTE_AT: NULL
  INTERVAL_VALUE: 5
  INTERVAL_FIELD: SECOND
        SQL_MODE: NULL
          STARTS: 0000-00-00 00:00:00
            ENDS: 0000-00-00 00:00:00
          STATUS: ENABLED
   ON_COMPLETION: NOT PRESERVE
         CREATED: 2006-02-09 22:36:06
    LAST_ALTERED: 2006-02-09 22:36:06
   LAST_EXECUTED: NULL
   EVENT_COMMENT:


3

@Rogue Coder

これは素晴らしい!

最後に単純にmodulo操作(mysqlではMODまたは%)を使用して、コードを単純にすることができます。

の代わりに:

AND (
    ( CASE ( 1299132000 - EM1.`meta_value` )
        WHEN 0
          THEN 1
        ELSE ( 1299132000 - EM1.`meta_value` )
      END
    ) / EM2.`meta_value`
) = 1

行う:

$current_timestamp = 1299132000 ;

AND ( ('$current_timestamp' - EM1.`meta_value` ) MOD EM2.`meta_value`) = 1")

これをさらに進めるために、永遠に再発しないイベントを含めることができます。

最後の「repeat_interval_1」の日付を示す「repeat_interval_1_end」などを追加できます。ただし、これによりクエリがより複雑になり、これを行う方法を実際に理解できません...

多分誰かが助けることができます!


1

あなたが与えた2つの例は非常に単純です。それらは単純な間隔として表すことができます(最初は4日、2番目は14日です)。これをどのようにモデル化するかは、再発の複雑さに完全に依存します。上記が本当に単純な場合は、開始日と繰り返し間隔の日数を保存します。

ただし、次のようなことをサポートする必要がある場合

イベントAは、2011年3月3日から毎月3日に繰り返されます

または

イベントAは、2011年3月11日から始まる月の第2金曜日に繰り返されます

次に、それははるかに複雑なパターンです。


1
後で述べた、今のところではない、より複雑なルールを追加しました。2011年3月7日にイベントを取得するSQLクエリをモデル化して、定期的なイベントを取得するにはどうすればよいですか?
Brandon Wamboldt、2011
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.