일정 반복 / 반복 이벤트-최상의 저장 방법


311

맞춤 이벤트 시스템을 구축 중이며 다음과 같은 반복되는 이벤트가있는 경우 :

2011 년 3 월 3 일부터 4 일마다 이벤트 A가 반복됩니다.

또는

2011 년 3 월 1 일부터 화요일에 2 주마다 이벤트 B가 반복됩니다.

조회하기 쉬운 방식으로 데이터베이스에 저장하는 방법 많은 수의 이벤트가있는 경우 성능 문제를 원하지 않으며 캘린더를 렌더링 할 때 각각의 이벤트를 수행해야합니다.


1299132000 하드 코딩되어 있는지 설명 할 수 있습니까 ? 주어진 종료 날짜에 발생 날짜와 사용자를 가져와야 할 경우 어떻게해야합니까?
Murali Murugesan

@Murali Boy 이것은 오래되었지만 1299132000이 현재 날짜라고 확신합니다.
Brandon Wamboldt

@BrandonWamboldt, SQL Server로 아이디어를 시도했습니다. stackoverflow.com/questions/20286332/display-next-event-date . C # version
Billa

답변:


211

"간단한"반복 패턴 저장

PHP / MySQL 기반 캘린더의 경우 반복 / 반복 이벤트 정보를 최대한 효율적으로 저장하고 싶었습니다. 나는 많은 수의 행을 원하지 않고 특정 날짜에 발생할 모든 이벤트를 쉽게 조회하고 싶었습니다.

아래의 방법은 매일, n 일마다, 매주, 매달마다 등 정기적 인 간격으로 발생하는 반복 정보를 저장하는 데 유용합니다 . 여기에는 화요일 및 목요일 유형 패턴도 포함되므로 저장되기 때문에 매주 화요일에 시작하고 매주 목요일에 시작하는 것과 별도로.

두 개의 테이블이 있다고 가정하면 하나는 다음 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는 유닉스 타임 스탬프로 시간이없는 날짜이고 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}현재 날짜의 유닉스 타임 스탬프로 교체 (시간 빼기, 시간, 분 및 초 값은 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/…
Ben Sinclair

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

1
이것은 큰 도움이됩니다. 개별 이벤트에 대한 의견이나 체크인을 원한다면 개별 레코드로 액세스하는 것이 어떻게 권장됩니까?
johnrees

26
86400일광 절약 시간을 고려하지 않기 때문에 반복 간격 (예 : 하루 초)에 하드 코드 된 값을 사용해서는 안됩니다 . 그것은 저장하는 대신 즉석에서 동적으로이 일을 계산하는 것이 더 적절한이다 interval = dailyinterval_count = 1interval = monthly하고 interval_count = 1.
Corey Ballou

185

현재 받아 들여진 대답은 나에게 큰 도움이되었지만 쿼리를 단순화하고 성능을 향상시키는 유용한 수정 사항을 공유하고 싶었습니다.


"간단한"반복 이벤트

다음과 같이 정기적으로 반복되는 이벤트를 처리하려면 다음을 수행하십시오.

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-1369008000 상당)을 가진 UNIX 타임 스탬프 날짜 인 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)를 사용하십시오.

모듈로 (% 기호) 사용에 유의하십시오. 이 기호는 정규 나누기와 비슷하지만 몫 대신 ''리마인더 ''를 반환하며 현재 날짜가 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_year, repeat_month, repeat_day, repeat_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
  )

이렇게하면 두 번째 주 금요일에 반복 되는 모든 이벤트와 매주 금요일마다 반복 되는 모든 이벤트가 반환되므로 이벤트 ID 1과 2가 모두 반환됩니다.

ID    NAME
1     Sample Event
2     Another Event

* 위의 SQL에서 주석은 PHP Date의 기본 요일 인덱스를 사용 했으므로 금요일에 "5"


이것이 원래의 대답이 나에게 도움이 된만큼 다른 사람들에게 도움이되기를 바랍니다!


6
대단하다, 고마워! "첫 번째 월요일에 2 개월마다"또는 "첫 번째 월요일에 3 개월마다"등을 인코딩하는 방법을 알고 있습니까?
Jordan Lev

6
나는 이것이 놀랍다는 것에 동의한다. 그러나 Jordan Lev와 같은 딜레마에 빠졌습니다. repeat_interval 필드는 일부 개월이 다른 개월보다 길기 때문에 반복되는 개월에 좋지 않습니다. 또한 되풀이 이벤트 기간을 어떻게 제한합니까? 즉, 첫 번째 월요일에 2 개월마다 8 개월 동안. 테이블에는 일종의 종료 날짜가 있어야합니다.
Abinadi

11
이것은 훌륭한 답변입니다. repeat_interval을 삭제하고 repeat_end 날짜를 추가했지만이 답변이 크게 도움이되었습니다.
Iain Collins

