2011-08-31 111 views
3

這是一個簡化的交易表。聚合列的更優雅的方式

每一行是一個具有獨特TRANSAC ID的交易(標識字段如果你願意),一個accountpointer(外鍵在這裏沒有顯示的賬表),一個TRANSAC日期和金額。下面

的樣本數據:

trans_id acc_ptr trans_date amount 
1  12  2011-08-24 2.0 
2  12  2011-08-25 3.0 
3  14  2011-07-28 -3.0 
4  16  2011-06-14 -1.0 
5  12  2011-05-15 0.5 
6  16  2011-07-30 -2 

我要的是很簡單的。顯示按acc_ptr分組的最近一次交易,包括該日期的金額。

我的工作完美,但我想知道的是,有沒有更優雅的方式(就編程而言)或更有效的方式來處理這個問題,特別是我對子查詢的處理量?想看看你會如何接近它。

我的方法:

select acc_ptr 
, max(trans_date) as [most rec transac date] 
, (select amount from transactions t2 
where t2.trans_date = max(t1.trans_date) 
and t2.acc_ptr = t1.acc_ptr) as amount 
from transactions t1 
group by acc_ptr 

回答

3

想到的是使用分析(IE:ROW_NUMBER)的第一選擇,但是這是SQL Server的2005+功能。

WITH example AS (
    SELECT t.acc_ptr, 
     t.trans_date AS [most rec transac date], 
     t.amount, 
     ROW_NUMBER() OVER (PARTITION BY t.acc_ptr 
           ORDER BY t.trans_date DESC) AS rnk 
    FROM transactions t) 
SELECT e.acc_tpr, 
     e.trans_date, 
     e.amount 
    FROM example e 
WHERE e.rnk = 1 

有在本例中使用CTE(WITH語法)沒有表現值 - 這相當於:

SELECT e.acc_tpr, 
     e.trans_date, 
     e.amount 
    FROM (SELECT t.acc_ptr, 
       t.trans_date AS [most rec transac date], 
       t.amount, 
       ROW_NUMBER() OVER (PARTITION BY t.acc_ptr 
             ORDER BY t.trans_date DESC) AS rnk 
      FROM transactions t) e 
WHERE e.rnk = 1 
+0

很好的答案。我認爲你的看起來更精緻,總體上更容易理解。我使用的是2005年,所以CTE絕對是一種選擇。 – deutschZuid

+0

如果我希望將來包含更多依賴列(例如transac_description),它也更加靈活。 – deutschZuid

2

要注意,你的子查詢可在兩筆交易的情況下,無法在同一天:

DECLARE @transactions TABLE (
    trans_id INT, 
    acc_ptr INT, 
    trans_date datetime, 
    amount money 
) 

INSERT @transactions VALUES 
(1,12,'2011-08-24',2.0), 
(2,12,'2011-08-25',3.0), 
(3,14,'2011-07-28', -3.0), 
(4,16,'2011-06-14', -1.0), 
(5,12,'2011-05-15', 0.5), 
(6,16,'2011-07-30', -2), 
(7,16,'2011-07-30', -1) -- New transaction 

select acc_ptr, 
    max(trans_date) as [most rec transac date], 
(select amount 
    from @transactions t2 
    where t2.trans_date = max(t1.trans_date) 
    and t2.acc_ptr = t1.acc_ptr) as amount 
    from @transactions t1 
    group by acc_ptr 

Result: 

Msg 512, Level 16, State 1, Line 17 
Subquery returned more than 1 value. 
This is not permitted when the subquery follows =, !=, <, <= , >, >= 
or when the subquery is used as an expression. 

OMG小馬通過使用ROW_NUMBER解決了決勝局的問題。

另一個值得考慮的選擇:

SELECT 
    acc_ptr, 
    amount, 
    trans_date 
FROM transactions t1 
WHERE trans_id = 
    (SELECT 
    MAX(trans_id) 
    FROM transactions t2 
    WHERE acc_ptr = t1.acc_ptr 
    AND trans_date = 
    (SELECT 
     MAX(trans_date) 
     FROM transactions 
     WHERE acc_ptr = t2.acc_ptr) 
    ) 
+0

嗨8kb。感謝您的解決方案。你是絕對正確的。在實際的表中,日期字段是完整的,因爲它具有整個日期/時間範圍,直到毫秒,因此對於同一個帳戶,兩個事務在同一毫秒內發生的可能性極小。儘管如此,仍然有可能。 :)。 – deutschZuid

-2

這可以通過簡單的查詢來完成

select tans_id, amount from tablename 
group by acc_ptr 
having date =max(date) 

結果是:

trans_id amount 
3   -3 
6   -2 
2   3 
+0

沒有冒犯,但這個查詢甚至不會運行,因爲trans_id和金額不是按語句組的部分。其邏輯實際上毫無意義。查詢引擎如何知道爲每個account_pointer選擇哪個trans_id?對不起,但我必須標記你的伴侶。 – deutschZuid

+0

請嘗試運行此查詢..這當然有效..我已測試此查詢與上面的表結構相同,然後只發布它.. –

+0

注意..使用sybase 15 .. –

1

另一種方法使用CROSS/OUTER應用可用運營商從SQL Server 2005開始: 1)如果你只想顯示acco與交易UNTS然後用CROSS APPLY

SELECT a.account_id, b.trans_date, b.amount 
FROM Account a CROSS APPLY 
(
SELECT TOP(1) t.trans_date, t.amount 
FROM Transactionts t 
WHERE t.acc_ptr = a.account_id 
ORDER BY t.trans_date DESC, t.trans_id DESC 
) b 

看看這個例子(它顯示爲每一位客戶只有最後的順序)基於AdventureWorks數據庫:

SELECT c.CustomerID, c.AccountNumber 
     ,ca.OrderDate, ca.SubTotal 
FROM Sales.Customer c 
CROSS APPLY 
(
SELECT TOP(1) 
     soh.OrderDate, soh.SubTotal 
FROM Sales.SalesOrderHeader soh 
WHERE soh.CustomerID = c.CustomerID 
ORDER BY soh.OrderDate DESC, soh.SalesOrderID DESC 
) ca 

2)如果你想顯示所有賬戶使用OUTTER APPLY

+0

由於需要訪問兩個表,這種性能如何明智?但它完美的工作。沒有分組,也沒有排名。 – deutschZuid

+0

請使用'SET STATISTICS IO ON'(查看邏輯讀取)來比較不同方法的性能。在這種情況下,由於TOP(1),如果'Transactionts'上有適當的索引(例如:覆蓋索引:acc_ptr),那麼來自'Transactionts'表的邏輯讀取次數可能少於來自其他解決方案的邏輯讀取次數+ trans_date + trans_id或不覆蓋索引:acc_ptr)。非覆蓋索引(僅限acc_ptr字段)將需要額外的步驟(密鑰查找)來查找缺失值:trans_date。 –