【问题标题】:Check if a table contains overlapping timespans检查表是否包含重叠的时间跨度
【发布时间】:2012-07-19 11:07:51
【问题描述】:

我有一个包含两列 FromDateToDate 的数据表,它们是字符串格式。 我想检查我的表中是否有任何重复的记录。即

From Date    To Date
----------------------      
9/01/2012    9/16/2012   
8/23/2012    8/24/2012   
8/25/2012    8/25/2012   
8/5/2012     8/6/2012    
8/26/2012    8/27/2012   
9/15/2012    9/23/2012

该表包含重复记录,因为它们的日期范围映射为

From Date       To Date      
----------------------      
9/01/2012    9/16/2012   
9/15/2012    9/23/2012

它应该返回 false。

【问题讨论】:

  • @Tisho:感谢您的编辑。
  • 您的意思是“完全相同的日期”还是“重叠的时间跨度”?
  • @Mare Infinitus :重叠跨度如上例所示
  • 请看我的回答。

标签: c# .net sql linq datatable


【解决方案1】:

使用DataTable.Search() 方法找出您的DataTable 中是否存在任何记录,这样您就可以在您的记录中强制执行唯一性。

类似的东西

string expression;
expression = "FromDate = #9/01/2012# AND ToDate = #9/16/2012#";
DataRow[] foundRows;

// Use the Select method to find all rows matching the filter.
foundRows = table.Select(expression);

if(foundRows.Length > 0)
     // Show duplicate message
else
    // Insert your new dates

了解更多Go here

【讨论】:

  • 我没有任何表达。记录已经在数据表中。我想检查现有记录是否有任何重复的范围值!!
【解决方案2】:

尝试解析“To Date”列,并为每个列在“From Date”列中搜索具有较晚对应“To Date”的任何较早日期。

【讨论】:

  • 一个嵌套循环(带过滤器的交叉连接)。好贵!
【解决方案3】:

ToDateFromDate 排序(或将排序后的索引数组构建到您的数据表中)。从行或数组位置 #2 循环到末尾,查看 FromDate

你也可以按FromDateToDate排序,做类似的逻辑。

