Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/ms-access/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 将记录分组到非连续的一小时长的存储箱中_Sql_Ms Access_Ms Access 2007 - Fatal编程技术网

Sql 将记录分组到非连续的一小时长的存储箱中

Sql 将记录分组到非连续的一小时长的存储箱中,sql,ms-access,ms-access-2007,Sql,Ms Access,Ms Access 2007,我有以下形式的事件数据,其中eventId是一个long,time是Date/time(为了简单起见,下面显示的时间,因为所有时间都在同一天): 我需要组成包含一小时事件的小组,时间从小组第一次开始计算。使用上述数据,我的分组将是 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

我有以下形式的事件数据,其中eventId是一个long,time是Date/time(为了简单起见,下面显示的时间,因为所有时间都在同一天):

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

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是不可能的……这似乎是一个鸡和蛋的问题,我需要根据数据本身将数据放入垃圾箱

这个问题的基础是给出每个范围的开始时间,但除了第一个开始时间这个琐碎的例子之外,我无法给出任何东西

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


理想情况下,我希望有一个SQL解决方案,但我自己无法提出任何接近的解决方案。

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

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

考虑到每个箱子的起始位置和箱子的数量都不是固定的,我认为您需要一个程序解决方案。递归SQL可以提供一种解决方案,但AFAIK Jet SQL不支持公共表表达式,也不支持对它们进行递归:-(因此,我认为你是正确的,VBA解决方案才是正确的方向。对于模棱两可的问题,我很抱歉-为了清晰起见,我编辑了我的答案。理想情况下,我想要一个SQL解决方案。时间是日期/时间;我上面的表示只是一个简化。你是一个天才……太棒了!碰巧你的另一个答案解决了我遇到的另一个问题g、 谢谢你两次救我出来!
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