How to calculate overlaping time and length of conflict

时间:2019-04-08 13:00:07

标签: sql sql-server tsql ssms

Employee table has four columns. Employee, Start, End, Diff. Diff column is the duration and calculated as End - Start.

I want to find the conflict between the Start and End time range. For instance, Employee A has three rows: First rows Start time is 01:02 and end time is 01:05 but second row start time is 01:03 which is a conflict in the first row data.

Sample Data:

   employee   StartDate    EndDate       Start         End        Diff 
    A       04/08/2019   04/08/2019       01:02:00   01:05:00       3
    A       04/08/2019   04/08/2019       01:03:00   01:08:00       5
    A       04/08/2019   04/08/2019       01:014:00  01:21:00       7
    B       04/08/2019   04/08/2019       02:00:00   02:17:00      17

I want to only select the specific start and end time for employee A that has an overlap in their start and end time and want to calculate total length of conflict in a new column using t-sql. i'm a newbie and need help. please anyone?

SELECT TOP (100) a.ccx_employeename AS employee
    ,CONVERT(Date,[a].[ccx_starttime]) AS [Start Date],CONVERT(Date,[a].[ccx_endtime]) AS [End Date], CONVERT(time (0), a.ccx_starttime) AS StartTime
    , CONVERT(time (0), a.ccx_endtime) AS EndTime
    , CONVERT (time(0), (a.ccx_endtime - a.ccx_starttime)) AS Duration
FROM ccp_sim_MSCRM.dbo.Filteredccx_Recorded_Service as a 
where CONVERT(time (0), a.ccx_starttime) BETWEEN CONVERT(time (0), a.ccx_starttime) And CONVERT(time (0), a.ccx_endtime) 

As first and second rows has conflict I want to show that two rows. As well as conflict duration is 2 minutes in this example. First row end time is 01:05 but second rows start time is 01:03 so conflict duration is 01:05 - 01:03 = 2 minutes

Desired Output

employee   StartDate    EndDate       Start         End        Diff 
A       04/08/2019   04/08/2019       01:02:00   01:05:00       3
A       04/08/2019   04/08/2019       01:03:00   01:08:00       5

duration of conflict : 2 mins

3 个答案:

答案 0 :(得分:0)

I would join the table over itself, though maybe not the most effective :

SELECT
    e1.employee,
    e1.Start as firstStart,
    e1.End as firstEnd,
    e2.Start as secondStart,
    e2.End as secondEnd,
    e1.End - e2.Start as conflictDuration
FROM
    Employee as e1 inner join
    Employee as e2 on (
        e1.employee = e2.employee and 
        e2.Start < e1.End and
        e2.End > e1.Start
    )

答案 1 :(得分:0)

您的问题有几个部分:

  • 找到冲突的行
  • 计算冲突时间
  • 以您想要的格式输出

下面的解决方案仅涵盖前两部分,并假定日期和时间字段为组合字段。

我添加了一些唯一的键来对结果进行重复数据删除,并对行进行“排序”以进行比较。在下面的代码中,它是“ id”。

declare @t table (id int identity,employee char(1), StartDateTime smalldatetime, EndDateTime smalldatetime, diff as DATEDIFF(minute,StartDateTime,EndDateTime))
insert into @t values('A','2019-04-08 01:02','2019-04-08 01:05')
insert into @t values('A','2019-04-08 01:03','2019-04-08 01:08')
insert into @t values('A','2019-04-08 01:14','2019-04-08 01:21')
insert into @t values('B','2019-04-08 02:00','2019-04-08 02:17')

SELECT T1.employee, T1.StartDateTime, T1.EndDateTime, T2.StartDateTime, T2.EndDateTime
,      (T1.diff + T2.diff)
       - DATEDIFF(minute, CASE WHEN T1.StartDateTime < T2.StartDateTime THEN T1.StartDateTime ELSE T2.StartDateTime END   -- MIN(Start)
                        , CASE WHEN T1.EndDateTime   > T2.EndDateTime   THEN T1.EndDateTime   ELSE T2.EndDateTime   END)  -- MAX(End)
       AS "duration of conflict"
FROM @t AS T1
JOIN @t AS T2
  ON  T2.employee = T1.employee
  AND T2.id       > T1.id        -- Each only once
  AND T2.StartDateTime < T1.EndDateTime
  AND T2.EndDateTime   > T1.StartDateTime

答案 2 :(得分:0)

这对我来说是使用LEAD / LAG函数的理想场所。结合使用一些子查询和IIF语句,您可以计算出所需的结果。

示例:

DECLARE @Employee TABLE
(
    Employee VARCHAR(1),
    startDate DATE,
    endDate DATE,
    [start] TIME,
    [end] TIME,
    diff AS DATEDIFF(MINUTE,[start],[end])
)

INSERT INTO @Employee (Employee, startDate, endDate, start, [end])
VALUES
    ('A',CAST('2019-04-08' AS DATE),CAST('2019-04-08' AS DATE),'01:02:00','01:05:00'),
    ('A',CAST('2019-04-08' AS DATE),CAST('2019-04-08' AS DATE),'01:03:00','01:08:00'),
    ('A',CAST('2019-04-08' AS DATE),CAST('2019-04-08' AS DATE),'01:14:00','01:21:00'),
    ('B',CAST('2019-04-08' AS DATE),CAST('2019-04-08' AS DATE),'02:00:00','02:17:00')

SELECT
    Employee.Employee,
    Employee.startDate,
    Employee.endDate,
    Employee.start,
    Employee.[end],
    diff,
    (IIF(ISNULL(lagConflict,0)>0,ISNULL(lagConflict,0),0)+IIF(ISNULL(Employee.leadConflict,0)>0,ISNULL(Employee.leadConflict,0),0)) AS conflict
FROM
    (
        SELECT
            Employee,
            startDate,
            endDate,
            start,
            [end],
            diff,
            DATEDIFF
            (
                MINUTE,
                [start],
                LAG([end],1)
                OVER
                (
                    PARTITION BY
                        Employee,
                        startDate,
                        endDate
                    ORDER BY
                        [start],
                        [end]
                )
            ) AS lagConflict,
            DATEDIFF
            (
                MINUTE,
                [end],
                LEAD([start],1)
                OVER
                (
                    PARTITION BY
                        Employee,
                        startDate,
                        endDate
                    ORDER BY
                        [start],
                        [end]
                )
            )*-1 AS leadConflict
        FROM
            @Employee
    ) AS Employee
WHERE
    Employee.leadConflict > 0
    OR Employee.lagConflict > 0;

Microsoft SQL文档:LAG] 1