如何为每个帐户的最后一笔交易进行SQL查询?

时间:2009-10-01 18:11:25

标签: sql greatest-n-per-group

假设我有一个表“事务”,其中包含“acct_id”“trans_date”和“trans_type”列,我想过滤此表,以便我只拥有每个帐户的最后一笔交易。显然,我可以做类似

的事情
SELECT acct_id, max(trans_date) as trans_date  
FROM transactions GROUP BY acct_id;

然后我失去了我的trans_type。然后,我可以使用我的日期列表和帐户ID进行第二次SQL调用,然后返回我的trans_type,但这感觉很麻烦,因为它意味着要么来回发送数据到sql server,要么就是创建一个临时表。

有没有办法使用单个查询执行此操作,希望是一个可以与mysql,postgres,sql-server和oracle一起使用的通用方法。

4 个答案:

答案 0 :(得分:22)

这是greatest-n-per-group查询的示例。这个问题每周在StackOverflow上出现几次。除了其他人提供的子查询解决方案之外,这是我的首选解决方案,它不使用子查询,GROUP BY或CTE:

SELECT t1.*
FROM transactions t1
LEFT OUTER JOIN transactions t2
  ON (t1.acct_id = t2.acct_id AND t1.trans_date < t2.trans_date)
WHERE t2.acct_id IS NULL;

换句话说,返回一行,使得不存在具有相同acct_id和更大trans_date的其他行。

此解决方案假定trans_date对于给定帐户是唯一的,否则可能会发生关联,并且查询将返回所有绑定的行。但对于其他人提供的所有解决方案也是如此。

我更喜欢这个解决方案,因为我经常使用MySQL,它不能很好地优化GROUP BY。因此,这种外连接解决方​​案通常证明性能更好。

答案 1 :(得分:11)

这适用于SQL Server ...

SELECT acct_id, trans_date, trans_type
FROM transactions a
WHERE trans_date = (
   SELECT MAX( trans_date )
   FROM transactions b
   WHERE a.acct_id = b.acct_id
)

答案 2 :(得分:2)

试试这个

WITH 
LastTransaction AS
(
    SELECT acct_id, max(trans_date) as trans_date  
    FROM transactions 
    GROUP BY acct_id
),
AllTransactions AS
(
    SELECT acct_id, trans_date, trans_type
    FROM transactions 
)
SELECT *
FROM AllTransactions
INNER JOIN AllTransactions 
    ON AllTransactions.acct_id = LastTransaction.acct_id
    AND AllTransactions.trans_date  = LastTransaction.trans_date

答案 3 :(得分:1)

select t.acct_id, t.trans_type, tm.trans_date
from transactions t
inner join (
    SELECT acct_id, max(trans_date) as trans_date  
    FROM transactions 
    GROUP BY acct_id;
) tm on t.acct_id = tm.acct_id and t.trans_date = tm.trans_date