I have table of user actions, each having a user associated, a type, and a timestamp. Here’s a simplified example:
TABLE USER_ACTIONS
------------------------
USER | TYPE | TIMESTAMP
------------------------
a | OPEN | 0
b | OPEN | 1
a | CLOSE | 2
a | OPEN | 3
b | CLOSE | 4
a | CLOSE | 4
a | OPEN | 5 <-- "orphaned" OPEN, with no corresponding CLOSE. Should be ignored.
c | OPEN | 3
c | CLOSE | 5
a | OPEN | 6
a | CLOSE | 8
I’d like to get a list of transaction times out of this. Each CLOSE should match the previous OPEN, for a particular user.
The results I’d like will look something like this:
USER | TRANSACTION_TIME
-----------------------
a | 2
b | 3
a | 1
c | 2
a | 2
I don’t care about the ordering.
I know that this is possible to do programmatically, but is it possible to do with some clever SQL?
UPDATE:
To do this programmatically, the general idea would be to…
- Select all of the “CLOSE” actions, ordering by TIMESTAMP descending.
- For each of those in that list, try to find a previous “OPEN” action made by the same user. Limit the TIMESTAMP to be before the “CLOSE” action TIMESTAMP, sort the results by TIMESTAMP DESC, and limit them to 1.
- For that pair, calculate the time difference, and ouput the result.
Here’s some pseudocode, but really I’d like SQL that does this cleverly:
for each CLOSE_ACTION IN ("SELECT USER, TYPE, TIMESTAMP FROM USER_ACTIONS WHERE TYPE='CLOSE' ORDER BY TIMESTAMP DESC;") {
OPEN_ACTION = "SELECT USER, TYPE, TIMESTAMP FROM USER_ACTIONS
WHERE TYPE='OPEN'
AND USER='<CLOSE_ACTION.USER>'
AND TIMESTAMP='<CLOSE_ACTION.TIMESTAMP>'
ORDER BY TIMESTAMP DESC
LIMIT 1";
if OPEN_ACTION != empty/null then {
print CLOSE_ACTION.USER, CLOSE_ACTION.TIMESTAMP - OPEN_ACTION.TIMESTAMP;
}
}
This takes each CLOSE event and matches it to the preceding event, if and only if the preceding event is an OPEN.