我想在特定日期之前找到每个帐户的最后一笔交易

I want to find the last transaction for each account prior to a certain date

我有一个 table 定义(在 Azure SQL 服务器上)如下:

CREATE TABLE dbo.[transaction] 
(
    id INT IDENTITY(1,1) NOT NULL,
    [date] DATETIME NULL,
    amount FLOAT NULL,
    balance FLOAT NULL,
    account_id INT NULL,
    CONSTRAINT PK__transact__32F PRIMARY KEY (id)
)

我想查找每个帐户在特定日期之前的最后余额。我需要 returned 的列是:account_id、日期、余额。

我试过:

select account_id, max(date) as date 
from dbo.[transaction] 
group by account_id

这有效,但它不会 return 余额。

其次,我的交易首先按日期排序,然后按 ID 排序。所以如果最大日期发生多笔交易,它应该选择具有最高id的交易上的余额。

我的应用程序是用 flask-sqlalchemy 编写的,所以 sqlalchemy 的答案会很好,但我也很高兴 SQL 中的答案。

您可以使用 row_number windows 函数为每个帐户 ID 的行编号,并为每个帐户取最后一行:

SELECT account_id, [date], balance
FROM   (SELECT account_id, [date], balance,
               ROW_NUMBER() OVER (PARTITION BY account_id
                                  ORDER BY [date] DESC, id DESC) AS rn
        FROM   [transaction]) t
WHERE  rn = 1

解决方案:包括您的日期检查

CREATE TABLE #transaction (
    id int NOT NULL,
    [date] datetime NULL,
    amount float NULL,
    balance float NULL,
    account_id int NULL
) ;

Insert Into #transaction Values
(1,'2018-11-20',50,4000,100),
(2,'2018-11-21',75,2475,100),
(3,'2018-12-15',75,2400,100),
(4,'2018-11-22',25,4000,200),
(5,'2018-11-22',25,4000,300)


With CTE As
(
   Select 
      ROW_NUMBER() Over(Partition By account_id Order By [Date] Desc) As rn,
      account_id, [Date], balance 
   From #transaction
   Where [Date] < '2018-12-01'
)
Select account_id, [Date], balance From CTE
Where  rn = 1 

结果:

account_id  Date                    balance
100         2018-11-21 00:00:00.000 2475
200         2018-11-22 00:00:00.000 4000
300         2018-11-22 00:00:00.000 4000

提供的两个答案同样出色。

我已经将其转换为 python sqlalchemy 答案以供参考:

from sqlalchemy import func
from datetime import datetime
import pandas as pd

start = datetime(2018,12,1)

row_number_column = func.row_number()                                    \
        .over(partition_by=Transaction.account_id,
              order_by=(Transaction.date.desc(), Transaction.id.desc()))  \
        .label('row_number')

query = DB.session.query(
            Transaction.account_id,
            Transaction.date,
            Transaction.balance,
            row_number_column)                            \
        .filter(Transaction.date < start)                 \
        .from_self().filter(row_number_column == 1)

df = pd.DataFrame(query.all(), columns=['Account Id', 'Date', 'Balance', 'RowId'])
df.drop(['RowId'], axis=1, inplace=True)
print(df)

最后三个可选行将其转换为 pandas 具有期初余额的数据框,按日期排序,然后按 ID 排序。