【问题标题】:How to calculate overlaping time and length of conflict如何计算重叠时间和冲突长度
【发布时间】:2019-04-08 13:00:07
【问题描述】:

Employee 表有四列。员工,开始,结束,差异。 Diff 列是持续时间,计算方式为 End - Start。

我想找出开始和结束时间范围之间的冲突。 例如,员工 A 有三行: 第一行开始时间是 01:02,结束时间是 01:05,但第二行开始时间是 01:03,这是第一行数据的冲突。

样本数据:

   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

我只想为员工 A 选择开始和结束时间重叠的特定开始和结束时间,并且想使用 t-sql 计算新列中的冲突总长度。我是新手,需要帮助。有人请吗?

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) 

由于第一行和第二行有冲突,我想显示这两行。在此示例中,冲突持续时间为 2 分钟。第一行结束时间是 01:05,但第二行开始时间是 01:03,所以冲突持续时间是 01:05 - 01:03 = 2 分钟

期望的输出

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

【问题讨论】:

  • 您使用的是 MySQL、Sybase 还是 MS SQL Server?
  • MS Sql 服务器管理工​​作室
  • 因此,为了更好地理解您的问题,并尝试激发您自己的一些想法......您基本上想要一个结束时间大于开始时间的员工的任何行的结果集下面的行。您将需要对员工进行分组,并按开始时间排序。其他需要考虑的是日期,我在这里看不到任何迹象,但这可能需要考虑,因为您的逻辑需要了解一天的时间不关心其他日子的时间。最后,不需要TOP 100,这可能会限制你前进。
  • haag1 开始日期和结束时间相同。例如,对于员工 A,两个时间范围都与 04/08/2019 开始的日期相同,一份工作的时间是 01:02:00- 01:05:00,第二份工作的时间是 01:03:00-01 :08:00 在这种情况下会有什么修改?
  • 顺便提一下你的问题非常好。

标签: sql sql-server tsql ssms


【解决方案1】:

我会自己加入表格,虽然可能不是最有效的:

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
    )

【讨论】:

  • 如果您想再看一遍,我已经对问题进行了一些更改。谢谢
  • 现在可能会更好,我忘记了加入子句中的条件
  • 这个逻辑并没有真正给出所需的输出,因为我试图只选择有冲突的记录。这个人试图把每一个记录都打破,并把它变成一场冲突!
  • 并且只返回包含冲突的记录对(作为新记录)。内连接和 on 子句构成了 sur。
【解决方案2】:

你的问题有几个部分:

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

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

我添加了一些唯一键来删除结果并“排序”行以进行比较。在下面的代码中,它是“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

【讨论】:

  • 任何其他不使用表变量的方式?
  • 因为您正在为这一小部分数据集创建表变量,但如果它是数千条记录,那么这样做并不是很有效......或者我错了?
  • 表变量的使用并不重要。您可以改用常规表。如果您提供了创建测试数据的语句,我会使用您的。当它对性能有所影响时,像这样的查询需要在您要加入它们的列上建立索引。在我发布的示例查询中,(employee, id) 上的索引将是理想的。话虽如此,要获得您要求的结果,您必须将表与自身连接起来,没有其他方法(或者更准确地说:没有更好的执行方式)。
【解决方案3】:

这对我来说是使用 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

【讨论】:

  • Dean,有没有办法在一开始就避免使用表变量?我觉得对于包含数千条记录的大容量表来说,表变量不是一个好主意......如果我错了或者如果你对我有建议,请纠正我,以便我可以实现这个查询包含数千条记录的卷表。
  • 表变量仅用于示例。在您的环境中,我假设您的 Employee 表将是具有适当索引的标准表/表。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-10
相关资源
最近更新 更多