计算开始日期和结束日期之间的时间并减去没有工作时间的天数

时间:2021-07-30 15:09:30

标签: sql-server tsql

我的目标是检查电子邮件是否在工作日的 24 小时内得到回复。工作日的定义是是否在另一个表中注册了时间。这是因为我们有时在周六或周日工作,或者不包括节假日。我从该表中创建了一个视图,如果日期有工作时间,则为 1,如果没有注册工作时间,则为 0。

<头>
工作日期 已经工作
2021-04-01 00:00:00.000 1
2021-04-02 00:00:00.000 1
2021-04-03 00:00:00.000 1
2021-04-04 00:00:00.000 0
2021-04-05 00:00:00.000 1

举几个例子:

1. MailIncoming:2021-04-01 16:30:00,MailAnswering:2021-04-02 14:00:00

这个很简单,我不用减任何东西,24小时内回复邮件。

2. MailIncoming:2021-04-01 09:30:00,MailAnswering:2021-04-03 14:00:00

这个也很简单,我不用减任何东西,24小时内不回复邮件。

3. 来信:2021-04-03 12:30:00,来信:2021-04-05 10:00:00

有 1 天没有人工作,所以我需要从总时间中减去 1 整天,这样邮件就会在工作日的 24 小时内回复。

4. MailIncoming:2021-04-04 11:00:00,MailAnswering:2021-04-05 18:00:00

从 04 开始的剩余 13 小时不计入“工作日的 24 小时”,因此电子邮件会在工作日的 24 小时内回复。

此外,可以有多个日期,每个日期后面都是零。

所以我正在寻找的结果是:

<头>
邮件传入 邮件回复 总时间 TotalTimeWithoutDaysNotWorked
2021-04-04 11:00:00.000 2021-04-05 18:00:00.000 31 18

如何计算最后一列?还是我以错误的方式处理这个问题?

2 个答案:

答案 0 :(得分:0)

我建议你使用一列 HasNotWorked,所以表格是

create table WorkingDay(DateWorked Date, HasNotWorked int);
create table MailIncoming(MailIncoming DateTime, MailAnswering DateTime);

和行

insert into WorkingDay values('2021-04-01', 0);
insert into WorkingDay values('2021-04-02', 0);
insert into WorkingDay values('2021-04-03', 0);
insert into WorkingDay values('2021-04-04', 1);
insert into WorkingDay values('2021-04-05', 0);
insert into WorkingDay values('2021-04-06', 0);

insert into MailIncoming values('2021-04-04 11:00:00.000', '2021-04-06 18:00:00.000');

我想计算开始日期。如果在工作日,我们必须考虑邮寄的时间,否则是第一个工作日

case when 
        (select HasNotWorked from WorkingDay where DateWorked = convert(date, MailIncoming)) = 1 then 
        (select min(DateWorked) from WorkingDay where DateWorked > MailIncoming and HasNotWorked = 0)
      else MailIncoming end as startDate  

丢弃非工作日的那一天

((select sum(HasNotWorked) from WorkingDay where DateWorked between convert(date, startDate) 
  and convert(date, MailAnswering)
) * 24) as numNotWorkingDay 

所以查询可能是

select startDate, MailAnswering, MailIncoming, hour, numNotWorkingDay, hour - numNotWorkingDay hourWitoutWorkingDay
from (
  select
    MailAnswering, startDate, MailIncoming,
    DateDiff("hh", startDate, MailAnswering) hour, 
    ((select sum(HasNotWorked) from WorkingDay where DateWorked between convert(date, startDate) 
      and convert(date, MailAnswering)
    ) * 24) as numNotWorkingDay 

  from (
    select *,
      case when 
        (select HasNotWorked from WorkingDay where DateWorked = convert(date, MailIncoming)) = 1 then 
        (select min(DateWorked) from WorkingDay where DateWorked > MailIncoming and HasNotWorked = 0)
      else MailIncoming end as startDate  
    from MailIncoming) as startCalc
) as calcTable;