3
팁 : 복잡한 패턴의 경우 repeat_interval열을 제거하고 후속 열 (예 repeat_year: 등)에 표시 할 수 있습니다. 첫 번째 행의 경우 2013 년 5 월 20 일 월요일마다 반복되는 상황은 1에 repeat_weekday그리고 *다른 열이다.
musubi

3
@OlivierMATROT @milos 아이디어는 명시 적으로 수정하려는 필드를 나머지는 와일드 카드로 설정하는 것 *입니다. 따라서 "매월 3 일"에 대해서는 3으로 설정 repeat_day하고 나머지 repeat필드는 * ( repeat_interval널 ( NULL))로 설정하고 2011 년 3 월 3 일의 유닉스 타임 코드로 repeat_start를 고정 날짜로 설정하십시오.
ahoffner

28

개선 : 타임 스탬프를 날짜로 교체

ahoffner가 이후에 수정 한 허용 된 답변을 약간 향상 시키면 타임 스탬프 대신 날짜 형식을 사용할 수 있습니다. 장점은 다음과 같습니다.

  1. 데이터베이스에서 읽을 수있는 날짜
  2. 연도> 2038 및 타임 스탬프에 문제가 없음
  3. 계절적으로 조정 된 날짜를 기준으로하는 타임 스탬프에주의해야합니다. 즉, 영국에서는 6 월 28 일부터 12 월 28 일보다 1 시간 일찍 시작하므로 날짜에서 타임 스탬프를 추출하면 재귀 알고리즘이 중단 될 수 있습니다.

이렇게하려면 DB repeat_start를 'date'유형으로 저장하도록 변경 하고 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 (예 : 3 월 11 일) 또는 repeat_month, repeat_week 및 repeat_weekday를 설정하여 4 월의 두 번째 화요일을 설정할 수 있습니다.
jerrygarciuh

25

나는이 안내서를 따르겠다 : https://github.com/bmoeskau/Extensible/blob/master/recurrence-overview.md

또한 휠을 다시 만들지 않도록 iCal 형식을 사용해야하며 규칙 # 0을 기억하십시오. 개별 반복 이벤트 인스턴스를 데이터베이스에 행으로 저장하지 마십시오!


2
특정 인스턴스에 참석 한 추적 사용자를 어떻게 모델링합니까? 이 경우 규칙 # 0에서 벗어나는 것이 합리적입니까?
Danny Sullivan

2
내 머리의 상단에서 @DannySullivan, 나는 다른 엔티티 것 attendedEvent과를 baseInstanceId하고 instanceStartDate- 즉 예를 들어 당신이 반복 규칙 달력보기를 만든 다음이 개체도 할 수 특정 인스턴스에 대한 정보를 지정하려면 시작 날짜를 사용할 수있는 기본 이벤트입니다 같은가 attendedListId다른 테이블에있는 리드를 id,attendedUserId
갈 Bracha의

@ DannySullivan 나는 당신이 요청한 이후 시간이 지났다는 것을 알고 있습니다. 그러나 이전 의견 외에는 항상 해당 사용자가 이벤트 반복 패턴의 일부인지 확인하기 위해 역방향 조회를 수행 할 수있었습니다. 그들은 최소한 이벤트 일정이 잡혔는 지 알려줄 것입니다. 그들이 실제로 참석했는지 여부는 DannySullivan의 의견에 따라 다른 이야기입니다.
BRogers

24

이것에 관심이있는 모든 사람들을 위해 이제 복사하고 붙여 넣기 만하면 몇 분 안에 시작할 수 있습니다. 나는 의견뿐만 아니라 조언을했다. 내가 빠진 것이 있으면 알려주세요.

"복잡한 버전":

행사

+ ---------- + ---------------- +
| 아이디 | 이름 |
+ ---------- + ---------------- +
| 1 | 샘플 이벤트 1 |
| 2 | 두 번째 이벤트 |
| 3 | 세번째 이벤트 |
+ ---------- + ---------------- +

events_meta

+ ---- + ---------- + -------------- + ------------------ + ------------- + -------------- + ------------ + ------- ------ + ---------------- +
| 아이디 | event_id | repeat_start | repeat_interval | 반복 _ 년 | repeat_month | 반복 일 | 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/…
Brad Kent

1
@Alex 반복 된 이벤트에서 하나의 인스턴스 발생을 어떻게 삭제합니까?
Pugazhenthi

1
나는 이것이 오래된 스레드라는 것을 알고 있지만 왜 repeat_ * 열의 varchar 유형입니까? '*'대신 정수와 음수 값을 사용할 수 없습니까?
Olivier MATROT

