SQL中时间段的交集和合并

时间:2018-02-02 08:02:42

标签: sql sql-server time period

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

首先,我有一个包含开始日期和结束日期的多行的表格,我希望将它们合并在一起,如下所示:

Combination

然后有了这个结果而另一个来自另一个表,我想找出他们两个之间的交集,就像这样,但只有2个输入(找到两者中存在的时期):

Intersection

一旦我有了交叉点就是总结它的时间。

这里我提供了一个带有预期输出的SQL小提琴,其中有一个例子:

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

3 个答案:

答案 0 :(得分:1)

样本数据准备

<div id="15175860223750456"><script type="text/JavaScript" src="https://www.aparat.com/embed/xom4D?data[rnddiv]=15175860223750456&data[responsive]=yes"></script></div>

查询:

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')
;

相交时间间隔在CTE中组合。然后与您的intersectTable一起查找重叠时段。如果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

,则两个时段重叠

答案 1 :(得分:0)

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

enter image description here

public static ColumnInfo[] GetColumnsInfo(Type linqTableClass)
    {
        // Just looking in the loop to see if I missed something.
        foreach (var fld in linqTableClass.GetProperties())
        {
            foreach (var attr in fld.CustomAttributes)
            {
                foreach (var arg in attr.NamedArguments)
                {
                    if (arg.MemberName == "Name")
                        Debug.WriteLine(arg.MemberName);

                    Debug.WriteLine("{0}", arg.MemberName);
                }
            }
        }

        var columnInfoQuery =
            from field in linqTableClass.GetProperties()
            from attribute in field.CustomAttributes
            from namedArgument in attribute.NamedArguments
            where namedArgument.MemberName == "DbType"
            select new ColumnInfo
            {
                //ColumnName = field.Name,
                ColumnName = namedArgument.MemberName,
                DatabaseType = namedArgument.TypedValue.Value.ToString(),
            };
        return columnInfoQuery.ToArray();
    }

答案 2 :(得分:0)

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

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

首先让您准备一个测试表:

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')
;

拥有表格后,让您创建带有时间交叉点的视图:

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