2009-10-01 40 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 
相關問題