【讨论】:

    【解决方案4】:
    var query = from row in dt.AsEnumerable()
                from row1 in dt.AsEnumerable()
                where
                (
    
                     (
                         DateTime.Parse(row1.Field<string>("fromDate")) >= DateTime.Parse(row.Field<string>("fromDate")) &&
                         DateTime.Parse(row1.Field<string>("fromDate")) <= DateTime.Parse(row.Field<string>("toDate"))
                     )
                     ||
                     (
                         DateTime.Parse(row1.Field<string>("toDate")) >= DateTime.Parse(row.Field<string>("fromDate")) &&
                         DateTime.Parse(row1.Field<string>("toDate")) <= DateTime.Parse(row.Field<string>("toDate"))
                     )
                )
                select new
                {
                    fromDate = DateTime.Parse(row1.Field<string>("fromDate")),
                    toDate = DateTime.Parse(row1.Field<string>("toDate"))
                };
    //This lst contains the dates which are overlapping    
    var lst = query.Distinct().ToList();
    

    【讨论】:

    • 不错,但如果数据表中的数据采用日期时间格式会更好,它将为每条记录 x 2 保存 DateTime.Parse。
    • @ Pravin:你运行查询了吗..bcz 当我运行它时..变量 lst 显示为 0,即使我有记录:第一个 FromDate:8/1/2012 第一个 ToDate: 2012 年 8 月 2 日第二次开始日期:2012 年 8 月 1 日第二次结束日期 2012 年 8 月 11 日
    • 没错,我也没有得到任何结果。
    • 我展示的示例只是比较 fromDate & 与
    【解决方案5】:

    那么,selfjoin 在这里会有所帮助:

    我有一个小班TimePeriod,只是为了满足你的需要

    public class TimePeriod
    {
        public int Id;
        public DateTime FromDate { get; set; }
    
        public DateTime ToDate { get; set; }
    
        public static DateTime Parse(string date)
        {
            var dt = DateTime.Parse(date, 
            CultureInfo.CreateSpecificCulture("en-US"), DateTimeStyles.RoundtripKind);
            return dt;
        }
    }
    

    然后我有一些测试数据

    var list = new List();

            list.Add(new TimePeriod() { Id = 1, FromDate = TimePeriod.Parse("9/01/2012"),  ToDate = TimePeriod.Parse("9/16/2012") });
            list.Add(new TimePeriod() { Id = 2, FromDate = TimePeriod.Parse("8/23/2012"), ToDate = TimePeriod.Parse("8/24/2012") });
            list.Add(new TimePeriod() { Id = 3, FromDate = TimePeriod.Parse("8/25/2012"), ToDate = TimePeriod.Parse("8/25/2012") });
            list.Add(new TimePeriod() { Id = 4, FromDate = TimePeriod.Parse("8/5/2012"), ToDate = TimePeriod.Parse("8/6/2012") });
            list.Add(new TimePeriod() { Id = 5, FromDate = TimePeriod.Parse("8/26/2012"), ToDate = TimePeriod.Parse("8/27/2012") });
            list.Add(new TimePeriod() { Id = 6, FromDate = TimePeriod.Parse("9/15/2012"), ToDate = TimePeriod.Parse("9/23/2012") });
    

    这是解决方案:(受到 OraNob 的启发,谢谢)

    var overlaps = from current in list
                from compare in list
                where
                (
                (compare.FromDate > current.FromDate &&
                compare.FromDate < current.ToDate) ||
                (compare.ToDate > current.FromDate &&
                compare.ToDate < current.ToDate)
                )
                select new
                {
                    Id1 = current.Id,
                    Id2 = compare.Id,
                };
    

    也许你想省略第二个 ID(因为你会有重复的 这里(1 / 6)和(6 / 1)

    【讨论】:

      【解决方案6】:

      如果您处理大型数据表,您应该使用@ErikE 响应。 这需要更多的代码行,但绝对是迄今为止最有效的。

      如果它的小表并且您更喜欢比较每两行。 您可以使用其他建议。 只需确保防止行与其自身进行比较,并在结果枚举中重复。

      var query = from x in list
                  where list.Exists((y) => x != y &&
                                           x.FromDate <= y.ToDate &&
                                           y.FromDate <= x.ToDate)
                  select x;
      

      【讨论】:

        【解决方案7】:
        strong textDeclare @Table Table  
        (  
            RowId Int Identity(1, 1) Not Null, 
              Id NChar(3) Not Null, 
              StartDate DATETIME Not Null, 
              EndDate DATETIME Not Null 
        );  
        
        Insert Into @Table (Id, StartDate, EndDate)  
        Select 'id1', '20131210 10:10', '20131220 10:10' Union All  
        Select 'id1', '20131211', '20131215' Union All  
        Select 'id1', '20131201', '20131205' Union All  
        Select 'id1', '20131206', '20131208' Union All  
        Select 'id1', '20131225 10:10', '20131225 10:11'
        Select *  
        From @Table;  
        
        
        With Overlaps (OverlapRowId, BaseRowId, OStart, OEnd, BStart, BEnd)  
        As  
        (  
                Select Overlap.RowId, Base.RowId, Overlap.StartDate, Overlap.EndDate, Base.StartDate, Base.EndDate 
                From @Table As Base  
                Inner Join @Table As Overlap On Overlap.Id = Base.Id  
                Where (((Overlap.StartDate > Base.StartDate) And (Overlap.StartDate < Base.EndDate))
                  Or ((Overlap.StartDate = Base.StartDate) And (Overlap.EndDate > Base.EndDate))) 
                  And (Base.RowId != Overlap.RowId) 
        ) 
        -- Remove records that were found to cause overlap issues.  
        Delete T  
        From @Table As T  
        Inner Join  
        (  
                Select O.OverlapRowId   
                From Overlaps As O 
                Left Join Overlaps As Fp On Fp.OverlapRowId = O.BaseRowId  
                Where (Fp.OverlapRowId Is Null) 
        ) As SubQuery On SubQuery.OverlapRowId = T.RowId;  
        
        -- Select the valid options.  
        Select RowId, Id, StartDate, EndDate  
        From @Table where StartDate<EndDate;  
        Go
        

        【讨论】:

        • 非常感谢,非常感谢您的帮助。我没有遇到过有多条记录具有相同开始和结束日期的情况。如果ID的数据发生变化,那将真的很有帮助。谢谢!!!
        猜你喜欢
        • 2014-01-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-06-30
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多