Reputation: 1058
Here is a simplified transactions table.
Each row is a transaction that has a unique transac id (identity field if you will), an accountpointer (foreign key to the accounts table which is not displayed here), a transac date and a dollar amount.
Sample data below:
trans_id acc_ptr trans_date amount
1 12 2011-08-24 2.0
2 12 2011-08-25 3.0
3 14 2011-07-28 -3.0
4 16 2011-06-14 -1.0
5 12 2011-05-15 0.5
6 16 2011-07-30 -2
What I want is very simple. Display the most recent transac grouped by acc_ptr including the amount for that date.
What I have works perfectly, but what I would like to know is, is there a more elegant way (as far as programming goes) or more efficient way of dealing with this problem, specifically my treatment of the subquery for amount? Would like to see how you would approach it.
My approach:
select acc_ptr
, max(trans_date) as [most rec transac date]
, (select amount from transactions t2
where t2.trans_date = max(t1.trans_date)
and t2.acc_ptr = t1.acc_ptr) as amount
from transactions t1
group by acc_ptr
Upvotes: 3
Views: 180
Reputation: 204
This can be done by simple query
select tans_id, amount from tablename
group by acc_ptr
having date =max(date)
result is :
trans_id amount
3 -3
6 -2
2 3
Upvotes: -2
Reputation: 11406
To note, your subquery could fail in the case of two transactions on the same day:
DECLARE @transactions TABLE (
trans_id INT,
acc_ptr INT,
trans_date datetime,
amount money
)
INSERT @transactions VALUES
(1,12,'2011-08-24',2.0),
(2,12,'2011-08-25',3.0),
(3,14,'2011-07-28', -3.0),
(4,16,'2011-06-14', -1.0),
(5,12,'2011-05-15', 0.5),
(6,16,'2011-07-30', -2),
(7,16,'2011-07-30', -1) -- New transaction
select acc_ptr,
max(trans_date) as [most rec transac date],
(select amount
from @transactions t2
where t2.trans_date = max(t1.trans_date)
and t2.acc_ptr = t1.acc_ptr) as amount
from @transactions t1
group by acc_ptr
Result:
Msg 512, Level 16, State 1, Line 17
Subquery returned more than 1 value.
This is not permitted when the subquery follows =, !=, <, <= , >, >=
or when the subquery is used as an expression.
OMG Ponies solves the issue of the tie breaker by using ROW_NUMBER.
Another option to consider:
SELECT
acc_ptr,
amount,
trans_date
FROM transactions t1
WHERE trans_id =
(SELECT
MAX(trans_id)
FROM transactions t2
WHERE acc_ptr = t1.acc_ptr
AND trans_date =
(SELECT
MAX(trans_date)
FROM transactions
WHERE acc_ptr = t2.acc_ptr)
)
Upvotes: 2
Reputation: 332581
The first alternative that comes to mind is to use analytics (IE: ROW_NUMBER), but that's SQL Server 2005+ functionality.
WITH example AS (
SELECT t.acc_ptr,
t.trans_date AS [most rec transac date],
t.amount,
ROW_NUMBER() OVER (PARTITION BY t.acc_ptr
ORDER BY t.trans_date DESC) AS rnk
FROM transactions t)
SELECT e.acc_tpr,
e.trans_date,
e.amount
FROM example e
WHERE e.rnk = 1
There's no performance value in this example to using a CTE (WITH
syntax) - this is equivalent:
SELECT e.acc_tpr,
e.trans_date,
e.amount
FROM (SELECT t.acc_ptr,
t.trans_date AS [most rec transac date],
t.amount,
ROW_NUMBER() OVER (PARTITION BY t.acc_ptr
ORDER BY t.trans_date DESC) AS rnk
FROM transactions t) e
WHERE e.rnk = 1
Upvotes: 3