sqlfiddle

答案 1 :(得分:0)

该查询需要一种在 MailIncoming 和 MailAnswering 之间生成计算日期的方法,以便WorkingDay 表可以有一个LEFT JOIN(或INNER JOIN)。在这种情况下,查询使用 dbo.fnTally,众所周知,这是一种快速有效的生成行的方式。

表格

drop table if exists #WorkingDay;
go
create table #WorkingDay(
    DateWorked        Date,
    HasNotWorked      int);

drop table if exists #MailIncoming;
go
create table #MailIncoming(
    MailIncoming      DateTime,
    MailAnswering     DateTime);


insert into #WorkingDay values
('2021-04-01', 0),
('2021-04-02', 0),
('2021-04-03', 0),
('2021-04-04', 1),
('2021-04-05', 0),
('2021-04-06', 0);

insert into #MailIncoming values
('2021-04-01 16:30:00', '2021-04-02 14:00:00'),
('2021-04-01 09:30:00', '2021-04-03 14:00:00'),
('2021-04-03 12:30:00', '2021-04-05 10:00:00'),
('2021-04-04 11:00:00', '2021-04-05 18:00:00');

dbo.fnTally

CREATE FUNCTION [dbo].[fnTally]
/**********************************************************************************************************************
    Jeff Moden Script on SSC: https://www.sqlservercentral.com/scripts/create-a-tally-function-fntally
**********************************************************************************************************************/
        (@ZeroOrOne BIT, @MaxN BIGINT)
RETURNS TABLE WITH SCHEMABINDING AS 
 RETURN WITH
  H2(N) AS ( SELECT 1 
               FROM (VALUES
                     (1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)
                    ,(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)
                    ,(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)
                    ,(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)
                    ,(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)
                    ,(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)
                    ,(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)
                    ,(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)
                    ,(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)
                    ,(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)
                    ,(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)
                    ,(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)
                    ,(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)
                    ,(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)
                    ,(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)
                    ,(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)
                    )V(N))            --16^2 or 256 rows
, H4(N) AS (SELECT 1 FROM H2 a, H2 b) --16^4 or 65,536 rows
, H8(N) AS (SELECT 1 FROM H4 a, H4 b) --16^8 or 4,294,967,296 rows
            SELECT N = 0 WHERE @ZeroOrOne = 0 UNION ALL
            SELECT TOP(@MaxN)
                   N = ROW_NUMBER() OVER (ORDER BY N)
              FROM H8
;

查询

select mi.MailIncoming, mi.MailAnswering,
        avg(datediff(hour, MailIncoming, MailAnswering)) hrs_to_ans,
        sum(case when w.HasNotWorked=1 and 
                        v.calc_dt > mi_dt.inc_dt and 
                        v.calc_dt < mi_dt.ans_dt
                then -24
                when w.HasNotWorked=1 
                then datediff(hour, dateadd(day, 1, mi_dt.inc_dt), mi.MailIncoming)
            else 0 end) hrs_to_sub
from #MailIncoming mi
        cross apply (values (cast(MailIncoming as date), 
                            cast(MailAnswering as date))) mi_dt(inc_dt, ans_dt)
        cross apply dbo.fnTally(0, datediff(day, mi.MailIncoming, mi.MailAnswering)) fn
        cross apply (values (dateadd(day, fn.n, mi_dt.inc_dt))) v(calc_dt)
        left join #WorkingDay w on v.calc_dt=w.DateWorked
group by mi.MailIncoming, mi.MailAnswering
order by mi.MailIncoming;
MailIncoming            MailAnswering           hrs_to_ans  hrs_to_sub
2021-04-01 09:30:00.000 2021-04-03 14:00:00.000 53          0
2021-04-01 16:30:00.000 2021-04-02 14:00:00.000 22          0
2021-04-03 12:30:00.000 2021-04-05 10:00:00.000 46          -24
2021-04-04 11:00:00.000 2021-04-05 18:00:00.000 31          -13