我的事件表有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;
答案 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;
答案 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