【问题标题】:How to set an event duration limit to define "same event" and "new event" in Access 2010 query or SQL?如何设置事件持续时间限制以在 Access 2010 查询或 SQL 中定义“相同事件”和“新事件”?
【发布时间】:2013-05-19 21:31:17
【问题描述】:

我在 Access 2010 中使用带有日期时间戳的记录(来自相机陷阱的照片)表示特定动物(SpeciesID (0-10)、AnimalID (1-20) 对不同相机站点 (StationID) 的访问)。我想计算每个AnimalID对每个StationID的访问次数和时长。

问题在于,有时动物会在同一天多次访问同一个站点。我尝试过按日期对记录进行分组并显示日期时间字段的“第一个”和“最后一个”的查询,但这只是给出了当天每个车站该动物的第一个和最后一个记录的日期时间,而不是每次单独访问。

我想使用的标准是“如果同一动物、物种和站点的连续记录相隔 > 20 分钟,那么它们是单独的访问”。我想知道解决这个问题的方法是否是使用更新查询创建一个新字段,该字段使用此条件为每次访问提供一个唯一的“访问 ID”编号,因此我可以按访问 ID 对记录进行分组,以计算每个单独的第一个和最后一个日期时间访问?谁能建议一种方法来作为查询或在 SQL 中执行此操作,或者考虑另一种方法?

我的数据表(称为 Capture)的布局如下: 捕获ID |站号 |物种ID |动物ID |日期时间

CaptureID 是每条记录的唯一自动编号。 SpeciesID 可以是 1-10,AnimalID 可以是 1-20(但 AnimalID 只分配给 Species 1 的记录),StationID 可以是 1-12,cDateTime 可以是任何时间,因为相机陷阱是运动触发的,并且被格式化作为 DD/MM/YYYY hh:mm:ss。我希望将访问持续时间格式化为 hh:mm:ss。

非常感谢任何帮助或建议!

【问题讨论】:

  • 如果一只动物每十分钟访问一个小时,那是一个事件吗?
  • 另外 - 我们可以认为 AnimalId 表示个人吗?
  • 是的,因为它们可能仍在相机附近,但不在相机前面。
  • 是的,每只动物都有自己独特的 AnimalID
  • 因此我们可以忽略物种 ID 以进行分组。我还假设一组 5 人(比如一个家庭)是 5 次事件。

标签: sql datetime ms-access-2010 duration


【解决方案1】:

您可以为捕获表定义一个on insert trigger 和一个新字段“VisitStart”。

触发器将在伪代码中:

在 20 分钟内搜索具有捕获日期 + AnimalId 的任何记录 这次捕获。

如果存在,则使用其 VisitStart 字段填充新的 记录的 VisitStart。

如果不存在,则将新的 VisitStart 设置为 Capture Date。

我意识到这对您现有的数据没有帮助,但应该可以使用一次性过程来为系统进行泵注。

有什么好处吗?

【讨论】:

  • 这可能行得通,我想为 VisitEnd 写一个类似的触发器?
  • 虽然当我向 Capture 表添加新记录时,并未立即分配 animalID,这就是为什么查询会更好...
  • VisitEnd 可以计算 - Max(VisitDate) group by VisitStart。由于所需的顺序逻辑,查询将(几乎)不可能。当然,您可以创建一个预处理过程来进行这些计算,以便轻松构建查询
  • 如果不立即分配animalId,那么你有一个大问题
【解决方案2】:

这是我的解决方案。我的测试数据是

CaptureID  AnimalID  StationID  cDateTime            VisitStart           VisitEnd
---------  --------  ---------  -------------------  -------------------  -------------------
        1         1          1  2013-05-21 08:00:00                      
        2         2          1  2013-05-21 08:02:00                      
        3         1          1  2013-05-21 08:07:00                      
        4         2          1  2013-05-21 08:21:00                      
        5         1          1  2013-05-21 08:28:00                      

注意事项:

  1. 我省略了 SpeciesID,因为 AnimalID 是唯一标识符,因此 SpeciesID 确实属于 [Animals] 表以及有关该特定动物的其他详细信息。

  2. 所有 VisitStart 值最初都是 NULL。这对于以下查询之一很重要。

要填充 VisitStart,对于相同 AnimalID 和 StationID 的任何在 20 分钟内没有先前捕获的捕获,我们将只使用 cDateTime。

