Reputation: 33
Sorry if the title is not really understandable, I've trouble even expressing it!
To simplify, I have two tables in a SQL Server 2012 database: one with requests and one with actions related to these requests (it's from a service manager software)
Table REQUESTS Table ACTIONS
+------+-------+---+ +---------+------+--------+
|Req_ID|RFC_Num|...| |Action_ID|Req_ID|Group_ID|
+------+-------+---+ +---------+------+--------+
| 1 | I01 |...| | a | 1 | 10 |
| 2 | I02 |...| | b | 1 | 20 |
| 3 | I03 |...| | c | 1 | 38 |
| 4 | I04 |...| | d | 1 | 38 |
+------+-------+---+ | e | 2 | 10 |
| f | 2 | 38 |
| g | 2 | 20 |
| h | 3 | 38 |
| i | 4 | 10 |
+---------+------+--------+
I want to be able to select all requests where the last action for that request has group_id = 38, so it should return requests with req_id is 1 and 3, but not req2 as the last action is made by another group than 38 nor req4 as group 38 is not involved.
I've tried things like
select *
from REQUEST r
inner join ACTION a
on (
(r.REQUEST_ID = a.REQUEST_ID)
and (select group_id
from ACTION a2
where a2.action_id = a.action_id
).GROUP_ID = 38
)
but I can't figure out how to put the "max(action_id)" (or select top 1 with an order by desc) and I don't really understand how to use things like having.
I've also tried requests like this one:
select *
from REQUEST r
inner join ACTION a
on (
(r.REQUEST_ID = a.REQUEST_ID)
and (select top 1 a2.action_id, a2.group_id
from ACTION a2
where a2.action_id = a.action_id
group by a2.ACTION_ID
order by a2.action_id desc
).GROUP_ID = 38
)
But I get these two errors:
Msg 8120, Level 16, State 1, Line 6
Column ACTION.GROUP_ID is not valid in the selection list because it's not contained in an aggregation function or in the GROUP BY clause.Msg 116, Level 16, State 1, Line 11
Only one expression can be specified in the selection list when the subquery is not introduced by EXISTS.
Thank you for you help!
Upvotes: 3
Views: 76
Reputation: 1270773
I would be inclined to use apply
:
select r.*, a.*
from request r cross apply
(select top 1 a.*
from action a
where a.request_id = a.request_id
order by a.action_id desc
)
where a.group_id = 38;
This assumes that "last action" is based on the action_id
column. Whatever the definition is is what the order by
uses.
Upvotes: 0
Reputation: 7385
Your query looks longer than it needs to be. Try this:
SELECT *
FROM requests r
WHERE (
SELECT TOP 1 Group_ID
FROM actions
WHERE Req_ID = r.Req_ID
ORDER BY Action_ID DESC
) = 38
Upvotes: 2
Reputation: 37487
You could join the tables, only keeping records WHERE Group_ID = 38
and no other action for this request exists with a greater Action_ID
.
SELECT r.*
FROM REQUESTS r
INNER JOIN ACTIONS a
ON a.Req_ID = r.Req_ID
WHERE a.Group_ID = 38
AND NOT EXISTS (SELECT *
FROM ACTIONS ai
WHERE ai.Req_ID = a.Req_ID
AND ai.Action_ID > a.Action_ID);
Upvotes: 0
Reputation: 9806
Your join column is wrong, you are using:
(r.REQUEST_ID = a.ACTION_ID)
but should be:
(r.REQUEST_ID = a.REQUEST_ID)
Upvotes: 0