【问题标题】:Group records into non-contiguous hour-long bins将记录分组到不连续的一小时箱中
【发布时间】:2012-12-16 19:10:08
【问题描述】:

我有表单的事件数据,其中 eventId 很长,时间是日期/时间(为简单起见,下面仅显示时间,因为所有时间都在同一天):

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

我需要组成包含一个小时的事件的组,其中小时是从该组的第一次开始计算的。使用上述数据,我的分组将是

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

我发现了很多在预定义时间段(例如每小时、每天、5 分钟)对数据进行分组的示例,但与我正在尝试做的事情完全不同。我怀疑使用直接 SQL 是不可能的……这似乎是一个先有鸡还是先有蛋的问题,我需要根据数据本身将数据放入 bin 中。

这个问题的基石是想出每个范围的开始时间,但我想不出除了琐碎的情况之外的任何东西:第一次开始时间。

我能想到的唯一方法是以编程方式(在 VBA 中)执行此操作,我将数据选择到临时表中,并在将行放入 bin 时删除它们。换句话说,找到最早的时间,然后在 1 小时内抓取该时间和所有记录,将它们从表中删除。获取剩余记录的最早时间并重复直到临时表为空。

理想情况下,我想要一个 SQL 解决方案,但我无法自己提出任何解决方案。

【问题讨论】:

  • 鉴于每个 bin 的开始和 bin 的数量都不是固定的,我认为您遇到了程序解决方案。递归 SQL 可能提供解决方案,但 AFAIK Jet SQL 不支持公用表表达式,也不支持它们的递归:-( 所以我认为 VBA 解决方案是正确的选择。
  • 抱歉含糊不清 - 为了清楚起见,我编辑了我的答案。理想情况下,我想要一个 SQL 解决方案。时间是日期/时间;我上面的表述只是一个简化。

标签: sql ms-access ms-access-2007


【解决方案1】:

关于可能的方法的一些说明。

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

【讨论】:

  • 你是个天才……太棒了!碰巧您的其他答案之一解决了我遇到的另一个问题...感谢您两次救助我!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-09-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-05
  • 1970-01-01
  • 2021-08-20
相关资源
最近更新 更多