如何根据从开始日期开始的星期几来计算下一个发生日期?

时间:2015-01-08 06:31:23

标签: postgresql

我的事件表有startdate和enddate列。它还有一个重复的布尔列,标记为重复发生的事件。我只需要支持每周复发。如何为这些重复发生的事件选择下一个合适的日期?

鉴于以下样本数据和撰写时间,我如何获得以下结果?

startdate    enddate     nextdate
12/29/14     12/31/15    1/12/15
1/2/15       4/1/15      1/9/15
6/1/14       12/31/14    null
4/1/15       12/31/15    4/1/15

更新:我刚刚写了这个函数,但现在我想知道是否有更高效的东西...

CREATE OR REPLACE FUNCTION nextdowinrange(startdate timestamp with time zone, enddate timestamp with time zone)
  RETURNS timestamp with time zone AS
$BODY$
    DECLARE
        loopday int;
        nextdate timestamp with time zone;
        BEGIN

        --RANGE PAST
        IF enddate < current_timestamp THEN
            RETURN null;
        --RANGE NOT STARTED
        ELSIF startdate > current_timestamp THEN
            RETURN startdate;
        --SAME DAY OF WEEK
        ELSIF extract(dow from startdate) = extract(dow from current_timestamp) THEN
            RETURN startdate;
        --FIND NEXT
        ELSE
            loopday:= 0;
            LOOP
                IF extract(dow from now() + (loopday || ' days')::interval) = extract(dow from startdate) THEN
                    nextdate:= now() + (loopday || ' days')::interval;
                END IF;
                EXIT WHEN extract(dow from now() + (loopday || ' days')::interval) = extract(dow from startdate);
                loopday:= loopday + 1;

            END LOOP;
            RETURN nextdate;
        END IF;

        END;
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;

2 个答案:

答案 0 :(得分:1)

可以通过简单的选择来完成,不需要自定义功能。

PostgreSQL 9.3+最简单的解决方案是LATERAL加入:

select  t.*, nextdate
from    t
left join lateral (
  select nextdate
  from   generate_series(startdate, enddate, '1 week') nextdate
  where  nextdate > now()
  limit  1
) nd on true;

对于较旧的PostgreSQL,您可以使用nextdate列的子选择:

select *, (select ds
           from   generate_series(startdate, enddate, '1 week') ds
           where  ds > now()
           limit  1) nextdate
from   t;

SQLFiddle

答案 1 :(得分:0)

以下查询将为您提供所需内容。希望这能为您提供基本的想法,您可以根据自己的需要进行修改。

我冒昧地添加了一个id列(使连接变得更容易),我认为startdate和enddate的类型为date

alter table mydates add date_id serial primary key

让我解释一下查询:内部查询生成一系列日期。下一个查询获取该系列中最早的未来日期(对于每个id) - 这不会返回enddate过去的行的记录。因此,有一个外部查询使用null nextdate添加那些丢失的记录。

SELECT a.startdate,a.enddate,nextdate FROM -- outer query with left join to get finished ranges
    mydates a
LEFT JOIN 
         -- select the earliest date in the future from the series
         -- This will not contain rows where the enddate is in the past
    (SELECT date_id,min(theweeks)::date AS nextdate FROM 
        (SELECT date_id, generate_series -- Get a series of the week dates
           (
           startdate
           ,enddate
           , '1 week'::interval) as theweeks 
         FROM mydates
         ) AS daterange
    WHERE now() < theweeks
    GROUP BY date_id) AS nextdates
ON nextdates.date_id = a.date_id
ORDER BY a.date_id