我需要检查上一个记录的元素,以确保我查询的日期不在结束日期和开始日期前7天之间的特定范围内。我有以下代码:
create or replace function eight (date) returns text as $$
declare
r record;
checkDate alias for $1;
begin
for r in
select * from periods
order by startDate
loop
if (checkDate between r.startDate and r.endDate) then
return q3(r.id);
elsif (checkDate between (r.startDate - interval '7 days') and r.startDate) then
return q3(r.id);
elsif (checkDate between (lag(r.endDate) over (order by r.startDate)) and (r.startDate - interval '8 days')) then
return q3(r.id);
end if;
end loop;
return null;
end;
$$ language plpgsql;
基本上,我需要检查以下内容:
如果查询日期介于开始日期和结束日期之间
如果查询日期是开始日期开始前7天
如果查询日期在结束日期和开始日期之间 并返回与该日期相关联的ID。
我的功能似乎在大多数情况下都能正常工作,但是有些情况似乎给了我0结果(当应该总是有1个结果时)我的功能中是否缺少某些东西?关于最后的if语句,我很不满意。也就是说,尝试检查从先前记录的结束日期到当前记录的开始日期(与7天的差距)
编辑:没有日期重叠。
答案 0 :(得分:3)
编辑:删除了关于RETURN NEXT的部分 - 我误读了那里的问题。
不按照你的方式工作。无法像这样调用window function。您的记录变量r
就像FOR
循环中的内置游标。只有结果的当前行在循环内可见。您必须将window function lag()
整合到最初的SELECT
。
但是,既然你在匹配的顺序中遍历行,你可以用另一种方式来做。
考虑这个很大程度上重写的例子。返回第一个违规行:
CREATE OR REPLACE FUNCTION q8(_day date)
RETURNS text AS
$BODY$
DECLARE
r record;
last_enddate date;
BEGIN
FOR r IN
SELECT *
-- ,lag(r.endDate) OVER (ORDER BY startDate) AS last_enddate
-- commented, because I supply an alternative solution
FROM periods
ORDER BY startDate
LOOP
IF _day BETWEEN r.startDate AND r.endDate THEN
RETURN 'Violates condition 1'; -- I return differing results
ELSIF _day BETWEEN (r.startDate - 7) AND r.startDate THEN
RETURN 'Violates condition 2';
ELSIF _day BETWEEN last_enddate AND (r.startDate) THEN
-- removed "- 7 ", that is covered above
RETURN 'Violates condition 3';
END IF;
last_enddate := r.enddate; -- remember for next iteration
END LOOP;
RETURN NULL;
END;
$BODY$ LANGUAGE plpgsql;
$1
的别名?您已在声明中将其命名为_day
。坚持下去。答案 1 :(得分:0)
你确定lag()
会给你一些回报吗?我很确定这是脱离背景的。假定按顺序选择periods
中的行,您可以将当前startDate
存储在变量中,并在下一个循环的if语句中使用它。
答案 2 :(得分:0)
SET search_path='tmp';
DROP table period;
CREATE table period
( start_date DATE NOT NULL
, end_date DATE
);
INSERT INTO period(start_date ,end_date) VALUES
( '2012-01-01' , '2012-02-01' )
, ( '2012-02-01' , '2012-02-07' )
, ( '2012-03-01' , '2012-03-15' )
, ( '2012-04-01' , NULL )
, ( '2012-04-17' , '2012-04-21' )
;
DROP FUNCTION valid_date(DATE) ;
CREATE FUNCTION valid_date(DATE) RETURNS boolean
AS $body$
declare
found boolean ;
zdate ALIAS FOR $1;
begin
found = false;
SELECT true INTO found
WHERE EXISTS (
SELECT * FROM period p
WHERE (p.start_date > zdate
AND p.start_date < zdate + interval '7 day' )
OR ( p.start_date < zdate AND p.end_date > zdate )
OR ( p.start_date < zdate AND p.end_date IS NULL
AND p.start_date >= zdate - interval '7 day' )
)
;
if (found = true) then
return false;
else
return true;
end if;
end;
$body$ LANGUAGE plpgsql;
\echo 2011-01-01:true
SELECT valid_date('2011-01-01' );
\echo 2012-04-08:false
SELECT valid_date('2012-04-08' );
\echo 2012-04-30:true
SELECT valid_date('2012-04-30' );
BTW:我真的认为所需的功能应该作为表约束实现,由触发函数(可能基于上述函数)强加。