SQL 中时间段的交集和合并

Intersection and consolidation of time periods in SQL

我想实现在 Time Period Library for .NET 中可用的类似功能,但在 SQL 中可用。

首先,我有一个 table,其中有几行带有开始日期和结束日期,我想像这样将它们合并在一起:

然后根据那个结果和另一个来自不同 table 的结果,我想找出它们两者之间的交集,就像这样,但只有 2 个输入(找到两者中都存在的句点) :

一旦我有了交集,就可以总结时间了。

这里我提供了一个 SQL Fiddle 和一个例子的预期输出:

http://sqlfiddle.com/#!18/504fa/3

PinX0,我不确定我是否完全理解你的问题/要求。 以下查询为您提供 ExpectedIntersectOutput 的结果:-

Insert into #ExpectedCombineOutput
select distinct min(startdate), max(enddate) from 
(
Select tc.IdDoc as IdDoc, tcw.IdDoc as SecIdDoc, 
case when (tc.startdate between tcw.startdate and tcw.enddate) then tcw.startdate else tc.StartDate end as StartDate,
case when (tc.enddate between tcw.startdate and tcw.enddate) then tcw.enddate else tc.EndDate end as EndDate
from #TableToCombine tc
left join #TableToCombine tcw on tc.IdDoc <> tcw.IdDoc
) test group by IdDoc

Insert into #ExpectedIntersectOutput
Select case when ti.startdate <= tc.startdate then tc.startdate else ti.startdate end as 'StartDate',
       case when ti.enddate >= tc.enddate then tc.enddate else ti.enddate end as 'EndDate'
from #TableToIntersect ti
inner join #ExpectedCombineOutput tc on 1=1

示例数据准备

CREATE TABLE TableToCombine
    ([IdDoc] int IDENTITY(1,1), [IdEmployee] int, [StartDate] datetime, [EndDate] datetime)
;

INSERT INTO TableToCombine
    (IdEmployee, StartDate, EndDate)
VALUES
    (1, '2018-01-01 06:00:00', '2018-01-01 14:00:00'),
    (2, '2018-01-01 11:00:00', '2018-01-01 19:00:00'),
    (3, '2018-01-01 20:00:00', '2018-01-02 03:00:00'),
    (1, '2018-01-02 06:00:00', '2018-01-02 14:00:00'),
    (2, '2018-01-02 11:00:00', '2018-01-02 19:00:00')
;

CREATE TABLE TableToIntersect
    ([IdDoc] int IDENTITY(1,1), [OrderId] int, [StartDate] datetime, [EndDate] datetime)
;

INSERT INTO TableToIntersect
    (OrderId, StartDate, EndDate)
VALUES
    (1, '2018-01-01 09:00:00', '2018-01-02 12:00:00')
;

查询:

with ExpectedCombineOutput as (
    select
        grp, StartDate = min(StartDate), EndDate = max(EndDate)
    from (
        select
            *, sum(iif(cd between StartDate and EndDate, 0, 1))over(order by StartDate) grp
        from (
            select
                *, lag(EndDate) over (order by IdDoc) cd
            from
                TableToCombine
        ) t
    ) t
    group by grp
)

select 
    a.grp, StartDate = iif(a.StartDate < b.StartDate, b.StartDate, a.StartDate)
    , EndDate = iif(a.EndDate < b.EndDate, a.EndDate, b.EndDate)
from
    ExpectedCombineOutput a
    join TableToIntersect b on a.StartDate <= b.EndDate and a.EndDate >= b.StartDate

相交的时间间隔在 CTE 中合并。然后加入您的 intersectTable 以查找重叠的时间段。如果 a.StartDate < b.EndDate and a.EndDate > b.StartDate

,则两个时间段重叠

这是 MySQL 中的一个工作示例。我为此使用了一个简单的视图。

让我们考虑与客户和员工的健身。您需要知道当员工在场时客户花费了多少小时。

先让大家准备一个测试table:

CREATE TABLE Customer
(id int NOT NULL AUTO_INCREMENT PRIMARY KEY,
 customerId int NOT NULL,
 arrival datetime,
 leaving datetime);

INSERT INTO Customer
    (customerId, arrival, leaving)
VALUES
    (1, '2018-01-01 06:00:00', '2018-01-01 14:00:00'),
    (2, '2018-01-01 11:00:00', '2018-01-01 19:00:00'),
    (3, '2018-01-01 20:00:00', '2018-01-02 03:00:00'),
    (1, '2018-01-02 06:00:00', '2018-01-02 14:00:00'),
    (2, '2018-01-02 11:00:00', '2018-01-02 19:00:00')
;

CREATE TABLE Employee
    (id int NOT NULL AUTO_INCREMENT PRIMARY KEY,
     employeeId int NOT NULL,
     arrival datetime,
     leaving datetime)
;

INSERT INTO Employee
    (employeeId, arrival, leaving)
VALUES
    (1, '2018-01-01 09:00:00', '2018-01-01 12:00:00',),
    (2, '2018-01-01 11:30:00', '2018-01-01 20:00:00')
;

当你有一个table,让你创建一个时间相交的视图:

CREATE OR REPLACE VIEW intersectionTimeView AS select e.employeeId, 
c.customerId,
IF(c.arrival>e.arrival, c.arrival, e.arrival) AS arrivalMax,
IF(c.leaving>e.leaving, e.leaving, c.leaving) AS leavingMin
FROM  Customer c, Employee e
WHERE TIMEDIFF(c.arrival,e.leaving)<=0
AND  TIMEDIFF(c.leaving,e.arrival)>=0

最后,您可以轻松地通过以下方式获取时间:

SELECT employeeId, SUM( timestampdiff(minute,arrivalMax,leavingMin)/60) as summ
FROM intersectionTimeView WHERE employeeId=2 
GROUP BY employeeId