【问题标题】:I am trying to convert a postgresql query to a plr function我正在尝试将 postgresql 查询转换为 plr 函数
【发布时间】:2018-12-10 17:45:23
【问题描述】:

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

但是,我在运行该函数时遇到了错误。错误是

在“PLR711818

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

非常感谢任何帮助。

【问题讨论】:

  • PL/R 需要 R 代码而不是 SQL。顺便说一句,使用 SQL 比任何过程扩展(包括 Postgres 的内置 plpgsql)更有效。
  • BTW:date 几乎是一个保留字。你可能会输,现在或将来。

标签: sql r postgresql plr


【解决方案1】:

PL/R 是 PostgreSQL 中的 procedural language 扩展(类似于 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')

【讨论】:

  • 不知何故,其中任何一个都不适用于我的 postgres。此外,该错误没有任何解释。只是说错误!可能是我或我的 postgres 版本。很快会再次检查
  • 在 rextester 演示链接上,尝试传递该月的最后一个日期
  • 那是因为可爱的二月天数缩短了,此后的模式也随之而来。但是,DATE_TRUNC() 有更好的方法。查看更新的答案和演示链接。
  • 完美!谢谢!!
  • 使用作者的site,其中包括 html/pdf 文档,包括安装步骤。顺便说一句,作者与 RPostgreSQL,R 包的帮助相同。
【解决方案2】:

其中一种解决方法是不走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-08
  • 1970-01-01
  • 2014-04-01
  • 2021-02-03
  • 1970-01-01
  • 1970-01-01
  • 2023-02-01
  • 1970-01-01
相关资源
最近更新 更多