web-dev-qa-db-ja.com

ほとんどの重複するイベントのSQLアルゴリズム

問題

次の問題を解決するのに役立つクエリを探しています。

  • 一連のイベントがあります
  • 各イベントには開始日と終了日があります。
  • これらのイベントの多くは重複しています
  • 私が探している答えは、重複するイベントの最大数です

5つのイベントがあるとします。

  • 1月1日-> 1月9日
  • 1月7日-> 1月12日
  • 1月8日-> 1月10日
  • 1月10日-> 1月15日
  • 1月12日-> 1月17日

これらのイベントのうち3つは1月9日と重複します。これは最大の重複イベントであるため、答えは3です。

(1月10日に3つのイベントが重複していますが、同じ答えです)

私が試したこと

メモリでこれを行っていた場合、これを行うことができます:

  • 各イベント:
    • 開始日を取得
    • このイベントを含む日付を数える
  • カウントが最も高いイベントを選択します。

しかし、これには2つの問題があります。

  • それは非常に効率的ではないようです
  • あまりSQL-yではありません(つまり、セットベースではなく手続き型です)

質問

このようなものをSQLに実装するにはどうすればよいですか?

ノート

  • 最も重複しているイベントの開始日/終了日を見つける必要はありません。カウントが必要です
  • 最大値が発生する頻度は気にせず、最大値が必要です。したがって、上記の例では、3つのイベントが重複する2つの状況があることを知っていますが、必要なのは「3」だけです。
  • イベントAがイベントBの開始と同じ日に終了した場合、それらは重複していると見なされます
3
Kramii

これをSQLではなくコードで記述する方がパフォーマンスが向上する可能性があります。

コードでは、アイテムを開始日、次に終了日で並べ替えます。それらを確認し、次の項目と重複していないか確認してください。重複している場合は、オーバーラップカウンターをインクリメントして繰り返します。次のアイテムがアイテムと重複していることを確認します。表示されない場合は、次に進みます。

SQLでは、自己結合を使用してすべての重複を一覧表示できます。

これにより、すべての重複が表示されます。

select a.eventid from events a
inner join events b 
on a.end > b.start and a.start < b.end

次に、それらをeventidでグループ化し、カウントを選択して、最大カウントのイベントを取得できます。

select top 1 eventid, count(*) as c
from 
    (select a.eventid from events a
    inner join events b 
    on a.end > b.start and a.start < b.end)
group by eventid
order by c desc
2
Carra

リレーショナルデータベースのもう1つの戦略は、各暦日のレコードを含むテーブルを作成することです。これは、システムに存在しない日を特定しようとしている状況で役立ちます。計算によってデータを作成するためにデータベースに依存する代わりに、そこにあるデータを操作するほうが簡単です。

そのテーブルとイベントのテーブルを使用して、それらを結合し、いくつかの単純な集計を実行できます(SQL Server)。

create table Datelist (
HistoryDate datetime not null
)
insert into DateList (HistoryDate)
values 
( '1/1/2018')   
, ('1/2/2018')
...

create table event (
StartDate datetime not null
, EndDate datetime not null
)

insert into event (StartDate, EndDate)
values ('01/01/2018', '01/09/2018')
, ('01/07/2018', '01/12/2018')
, ('01/08/2018', '01/10/2018')
, ('01/10/2018', '01/15/2018')
, ('01/12/2018', '01/17/2018')

select max(c.EventCount) as maxEvents
from (
select d.HistoryDate
    , count(d.HistoryDate) as EventCount
from DateList as d
inner join event as e
on d.HistoryDate between e.StartDate and e.EndDate
group by d.HistoryDate
) as c

クエリを読むのはそれほど難しくありませんが、事前設定された「DateList」テーブルの内容を理解する必要があります。サブクエリを実行して、テスト目的で各日付の実際のリストを確認できます。

0
JeffO