16

假设我有一个表“事务”,其中包含“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 服务器,要么意味着创建一个临时表。

有没有办法通过单个查询来做到这一点,希望是一种适用于 mysql、postgres、sql-server 和 oracle 的通用方法。

4

4 回答 4

32

这是每组最大 n 个查询的示例。这个问题每周在 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不是很好。因此,这种外连接解决方​​案通常被证明对性能更好。

于 2009-10-01T18:19:44.663 回答
13

这适用于 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
)
于 2009-10-01T18:15:04.633 回答
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 LastTransaction
    ON AllTransactions.acct_id = LastTransaction.acct_id
    AND AllTransactions.trans_date  = LastTransaction.trans_date
于 2009-10-01T18:17:05.323 回答
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
于 2009-10-01T18:15:46.527 回答