Reputation: 491
I have a postgres
query, which works fine when I run it as a query. However, I would like to convert it to pl/r
and be able to dynamically input the start and end date.
The SQL that works is:
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;
Would like to make a pl/r like:
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')
However, I am getting error while running the function. The error is
R parse error caught in "PLR711818 <- function(min_date_str,max_date_str)
Have tried declaring the max min date to be date as well.
Any help is highly appreciated.
Upvotes: 3
Views: 199
Reputation: 107687
PL/R is a procedural language extension in PostgreSQL (similar to plpython, plperl, plphp) where valid, compliant R language code can be run. You are attempting SQL which cannot by itself run inside an R session, so your code will fail within a PG plr
stored function.
However, there is no need for such an extension as your needs can be handled with the very basic SQL
language (often more times efficient) to return needed date range table by specified input range:
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');
Now, if your really want a plr
stored function, use R's seq()
on given date range:
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')
Upvotes: 2
Reputation: 491
One of the solutions is to not go via plr, but write a sql query:
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;
In case, you'd need end of month date instead of start of month:
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;
Upvotes: 1