1

次のクエリを SQL で記述しようとしています:イベントには開始日/終了日/時刻があります。ユーザーは特定の時間に利用できます。ユーザーが特定のイベントに参加できる合計時間を確認するにはどうすればよいですか?

例:

--Event--
eventID eventStart          eventEnd
1       2012-10-10 15:00    2012-10-10 18:00

--Available--
userID  availStart          availEnd
64      2012-10-10 10:00    2012-10-10 16:00
64      2012-10-10 16:30    2012-10-10 16:40
64      2012-10-10 16:55    2012-10-10 22:00

ユーザーは 135 分間無料です (15:00 ~ 16:00 の 60 分、16:30 ~ 16:40 の 10 分、16:55 ~ 18:00 の 65 分)。

SQL を書くためのいくつかのヘルプは本当に役に立ちます。これはトリッキーだと思います!

4

1 に答える 1

1

今それをテストしました:http://sqlfiddle.com/#!3/a4e7a/2

ユーザーテーブルを想定しています。パフォーマンス改善の余地はたくさんあります。たとえば、重複しない範囲を除外する where 句を追加します。関数を恐ろしい case ステートメントに置き換えると、おそらく高速になります。

難しいのは、2 つのタイムスパンがどの程度重なるかのアルゴリズムを理解することです。ケースの絵を描くことはいつも役に立ちます。

Case 1
|------|
         |=======|

Case 2
|------|
     |======|

Case 3
|-------|
  |===|

および順序を逆にした同等のもの。

オーバーラップは、2 つの終了時間の最小値から 2 つの開始時間の最大値を引いたものであることがわかります。(負の場合、重複はありません)。私は常にすべてのケースをチェックして、これを再確認する必要があります.

-- Function that determines how many minutes of overlap there are between two timespans
Create Function dbo.MinutesOverlap(
  @Start1 as datetime, @End1 as datetime, @Start2 as datetime, @End2 as datetime
) Returns int As
Begin
  Declare 
    @MaxStart As datetime,
    @MinEnd As datetime,
    @Ret int = 0

  Set @MaxStart = Case When @Start1 > @Start2 Then @Start1 Else @Start2 End
  Set @MinEnd = Case When @End1 > @End2 Then @End2 Else @End1 End

  If @MaxStart < @MinEnd
    Set @Ret = DateDiff(Minute, @MaxStart, @MinEnd)

  Return @Ret
End


Select
  u.UserID,
  e.EventID,
  Sum(dbo.MinutesOverlap(e.eventStart, e.eventEnd, a.availStart, a.availEnd))
From
  Event e
    Cross Join
  User u
    Left Outer Join
  Available a
    On u.UserID = a.UserID
Group By
  u.UserID, 
  e.EventID
于 2012-11-17T02:20:15.867 に答える