Подсчет рабочих дней PostgresSQL

#sql #postgresql #datetime #count #sql-function

#sql #postgresql #дата и время #подсчет #sql-функция

Вопрос:

Я пытаюсь сделать что-то вроде этого:

 SELECT t.id, t.startdate, t.enddate, FOO
FROM table
  

Где «Foo» — это какой-то sql-мумбо-джамбо для вычисления рабочих дней между startdate и enddate, например:

  ---- ------------ ------------ -------------- 
| id | startdate  |  enddate   | businessdays |
 ---- ------------ ------------ -------------- 
| 1  | 2020-09-12 | 2020-09-28 |     11       | 
| 2  | 2020-09-02 | 2020-09-28 |     19       | 
| 3  | 2020-09-22 | 2020-09-28 |     5        | 
 ---- ------------ ------------ -------------- 
  

Я смог создать функцию для этого без проблем:

 CREATE OR REPLACE FUNCTION getbusinessday(startdate date, enddate date DEFAULT current_date) RETURNS int
LANGUAGE plpgsql
AS
$$
DECLARE
    daycount integer;
BEGIN
    SELECT COUNT(i) 
    INTO daycount
    FROM generate_series(startdate,enddate,'1 day') i 
    WHERE EXTRACT(DOW FROM i) NOT IN (0, 6);
    RETURN daycount;
END;
$$;
  

Могу ли я в любом случае добиться этого без использования этой функции?

Бонусный вопрос для получения бонусных баллов:

Можно ли разрешить вводить временную метку и просто приводить ее к дате в рамках фактической функции? Мне просто любопытно.

Ответ №1:

Вы можете заменить функцию боковым соединением:

 select t.*, x.*
from mytable t
cross join lateral (
    select count(*) businessdays
    from generate_series(t.startdate, coalesce(t.enddate, current_date), '1 day') x(dt)
    where extract (dow from x.dt) not in (0, 6)
) x
  

Я не уверен в вашем вопросе относительно приведения временных меток / дат. Если в ваших столбцах есть компонент времени, и вы не хотите его учитывать, вы можете использовать generate_series() :

 from generate_series(t.startdate::date, coalesce(t.enddate::date, current_date), '1 day') x(dt)
  

Комментарии:

1. Спасибо за быстрый ответ! Я рассмотрю боковое соединение. Что касается дополнительного вопроса, я считаю, что это ответ на него. Я проверю утром и это как ответ, если это сработает.