合并日期范围Linq到SQL

时间:2016-04-26 01:48:03

标签: c# linq date linq-to-sql

注意:这是一个linq to sql问题,而不是一般的linq问题。 Linq to SQL限制你可以做什么。

我需要合并日期范围以删除重叠。在stackoverflow上已经存在对这个问题的现有答案,但是在linq到sql中没有实现答案(没有递归CTE,滞后等)。

SQL: Merge Date Ranges

使用SQL 92语法的第二个答案中有一个错误(如果有行与相同的结束日期相交,那么这些行不会被视为重叠)。

有什么建议吗?

提前谢谢

示例数据(从其他堆栈流Q无耻地复制)

PK |开始| ENDDATE

1 | 2012/07/21 02:00 | 2012/07/21 04:00
2 | 2012/07/21 03:00 | 2012/07/21 10:00
3 | 2012/07/21 06:00 | 2012/07/21 17:00
4 | 2012/07/21 18:00 | 2012/07/21 19:00

合并将导致:

PK |开始| ENDDATE

1 | 2012/07/21 02:00 | 2012/07/21 17:00
2 | 2012/07/21 18:00 | 2012/07/21 19:00

1 个答案:

答案 0 :(得分:1)

让我们先创建一个游戏区:

CREATE TABLE [dbo].[dateTable](
    [dt_from] [datetime2](7) NOT NULL,
    [dt_to] [datetime2](7) NOT NULL
) ON [PRIMARY]
GO

INSERT INTO [dbo].[dateTable]
           ([dt_from]
           ,[dt_to])
     VALUES 
('2012-07-21 02:00:00', '2012-07-21 04:00:00'),
('2012-07-21 03:00:00', '2012-07-21 10:00:00'),
('2012-07-21 06:00:00', '2012-07-21 17:00:00'),
('2012-07-21 18:00:00', '2012-07-21 19:00:00')
GO

我们有一堆间隔,我们想合并它们。我们需要找到这些合并间隔的开始和结束。合并的开始必须满足这些约束:

  1. 这是一些未合并的间隔的开始。
  2. 没有这样的间隔,在此时或之后结束,并且比此时间更早开始。
  3. 如果更多间隔同时开始,我们只需要一次。
  4. 合并结束是相似的。每个合并的开始都有一个合并的结尾。唯一的问题可能是未合并的间隔,其中start大于end。我决定跳过它们无效。代码在这里

    var ed = new DataClasses1DataContext();
    
    var res = ed.dateTables
        .Where(d => d.dt_from <= d.dt_to) //change to < for nonzero intervals only
        .Select(f => f.dt_from)
        .Distinct()
        .Where(w => !ed.dateTables.Any(a => a.dt_from < w && a.dt_to >= w))                
        .Select(date => new
        {
            FROM = date,
            TO = ed.dateTables.Select(t => t.dt_to)
            .Where(w => !ed.dateTables.Any(a => a.dt_from <= w && a.dt_to > w) && w >= date)
            .Min()
        }).ToArray();
    
    foreach (var r in res)
    {
        Console.WriteLine("FROM: " + r.FROM + " TO: " + r.TO);
    }
    

    结果在这里:

    FROM: 21.07.2012 2:00:00 TO: 21.07.2012 17:00:00 
    FROM: 21.07.2012 18:00:00 TO: 21.07.2012 19:00:00
    

    生成的SQL并不奇怪,只是有点混乱

    SELECT [t1].[dt_from] AS [FROM], (
        SELECT MIN([t3].[dt_to])
        FROM [dbo].[dateTable] AS [t3]
        WHERE (NOT (EXISTS(
            SELECT NULL AS [EMPTY]
            FROM [dbo].[dateTable] AS [t4]
            WHERE ([t4].[dt_from] <= [t3].[dt_to]) AND ([t4].[dt_to] > [t3].[dt_to])
            ))) AND ([t3].[dt_to] >= [t1].[dt_from])
        ) AS [TO]
    FROM (
        SELECT DISTINCT [t0].[dt_from]
        FROM [dbo].[dateTable] AS [t0]
        WHERE [t0].[dt_from] <= [t0].[dt_to]
        ) AS [t1]
    WHERE NOT (EXISTS(
        SELECT NULL AS [EMPTY]
        FROM [dbo].[dateTable] AS [t2]
        WHERE ([t2].[dt_from] < [t1].[dt_from]) AND ([t2].[dt_to] >= [t1].[dt_from])
        ))