在 PostgreSQL 中添加工作日

joh*_*855 3 postgresql date

我正在尝试找到一种将工作日添加到任何日期的方法。一个例子是:

date = '2017-04-28'  (It was a Friday)

date + 2 = '2017-05-02' (It skipped Saturday and Sunday)
Run Code Online (Sandbox Code Playgroud)

有没有办法在没有自定义查询的情况下做到这一点?

McN*_*ets 8

您可以使用generate_series()生成一系列日期,并使用extract()获取星期几。

然后简单地过滤那些星期几不是 0=星期日,6=星期六的日期。

with days as
(
    select dd, extract(DOW from dd) dw
    from generate_series('2017-04-28'::date, '2017-05-02'::date, '1 day'::interval) dd
)
select *
from   days
where  dw not in (6,0);
Run Code Online (Sandbox Code Playgroud)
日 | 体重
:--------------------- | :-
2017-04-28 00:00:00+01 | 5
2017-05-01 00:00:00+01 | 1
2017-05-02 00:00:00+01 | 2

dbfiddle在这里

如果必须排除公共假期和其他非工作日,可以建business_day表。只需插入上面的输出,然后删除所有必须排除的天数(在某些国家/地区,例如匈牙利,也可能需要添加额外的替换天数(通常是星期六))。当然,这必须维护(例如,您可以在每年 12 月准备下一年),但是由于没有内置功能可以了解那些日子,因此您没有更好的选择。

使用日历表

让我创建一个示例calendar表并插入一些值:

create table calendar
(
    id serial primary key, 
    cal_day date not null,
    bussines_day bool not null
);

insert into calendar (cal_day, bussines_day) values 
('20180101', false), ('20180102', true),
('20180103', false), ('20180104', true),
('20180105', false), ('20180106', true),
('20180107', false), ('20180108', true),
('20180109', false), ('20180110', true),
('20180111', false), ('20180112', true);
Run Code Online (Sandbox Code Playgroud)

现在您可以使用函数以这种方式获取下一个第 N 个工作日:

create or replace function add_business_day(from_date date, num_days int)
returns date
as $fbd$

    select max(cal_day) as the_day
    from (select   cal_day
          from     calendar
          where    cal_day > $1
          and      business_day = true
          order by cal_day
          limit    $2) bd;

$fbd$ language sql;
Run Code Online (Sandbox Code Playgroud)

或者

create or replace function add_business_day2(from_date date, num_days int)
returns date
as $fbd$

    select cal_day
    from   (select cal_day,
                   row_number() over (order by cal_day) rn
            from   calendar
            where  cal_day > $1
            and    business_day = true
            limit  $2) bd
    where  rn = $2;

$fbd$ language sql;
Run Code Online (Sandbox Code Playgroud)

两者都返回相同的结果:

select add_business_day('20180103', 4);
Run Code Online (Sandbox Code Playgroud)
| add_business_day |
| :--------------- |
| 2018-01-10 |
select add_business_day2('20180103', 4)
Run Code Online (Sandbox Code Playgroud)
| add_business_day2 |
| :---------------- |
| 2018-01-10 |

db<>在这里摆弄