这是一个简化的交易表。
每一行都是一个具有唯一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分组的最新transac,包括该日期的金额。
我的工作完美,但我想知道的是,是否有一种更优雅的方式(就编程而言)或更有效的方法来处理这个问题,特别是我对子查询的处理量?想看看你会如何接近它。
我的方法:
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
答案 0 :(得分: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
答案 1 :(得分: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 Ponies使用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)
)
答案 2 :(得分:1)
另一种方法使用从SQL Server 2005开始提供的CROSS / OUTER APPLY运算符:
1)如果您只想显示包含交易的帐户,请使用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
。
答案 3 :(得分:-2)
这可以通过简单的查询
来完成select tans_id, amount from tablename
group by acc_ptr
having date =max(date)
结果是:
trans_id amount
3 -3
6 -2
2 3