我有一个postgres
查询,当我将其作为查询运行时,它可以正常工作。但是,我想将其转换为pl/r
,并能够动态输入开始日期和结束日期。
有效的SQL是:
with date as (
select d as first_day,
d + interval '1 month' - interval '1 day' as last_day
from generate_series('2010-01-01'::date,
'2018-12-01'::date,
'1 month') as d
) select last_day::date as snapshot_date from date;
想做一个pl / r:
DROP FUNCTION IF EXISTS standard.seq_monthly(min_date_str char, max_date_str char);
CREATE FUNCTION standard.seq_monthly(min_date_str char, max_date_str char)
RETURNS setof dates AS
$$
with date as (
select d as first_day,
d + interval '1 month' - interval '1 day' as last_day
from generate_series(min_date_str::date,
max_date_str::date,
'1 month') as d
) select last_day::date as snapshot_date from date;
$$
LANGUAGE 'plr';
select * from standard.seq_monthly('2010-01-01' , '2018-12-01')
但是,运行该函数时出现错误。错误是
在R解析错误<- 函数(min_date_str,max_date_str)
尝试将最大最小日期也声明为日期。
我们非常感谢您的帮助。
答案 0 :(得分:2)
PL / R是PostgreSQL中的procedural language扩展名(类似于plpython,plperl,plphp),可以在其中运行有效的兼容R语言代码。您正在尝试无法仅在R会话中运行的SQL,因此您的代码将在PG plr
存储的函数中失败。
但是,不需要扩展,因为可以使用非常基本的SQL
语言(通常效率更高)来处理您的需求,以按指定的输入范围返回所需的日期范围表:
CREATE OR REPLACE FUNCTION seq_monthly(min_date_str char, max_date_str char)
RETURNS TABLE(snapshot_date date) AS
$$
with mydate as (
select d as first_day,
DATE_TRUNC('month', d)
+ '1 MONTH'::INTERVAL
- '1 DAY'::INTERVAL as last_day
from generate_series(min_date_str::date,
max_date_str::date,
'1 month') as d
)
select last_day::date as snapshot_date from mydate;
$$
LANGUAGE SQL STABLE;
select * from seq_monthly('2010-01-31' , '2018-12-31');
现在,如果您真的想要一个plr
存储的函数,请在给定的日期范围内使用R的seq()
:
CREATE FUNCTION standard.seq_monthly(min_date_str char, max_date_str char)
RETURNS setof dates AS
$$
seq(as.Date(min_date_str), as.Date(max_date_str), by='month')
$$
LANGUAGE 'plr';
select * from standard.seq_monthly('2010-01-01' , '2018-12-01')
答案 1 :(得分:1)
一种解决方案是不通过plr,而是编写一个sql查询:
with max_min_date as(
select max(snapshot_date) as max_date_str, min(snapshot_date) as min_date_str from data
) ,
ts as (
select d as first_day,
d + interval '1 month' - interval '1 day' as last_day
from generate_series((select min_date_str from max_min_date)::date,
(select max_date_str from max_min_date)::date,
'1 month') as d
) select last_day::date as snapshot_date from ts;
以防万一,您需要月末日期而不是月初:
with max_min_date as(
with max_min_wrk as (
select max(snapshot_date) as max_date_str, min(snapshot_date) as min_date_str from data
) select cast(date_trunc('month', max_date_str) as date) as max_date, cast(date_trunc('month', min_date_str) as date) as min_date from max_min_wrk
),
ts as (
select d as first_day,
d + interval '1 month' - interval '1 day' as last_day
from generate_series((select min_date from max_min_date)::date,
(select max_date from max_min_date)::date,
'1 month') as d
) select last_day::date as snapshot_date from ts
order by snapshot_date asc;