我正在尝试将Postgresql查询转换为plr函数

时间:2018-12-10 17:45:23

标签: sql r postgresql plr

我有一个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)

尝试将最大最小日期也声明为日期。

我们非常感谢您的帮助。

2 个答案:

答案 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');

Rextester demo


现在,如果您真的想要一个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;