1
코드 주셔서 감사합니다. 그러나 db / queries 구현은 약간 혼란스럽고 매우 비효율적입니다. 예를 들어 왜 간단한 열에 varchar (255)를 사용 하는가 (@OlivierMATROT에서 언급했듯이 정수를 사용할 수 있으며, 그렇지 않은 경우에도 255)? 그리고 쿼리를 30 번 반복한다면 명령문이나 프로 시저를 사용하지 않는 이유는 무엇입니까? 누군가가 이것을 구현하려고한다면 그냥 말하십시오.
Rony

15

제안 된 솔루션이 작동하는 동안 전체 일정으로 구현하려고 시도했지만 각보기마다 90 건 이상의 데이터베이스 호출이 필요합니다 (현재, 이전 및 다음 달에로드 할 때).

나는 당신이 단순히 데이터베이스에 규칙을 저장하고 모든 관련 규칙을 가져 오기 위해 하나의 쿼리를 재귀 라이브러리 https://github.com/tplaner/When 찾았습니다 .

좋은 해결책을 찾기 위해 많은 시간을 보냈으므로 다른 사람에게 도움이되기를 바랍니다.

편집 :이 라이브러리는 PHP 용입니다


또한 fullcalendar를 사용하고 싶습니다. 언제 도서관이 도움이 될 수 있습니까? 제안자 이벤트를 추출하는 방법?
piernik

@ piernik-문서에서와 같이 라이브러리를 설정하고 특정 문제가 발생하면 설정 한 코드와 발생하는 문제로 stackoverflow에 대한 새로운 질문을여십시오. 당신이 일부 회원들에게 많은 노력을 기울이면 당신을 도울 것입니다.
Tim Ramsey

나는 When당신이 데이터베이스에 모든 되풀이 날짜를 저장하거나 모든 되풀이 이벤트를 가져 와서 데이터베이스에서 php no에 날짜를 생성해야 한다는 것을 의미 합니다. 내가 맞아?
piernik

@piernik 데이터베이스에 초기 날짜와 규칙을 When저장하고 초기 저장된 날짜 / 규칙에서 채워지는 모든 날짜를 생성 하는 데 사용 합니다.
Tim Ramsey

하나의 mysql 명령으로 올바른 이벤트를 얻을 수 없습니다-PHP를 사용해야합니다. 어쨌든 감사합니다
piernik

14

왜 Apache cron 작업과 유사한 메커니즘을 사용하지 않습니까? http://en.wikipedia.org/wiki/Cron

캘린더 / 스케줄링의 경우 표준 캘린더 재발 이벤트를 수용하기 위해 "비트"에 대해 약간 다른 값을 사용합니다. [요일 (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

2
cron을 사용하여 반복을 저장하는 것이 좋습니다. 그러나 문제는 조회하기가 매우 어렵다는 것입니다.
Stony

@ 블라디미르 매주 화요일마다 (매주 2 주마다)
julestruong

@julestruong이 웹 사이트는 답이있는 것 같습니다 : coderwall.com/p/yzzu5a/running-a-cron-job-everyother-week
Ashton Wiersdorf

cron은 표현력이 제한적이기 때문에 상태가 제한적이지 않기 때문에 (단지 현재 / 임상 날짜 / 시간을 패턴과 비교하기 만 함) "3 일마다"또는 "7 시간마다"와 같은 일반적인 비즈니스 / 인간 패턴을 나타낼 수 없습니다. 마지막 발생을 기억해야합니다. 이것은 분명하지 않습니다. 당신은 당신이 crontab에서 3/3 또는 7/7 일이라고 말하고 있다고 생각할 수 있지만, 그 달 / 일의 끝에서, 당신은 "남은"일 / 시간이 3 또는 7보다 적습니다; 가능한 치명적인 결과.
Jaime Guerrero

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

@ 도적 코더

대단해!

모듈로 연산 (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

여러분이 제시 한 두 가지 예는 매우 간단합니다. 그것들은 간단한 간격 (첫 번째는 4 일, 두 번째는 14 일)으로 표시 될 수 있습니다. 이를 모델링하는 방법은 전복의 복잡성에 전적으로 달려 있습니다. 위의 내용이 정말 간단하다면 시작 간격과 일 수를 반복 간격으로 저장하십시오.

그러나 다음과 같은 것을 지원해야하는 경우

2011 년 3 월 3 일부터 매월 3 일에 이벤트 A가 반복됩니다.

또는

2011 년 3 월 11 일부터 이벤트 A가 매월 둘째 주 금요일에 반복

그러면 훨씬 복잡한 패턴입니다.


1
나중에 방금 언급했지만 지금은 아닌 더 복잡한 규칙을 추가했습니다. 2011 년 3 월 7 일에 되풀이 이벤트가 발생하도록 이벤트를 가져 오기 위해 SQL 쿼리를 어떻게 모델링합니까?
Brandon Wamboldt
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.