Home > Software design >  SQL determine business days passed since beginning of month using calendar table
SQL determine business days passed since beginning of month using calendar table

Time:02-12

I have a calendar table with all dates and a column indicating whether its a business day.
For example

Date Business_Day
1/1/2021 False
1/2/2021 False
1/3/2021 True

... I have another table with dates and would like to determine how many business days have elapsed since the beginning of that month. For example:

Date Business_Days_Passed
1/1/2022 0
1/2/2022 0
1/3/2022 1
1/4/2022 2
1/15/2022 10
2/2/2022 2
2/11/2022 9
2/12/2022 9

Is there a way to do this using standard sql? I was thinking of creating some kind of UDF but there may be an easier way? This using snowflake so there is access to all common date functions and window/udf functions

CodePudding user response:

Here is a simple query

Select count(c.date) from calendar c 
Join dates_to_check d
Where month(c.date) = month(d.day)
And day(c.date) < day(d.day)
And business_Day = True;

CodePudding user response:

I think you can accomplish this with a simple join and a window function. I am assuming your date is formatted yyyy-mm-dd which would allow left(date,7) to get the year-month. If not, just use a different function to extract year-month for aggregating per month.

select a.date, 
       count(b.business_day) over (partition by left(a.date,7) order by a.date) business_days_elapsed
from table a
     left join calendar_table b on a.date=b.date and b.business_day='True'
group by a.date, b.business_day; --in case your data is not deduped before window function is applied

CodePudding user response:

try this with the single, table you can create a view

create or replace table bus_day as
SELECT column1  Date, column2   Business_Day  from values
('1/1/2021',    'False'),
('1/2/2021',    'False'),
('1/3/2021',    'True'),
('1/4/2021',    'True'),
('1/5/2021',    'True'),
('1/6/2021',    'True'),
('1/7/2021',    'True'),
('2/1/2021',    'True'),
('2/2/2021',    'True'),
('2/3/2021',    'True'),
('2/4/2021',    'True'),
('2/5/2021',    'False'),
('2/6/2021',    'False'),
('2/7/2021',    'True')
;
 
  SELECT DATE,FIRST_DAY_MONTH 
 ,row_number() over (partition by month(to_date(Date,'mm/dd/yyyy')) order by date) as row_number
 ,count_if(business_day ='True') over (partition by month(to_date(Date,'mm/dd/yyyy'))   order by DATE ) count_days
FROM (
  select Date , DATE_TRUNC('month',to_date(Date,'mm/dd/yyyy')) frst_day,
  iff(to_date(Date,'mm/dd/yyyy') = DATE_TRUNC('month',to_date(Date,'mm/dd/yyyy')), 'Y', 'N') first_day_Month , 
  business_day from bus_day order by date
   );

CodePudding user response:

So if your dates has "all dates" you can use a JOIN like:

SELECT d.date,
    count_if(w.business_day) AS business_days_passed
FROM dates_of_interest AS d
JOIN work_days AS w
    ON date_trunc(month, d.date) = date_trunc(month, w.date) 
        AND d.date >= w.date
GROUP BY 1
ORDER BY 1;

But if you Dates have gaps in them, like my example data does... you would want the LEFT JOIN form..

SELECT d.date,
    count_if(w.business_day) AS business_days_passed
FROM dates_of_interest AS d
LEFT JOIN work_days AS w
    ON date_trunc(month, d.date) = date_trunc(month, w.date) 
        AND d.date >= w.date
GROUP BY 1
ORDER BY 1;

And using this wonderful fake data:

WITH work_days(date, business_day) AS (
    SELECT TO_DATE(column1, 'mm/dd/yyyy'), column2
    FROM VALUES
        ('1/1/2022', False),
        ('1/2/2022', False),
        ('1/3/2022', True),
        ('1/4/2022', True),
        ('1/5/2022', True),
        ('1/6/2022', True),
        ('1/7/2022', True),
       ('1/10/2022', True),
       ('1/11/2022', True),
       ('1/12/2022', True),
       ('1/13/2022', True),
       ('1/13/2022', True)    
), dates_of_interest(date) AS (
    SELECT TO_DATE(column1, 'mm/dd/yyyy')
    FROM VALUES 
        ('1/1/2022'),
        ('1/2/2022'),
        ('1/3/2022'),
        ('1/4/2022'),
        ('1/15/2022'),
        ('2/2/2022'),
        ('2/11/2022'),
        ('2/12/2022')
)

we get:

DATE BUSINESS_DAYS_PASSED
2022-01-01 0
2022-01-02 0
2022-01-03 1
2022-01-04 2
2022-01-15 10
2022-02-02 0
2022-02-11 0
2022-02-12 0
  • Related