3

次の形式のイベントデータがあります。eventIdは長く、時刻はDate / Timeです(すべての時刻が同じ日になるため、わかりやすくするために以下に示します)。

eventId    time
---------------
   1       0712
   2       0715
   3       0801
   4       0817
   5       0916
   6       1214
   7       2255

1時間分のイベントを含むグループを形成する必要があります。ここで、時間はそのグループの最初の時間から測定されます。上記のデータを使用すると、私のグループ化は次のようになります

Group 1 (0712 to 0811 inclusive): events 1, 2, 3
Group 2 (0817 to 0916 inclusive): events 4, 5
Group 3 (1214 to 1313 inclusive): event 6
Group 4 (2255 to 2354 inclusive): event 7

事前定義された期間(たとえば、1時間ごと、1日ごと、5分ごと)でデータをグループ化する例をたくさん見つけましたが、私がやろうとしていることとはまったく異なります。ストレートSQLを使用することは不可能だと思います...データ自体に基づいてデータをビンに入れる必要がある鶏が先か卵が先かという問題のようです。

この問題の要は、各範囲の開始時刻を考え出すことですが、些細なケース、つまり最初の開始時刻以外のことは思いつきません。

私が思いつく唯一の方法は、これをプログラムで(VBAで)行うことです。ここでは、データを一時テーブルに選択し、行をビンに入れるときに行を削除します。つまり、最も早い時間を見つけて、それから1時間以内にすべてのレコードを取得し、テーブルから削除します。残りのレコードの最も早い時刻を取得し、一時テーブルが空になるまで繰り返します。

理想的にはSQLソリューションが欲しいのですが、自分で何かに近いものを思いつくことはできません。

4

1 に答える 1

2

可能なアプローチに関するいくつかのメモ。

Dim rs As DAO.Recordset
Dim db As Database
Dim rsBins As DAO.Recordset
Dim qdf As QueryDef 'Demo

Set db = CurrentDb

'For demonstration, if the code is to be run frequently
'just empty the bins table
db.Execute "DROP TABLE Bins"
db.Execute "CREATE TABLE Bins (ID Counter, Bin1 Datetime, Bin2 Datetime)"

'Get min start times
db.Execute "INSERT INTO bins ( Bin1, Bin2 ) " _
   & "SELECT Min([time]) AS Bin1, DateAdd('n',59,Min([time])) AS Bin2 " _
   & "FROM events"

Set rsBins = db.OpenRecordset("Bins")

Do While True
    Set rs = db.OpenRecordset("SELECT Min([time]) AS Bin1, " _
    & "DateAdd('n',59,Min([time])) AS Bin2 FROM events " _
    & "WHERE [time] > (SELECT Max(Bin2) FROM Bins)")

    If IsNull(rs!Bin1) Then
        Exit Do
    Else
        rsBins.AddNew
        rsBins!Bin1 = rs!Bin1
        rsBins!bin2 = rs!bin2
        rsBins.Update
    End If
Loop

''Demonstration of final query.
''This will only run once and then error becaue the query exists, but that is
''all you need after that, just open the now existing binned query

sSQL = "SELECT events.Time, bins.ID, bins.Bin1, bins.Bin2 " _
     & "FROM events, bins " _
     & "GROUP BY events.Time, bins.ID, bins.Bin1, bins.Bin2 " _
     & "HAVING (((events.Time) Between [bin1] And [bin2]));"

Set qdf = db.CreateQueryDef("Binned", sSQL)
DoCmd.OpenQuery qdf.Name
于 2012-12-16T20:31:55.250 に答える