假设我有一个表“事务”,其中包含“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一起使用的通用方法。
答案 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