给定一个包含两个DateTime列(StartTime和EndTime)的表,以及包含可能重叠的数据的行,如何找到每个组合的开始/结束块的单个实例?
例如,给定:
我需要一个结果{07/01/2013 00:00:00,07 / 01/2013 18:00:00}。这项工作可以在SQL查询中完成,也可以在给定DataTable的C#中完成,如上所述。
答案 0 :(得分:1)
我能想到的最简单的方法是在您感兴趣的时间范围内啜饮所有记录,然后根据众所周知的重叠日期公式“合并”记录:
List<Tuple<DateTime, DateTime>> dateRows = GetDateRowsSomehow();
//sorting by start time; you can do this in SQL pretty easily
//necessary to make sure the row most likely to overlap a given row is the next one
dateRows.Sort((a,b) => a.Item1.CompareTo(b.Item1));
for(var i=0; i<dateRows.Count - 1; i++)
for(var j=i+1, j<dateRows.Count; j++)
if(dateRows[i].Item1 <= dateRows[j].Item2
&& dateRows[i].Item2 >= dateRows[j].Item1) //overlap
{
//keep date row i, with the values of the complete time range of i and j
dateRows[i].Item1 = dateRows[i].Item1 < dateRows[j].Item1
? dateRows[i].Item1
: dateRows[j].Item1;
dateRows[i].Item2 = dateRows[i].Item2 > dateRows[j].Item2
? dateRows[i].Item2
: dateRows[j].Item2;
//remove row j and ensure we don't skip the row after it
dateRows.RemoveAt(j);
j--;
}
此解决方案的WCS是一个零重叠的大结果集,它将按N(N-1)/ 2 = O (N 2 )的顺序执行。最好的情况是线性的(不计算NlogN排序操作或列表中的重复线性移位),当所讨论的所有行彼此重叠时。你不能使用foreach,因为我们正在改变集合的大小。可能有一种更有效的方式(例如,从前到后遍历列表,最小化移位),但这应该是体面的,而且重要的是,干净简洁。
答案 1 :(得分:1)
您可以使用Time Period Library for .NET计算不重叠的时间跨度:
// ----------------------------------------------------------------------
public void TimeSpansWithoutOverlap()
{
// periods
ITimePeriodCollection periods = new TimePeriodCollection();
periods.Add( new TimeRange(
new DateTime( 2013, 7, 1, 0, 0, 0 ),
new DateTime( 2013, 7, 1, 12, 0, 0 ) ) );
periods.Add( new TimeRange(
new DateTime( 2013, 7, 1, 6, 0, 0 ),
new DateTime( 2013, 7, 1, 18, 0, 0 ) ) );
ITimePeriodCollection combinedPeriods = new TimePeriodCombiner<TimeRange>().CombinePeriods( periods );
foreach ( ITimePeriod combinedPeriod in combinedPeriods )
{
Console.WriteLine( "Period: " + combinedPeriod );
}
} // TimeSpansWithoutOverlap
答案 2 :(得分:0)
作为初学者,我会创建一个c#类并使用DateTime操作来查找重叠。至于重叠算法,只需区分开始和结束时间。
似乎也在这里完成Algorithm to detect overlapping periods
另外 http://www.codeproject.com/Articles/168662/Time-Period-Library-for-NET
答案 3 :(得分:0)
这样的事应该对你有用:
select *
from myTable t
where not exists ( select *
from myTable overlap
where overlap.partial_key = t.partial_key
and overlap.dateTimeFrom <= t.dateTimeThru
and overlap.dateTimeThru >= t.dateTimeFrom
)
这是一个简单的相关子查询。