UPDATE Captures SET VisitStart = cDateTime
WHERE NOT EXISTS 
    (
        SELECT * FROM Captures c2 
        WHERE c2.AnimalID=Captures.AnimalID AND c2.StationID=Captures.StationID
            AND c2.cDateTime<Captures.cDateTime
            AND c2.cDateTime>=DateAdd("n", -20, Captures.cDateTime)
    )

这为我们提供了离散访问的开始时间:

CaptureID  AnimalID  StationID  cDateTime            VisitStart           VisitEnd
---------  --------  ---------  -------------------  -------------------  -------------------
        1         1          1  2013-05-21 08:00:00  2013-05-21 08:00:00          
        2         2          1  2013-05-21 08:02:00  2013-05-21 08:02:00          
        3         1          1  2013-05-21 08:07:00                               
        4         2          1  2013-05-21 08:21:00                               
        5         1          1  2013-05-21 08:28:00  2013-05-21 08:28:00          

现在我们可以通过查找该 AnimalID/StationID 的最大先前 VisitStart 来填充其余的 VisitStart 值

UPDATE Captures 
SET VisitStart = DMax("VisitStart", "Captures", "AnimalID=" & AnimalID & " AND StationID=" & StationID & " AND cDateTime<#" & Format(cDateTime, "yyyy-mm-dd Hh:Nn:Ss") & "#")
WHERE VisitStart IS NULL

这给了我们

CaptureID  AnimalID  StationID  cDateTime            VisitStart           VisitEnd
---------  --------  ---------  -------------------  -------------------  -------------------
        1         1          1  2013-05-21 08:00:00  2013-05-21 08:00:00          
        2         2          1  2013-05-21 08:02:00  2013-05-21 08:02:00          
        3         1          1  2013-05-21 08:07:00  2013-05-21 08:00:00          
        4         2          1  2013-05-21 08:21:00  2013-05-21 08:02:00          
        5         1          1  2013-05-21 08:28:00  2013-05-21 08:28:00          

类似的查询可以计算 VisitEnd 值

UPDATE Captures 
SET VisitEnd = DMax("cDateTime", "Captures", "AnimalID=" & AnimalID & " AND StationID=" & StationID & " AND VisitStart=#" & Format(VisitStart, "yyyy-mm-dd Hh:Nn:Ss") & "#")

结果是

CaptureID  AnimalID  StationID  cDateTime            VisitStart           VisitEnd           
---------  --------  ---------  -------------------  -------------------  -------------------
        1         1          1  2013-05-21 08:00:00  2013-05-21 08:00:00  2013-05-21 08:07:00
        2         2          1  2013-05-21 08:02:00  2013-05-21 08:02:00  2013-05-21 08:21:00
        3         1          1  2013-05-21 08:07:00  2013-05-21 08:00:00  2013-05-21 08:07:00
        4         2          1  2013-05-21 08:21:00  2013-05-21 08:02:00  2013-05-21 08:21:00
        5         1          1  2013-05-21 08:28:00  2013-05-21 08:28:00  2013-05-21 08:28:00

计算访问持续时间只需在 VisitStart 和 VisitEnd 上使用DateDiff()。请注意,上次访问的持续时间为零,因为它只有一次捕获。

【讨论】:

  • 您好,感谢您为我编写 SQL。在 VisitEnd 查询之前它工作得很好——它说由于转换类型错误,一些记录无法更新。知道为什么会这样吗?似乎唯一更新的记录是 VisitEnd 时间与 VisitStart 时间相同的记录...?
  • @user2416916 [cDateTime]、[VisitStart] 和 [VisitEnd] 是否都访问 Date/Time 列?
  • 很抱歉。我认为 dd/mm/yyyy 格式混淆了我的代码。 (我会学习......?)。我用Format() 调整了最后两个查询以适应它。您可能希望将 [VisitStart] 和 [VisitEnd] 设置回 NULL 并重新开始,以确保没有 2 月 4 日变成 4 月 2 日。 :(
  • 成功了!这些查询需要很长时间才能完成,因为我有很多记录,但我很高兴它起作用了。非常感谢您的帮助!
  • @GordThompson 嗨,我刚刚更新了我的问题 - 你能看一下吗?
猜你喜欢
  • 1970-01-01
  • 2013-12-05
  • 2013-10-02
  • 2013-08-20
  • 1970-01-01
  • 2010-10-20
  • 2023-04-04
  • 2018-01-29
  • 1970-01-01
相关资源
最近更新 更多