Ignoring the OPs need for no aggregate functions (still not sure why...)
The issue I have with the given answer is :
- It's not dynamic to allow for any other user - say 'mark'
- it assumes that the max(id) for an action will match the latest action - the test data suggests that, but I wouldn't assume that as a rule.
so with those in mind a more dynamic query needs to be built
with 2 more rows added to the test data
7, john, update, 04/01/09
8, mark, insert, 01/02/09
the answer doesn't give what the OP wanted
Here's my first draft quickly - will tidy later
select
userActions.id,
userActions.[user],
userActions.Action,
userActions.insertDate
from
userActions
join
(
select
[user], action, max(insertdate) as maxinsertdate
from userActions
group by
[user], action
) aggsubquery
on userActions.[user] = aggsubquery.[user]
and userActions.action = aggsubquery.action
and userActions.insertdate = aggsubquery.maxinsertdate
Update....
2nd version uses the ID to get a distinct row where there may be more than one occurance of an action by a particular user, i.e. if the test data also had the following row
9, john, delete, 06/01/09
then you would need to decide between row id 6 and row id 9 as to which one to return. I arbitrarily chose to use max(id), as I guess the data is important and not the row id
select
max(userActions.id) as id,
userActions.[user],
userActions.Action,
userActions.insertDate
from
userActions
join
(
select
[user], action, max(insertdate) as maxinsertdate
from userActions
group by
[user], action
) aggsubquery
on userActions.[user] = aggsubquery.[user]
and userActions.action = aggsubquery.action
and userActions.insertdate = aggsubquery.maxinsertdate
group by
userActions.[user],
userActions.Action,
userActions.insertDate