-1

2 つの DateTime 列 (StartTime と EndTime) を持つテーブルと、重複する可能性のあるデータを含む行がある場合、結合された各開始/終了ブロックの単一のインスタンスを見つけるにはどうすればよいですか?

たとえば、次のようになります。

  • 2013 年 7 月 1 日 00:00:00、2013 年 7 月 1 日 12:00:00
  • 2013 年 7 月 1 日 06:00:00、2013 年 7 月 1 日 18:00:00

単一の結果 { 07/01/2013 00:00:00, 07/01/2013 18:00:00 } が必要です。作業は、SQL クエリで行うことも、上記のように DataTable を指定して C# で行うこともできます。

4

4 に答える 4

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
于 2013-09-13T13:33:09.380 に答える
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 は使用できません。おそらくもっと効率的な方法があります (たとえば、リストを前後に移動してシフトを最小限に抑えるなど) が、これは適切であり、また重要なことに、クリーンで簡潔でなければなりません。

于 2013-07-09T17:23:25.643 に答える
0

手始めに、ac# クラスを作成し、DateTime 操作を使用してオーバーラップを見つけます。オーバーラップ アルゴリズムに関しては、開始時刻と終了時刻を比較するだけです。

また、ここで行ったようです重複期間を検出するアルゴリズム

また http://www.codeproject.com/Articles/168662/Time-Period-Library-for-NET

于 2013-07-09T17:22:23.347 に答える
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
                 )

これは単純な相関サブクエリです。

于 2013-07-09T17:34:20.153 に答える