Calculate closest working day in Postgres

后端 未结 4 1075
没有蜡笔的小新
没有蜡笔的小新 2021-01-05 13:24

I need to schedule some items in a postgres query based on a requested delivery date for an order. So for example, the order has a requested delivery on a Monday (20120319

相关标签:
4条回答
  • 2021-01-05 13:55
    SELECT y.d AS prep_day
    FROM  (
        SELECT generate_series(dday - 8, dday - 1, interval '1d')::date AS d
        FROM (SELECT '2012-03-19'::date AS dday) x
        ) y
    LEFT   JOIN holiday h USING (d)
    WHERE  h.d IS NULL
    AND    extract(isodow from y.d) < 6
    ORDER  BY y.d DESC
    LIMIT  1;
    
    • It should be faster to generate only as many days as necessary. I generate one week prior to the delivery. That should cover all possibilities.

    • isodow as extract parameter is more convenient than dow to test for workdays.

    • min() / max(), ORDER BY / LIMIT 1, that's a matter of taste with the few rows in my query.

    • To get several candidate days in descending order, not just the top pick, change the LIMIT 1.

    • I put the dday (delivery day) in a subquery so you only have to input it once. You can enter any date or timestamp literal. It is cast to date either way.

    0 讨论(0)
  • 2021-01-05 13:59

    To have the previous work day:

    select max(s.a) as work_day
    from (
        select s.a::date
        from generate_series('2012-01-02'::date, '2050-12-31', '1 day') s(a)
        where extract(dow from s.a) between 1 and 5
        except
        select holiday_date
        from holiday_table
        ) s
    where s.a < '2012-03-19'
    ;
    

    If you want the next work day just invert the query.

    0 讨论(0)
  • 2021-01-05 14:05
    CREATE TABLE Holidays (Holiday, PrecedingBusinessDay) AS VALUES
      ('2012-12-25'::DATE, '2012-12-24'::DATE),
      ('2012-12-26'::DATE, '2012-12-24'::DATE);
    SELECT Day, COALESCE(PrecedingBusinessDay, PrecedingMondayToFriday)
    FROM
      (SELECT Day, Day - CASE DATE_PART('DOW', Day)
                             WHEN 0 THEN 2
                             WHEN 1 THEN 3
                             ELSE 1
                         END AS PrecedingMondayToFriday
       FROM TestDays) AS PrecedingMondaysToFridays
    LEFT JOIN Holidays ON PrecedingMondayToFriday = Holiday;
    

    You might want to rename some of the identifiers :-).

    0 讨论(0)
  • 2021-01-05 14:16

    This gets you previous business day.

    SELECT 
        CASE (EXTRACT(ISODOW FROM current_date)::integer) % 7
            WHEN 1 THEN current_date-3
            WHEN 0 THEN current_date-2
            ELSE current_date-1
        END AS previous_business_day
    
    0 讨论(0)
提交回复
热议问题