2009-10-01 39 views
9

说我有一个表“交易”,有列“acct_id”“trans_date”和“trans_type”,我想筛选此表,以便我只有最后一个交易为每个帐户。很明显,我可以做类似如何为每个帐户的上次交易进行SQL查询?

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服务器和甲骨文的工作通用的方法。

回答

17

这是一个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。所以这个外部连接解决方​​案通常被证明对性能更好。

8

这工作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 
) 
+1

这是我的最爱。你也可以让你的where子句为'NOT EXISTS(从事务z中选择NULL,其中a.acct_id = z.acct_id AND z.trans_date> a.trans_date)' – cjk 2010-03-02 10:10:53

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 
+0

固定错字..... – RedFilter 2009-10-01 18:19:13

+0

这就是我所固定的,离开在ON子句中输出trans_date。 – RedFilter 2009-10-01 18:22:53

1

试试这个

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 
相关问题