3

我有一个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 解析错误在“PLR711818 <- function(min_date_str,max_date_str)

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

非常感谢任何帮助。

4

2 回答 2

2

PL/R 是 PostgreSQL 中的一种过程语言扩展(类似于 plpython、plperl、plphp),可以在其中运行有效、兼容的 R 语言代码。您正在尝试的 SQL 本身不能在 R 会话中运行,因此您的代码将在 PGplr存储函数中失败。

但是,不需要这样的扩展,因为您可以使用非常基本的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 演示


现在,如果您真的想要一个plr存储函数,请seq()在给定日期范围内使用 R:

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')
于 2018-12-10T20:31:51.860 回答
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;
于 2018-12-10T19:40:12.560 回答