使用日历 table 计算数据 table 中两个日期之间的工作日

Counting working days between two dates in data table using calendar table

我有一个数据 table,每个字符串包含 4 个日期: table example 我还有日历 table,其中包含我所在位置的假期和周末。 calendar table

我需要的是计算数据中以下对的工作日数 table:

我试过跟随 select,但它总是显示 1 个工作日,因为我把 calendar_date 放在前面:

select data_table.*, days.work_days 
from data_table
left join (
    select calendar_date, count(calendar_date) as work_days
    from calendar_table
    where type_of_day IN ('workday', 'workday shortened')
    group by calendar_date ) days
ON days.calendar_date between task_assigned_date and task_got_to_work_date

请就 SQL 提出建议,以实现正确加入那些 table。

要使用左联接,您需要更改分组方式。您也可以在 group byselect 中列出 data_table 中的实际列。

select data_table.*, count(days.calendar_date)
from data_table
left join calendar_table days
   ON days.calendar_date between task_assigned_date and task_got_to_work_date
      and type_of_day IN ('workday', 'workday shortened')
group by data_table.*

另一种选择是外部应用并以这种方式获取计数:

select data_table.*, days.work_days 
from data_table
outer apply (
    select count(calendar_date) as work_days
    from calendar_table
    where type_of_day IN ('workday', 'workday shortened')
      and calendar_date between task_assigned_date and task_got_to_work_date) days

如果您在 SQL 服务器上,请按如下方式使用 OUTER APPLY

select d.*, days.work_days 
from data_table d
outer apply (
    select count(calendar_date) as work_days
    from calendar_table c
    where c.type_of_day IN ('workday', 'workday shortened') 
      and c.calendar_date between d.task_assigned_date and d.task_got_to_work_date) days

横向连接绝对是解决问题的一种方法(即其他答案中的 apply 语法)。

一个更通用的答案只是一个相关的子查询:

select d.*, 
       (select count(*)
        from calendar_table c
        where c.type_of_day in ('workday', 'workday shortened') and
              c.calendar_date between d.task_assigned_date and d.task_got_to_work_datework_days 
       ) as work_days
from data_table d;

注意:如果性能是个问题,可能还有其他方法。如果是这种情况,请在此处接受其中一个答案并提出 new 问题。

解决方案在 POSTGRES 中非常适合我:

table example
join
calendar table ON tsrange(task_assigned_date, task_got_to_work_date)&&tsrange(calendar.start_time, calendar.end_time)