Я пытаюсь преобразовать запрос postgresql в функцию plr - PullRequest
0 голосов
/ 10 декабря 2018

У меня есть запрос 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 <- (min_date_str, max_date_str) </p>

Попытка также объявить максимальную минимальную дату как дату.

Любая помощь высоко ценится.

Ответы [ 2 ]

0 голосов
/ 10 декабря 2018

PL / R - это расширение процедурного языка в PostgreSQL (аналогично plpython, plperl, plphp), где можно запустить корректный, совместимый код языка R.Вы пытаетесь выполнить SQL, который сам по себе не может быть запущен в сеансе R, поэтому ваш код не будет работать в хранимой функции 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')
0 голосов
/ 10 декабря 2018

Одним из решений является не проходить через 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;
...