How to set an event duration limit to define "same event" and "new event" in Access 2010 query or SQL?

StackOverflow https://stackoverflow.com/questions/16732288

質問

I am working in Access 2010 with datetime-stamped records (photographs from camera-traps) that signify visits by specific animals (SpeciesID (0-10), AnimalID (1-20) to different camera sites (StationID). I want to calculate the number and duration of visits by each AnimalID to each StationID.

The problem is that sometimes animals visit the same station multiple times in the same day. I have tried queries that group the records by date and show the 'First of' and 'Last of' the datetime field, but this just gives the datetime of the first and last records of that animal at each station on that day, not of each individual visit.

The criteria I want to use is 'if consecutive records of the same animal, species and station are >20 minutes apart, then they are separate visits'. I wonder whether a way to solve this is to create a new field with an update query that gives each visit a unique 'VisitID' number using this criteria, so I can then group records by VisitID to calculate the First and Last datetime for each separate visit? Can anyone suggest a way to do this as a query or in SQL, or think of another way of doing this??

My data table (called Capture) is laid out like this: CaptureID | StationID | SpeciesID | AnimalID | cDateTime

CaptureID is a unique Autonumber for every record. SpeciesID can be 1-10, AnimalID can be 1-20 (but AnimalIDs are only assigned to records of Species 1), StationID can be 1-12, cDateTime can be any time as the camera traps are motion-triggered, and is formatted as DD/MM/YYYY hh:mm:ss. I want the visit duration to be formatted as hh:mm:ss.

Any help or advice much appreciated!!

役に立ちましたか?

解決

Here is my solution. My test data is

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                      

Notes:

  1. I have omitted SpeciesID since AnimalID is the unique identifier, so SpeciesID really belongs in the [Animals] table with the other details about that particular animal.

  2. All VisitStart values are initially NULL. That is important for one of the queries below.

To populate VisitStart, we'll just use the cDateTime for any capture that does not have a previous capture within 20 minutes for the same AnimalID and StationID.

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)
    )

That gives us the start times for the discrete visits:

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          

Now we can fill in the rest of the VisitStart values by finding the largest previous VisitStart for that AnimalID/StationID

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

That gives us

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          

A similar query can calculate the VisitEnd values

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

The result is

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

Calculating the visit duration is simply a matter of using DateDiff() on VisitStart and VisitEnd. Note that the last visit will have a duration of zero since there was only one capture for it.

他のヒント

You could define an on insert trigger for the capture table and a new field 'VisitStart'.

The trigger would, in pseudocode:

Search for any record with a capture date + AnimalId within 20 mins of this capture.

If one exists then take its VisitStart field to populate the new record's VisitStart.

If none exists then set new VisitStart to Capture Date.

I realise this does not help you with your existing data but a one-off process to pump-prime the system should be possible.

Any good ?

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top