在 Postgresql 函数中添加日期中的工作日

Add business days in date in Postgresql function

我必须将 SQL 服务器过程转换为 PostgreSQL 以增加给定日期的天数。我做了一些研究并找到了一个解决方案,但它只适用于正数天数,当我传递一个负数(从给定日期后退)时它永远不会起作用。 以下是函数:

CREATE OR REPLACE FUNCTION public.add_business_day(
    from_date date,
    num_days integer)
    RETURNS date
    LANGUAGE 'sql'

    COST 100
    VOLATILE 
    
AS $BODY$
    select d
    from (
        select d::date, row_number() over (order by d)
        from generate_series(from_date+ 1, from_date+ num_days * 2 + 5, '1d') d
        where 
            extract('dow' from d) not in (0, 6) 
        ) s
    where row_number = num_days
$BODY$;

是否有任何 fix/modification 或替代此逻辑以使其在正天数和负天数上都有效?

demo:db<>fiddle

我相信您需要一个条件查询来生成日期系列。像这样:

select 
    d::date, 
    CASE 
        WHEN num_days >= 0 THEN row_number() over (order by d) - 1
        ELSE row_number() over (order by d DESC) * -1 + 1
    END as row_number,
    extract('dow' from d)
from
    generate_series(
        CASE WHEN num_days >= 0 THEN current_date ELSE current_date + num_days * 2 - 5 END, 
        CASE WHEN num_days >= 0 THEN current_date + num_days * 2 + 5 ELSE current_date END, 
        '1d'
    ) d

这会切换 generate_series() 函数的起始值和结束值,并更改 row_number() window 函数的顺序,以确保它以正确的顺序计算负值.

可以使用 sign() 函数从 generate_series() 函数中删除 CASE 子句。有了这个你就可以控制你要加的区间了,可以是负数,当然:

demo:db<>fiddle

select 
    d::date, 
    CASE 
        WHEN num_days >= 0 THEN row_number() over (order by d) - 1
        ELSE row_number() over (order by d DESC) * -1 + 1
    END as row_number,
    extract('dow' from d)
from
    generate_series(current_date, current_date + num_days * 2 + sign(num_days)::int * 5, sign(num_days)::int * interval '1d') d