Access SQL 查询每笔交易的上一次付款日期
支付小周
结论
可以使用相关子查询,查找同一 TenantID 下、日期早于当前交易且 TransactionType = 2 的记录,再用 Max() 取得最近一次付款日期。如果没有符合条件的付款记录,Max() 会返回 Null,当前交易仍会保留。
假设现有查询名为 qryTransactions:
SELECT
T.TransID,
T.TenantID,
T.TransactionType,
T.Amount,
T.TransactionDate,
(
SELECT Max(P.TransactionDate)
FROM qryTransactions AS P
WHERE P.TenantID = T.TenantID
AND P.TransactionType = 2
AND P.TransactionDate < T.TransactionDate
) AS PreviousPaymentDate
FROM qryTransactions AS T
ORDER BY
T.TenantID,
T.TransactionDate,
T.TransID;
查询原理
相关子查询会针对外层查询中的每笔交易执行一次:
P.TenantID = T.TenantID:只查找当前客户的交易。P.TransactionType = 2:只考虑付款记录。P.TransactionDate < T.TransactionDate:只考虑当前交易之前发生的付款。Max(P.TransactionDate):从符合条件的付款记录中取得最近的日期。
外层查询没有使用 INNER JOIN,所以找不到历史付款时也不会过滤当前记录,PreviousPaymentDate 会返回 Null。
使用表名时的写法
如果数据直接来自名为 Transactions 的表,可以写成:
SELECT
T.TransID,
T.TenantID,
T.TransactionType,
T.Amount,
T.TransactionDate,
(
SELECT Max(P.TransactionDate)
FROM Transactions AS P
WHERE P.TenantID = T.TenantID
AND P.TransactionType = 2
AND P.TransactionDate < T.TransactionDate
) AS PreviousPaymentDate
FROM Transactions AS T
ORDER BY
T.TenantID,
T.TransactionDate,
T.TransID;
如果表名或字段名与 Access 保留字冲突,建议加上方括号:
SELECT
T.[TransID],
T.[TenantID],
T.[TransactionType],
T.[Amount],
T.[TransactionDate],
(
SELECT Max(P.[TransactionDate])
FROM [Transactions] AS P
WHERE P.[TenantID] = T.[TenantID]
AND P.[TransactionType] = 2
AND P.[TransactionDate] < T.[TransactionDate]
) AS [PreviousPaymentDate]
FROM [Transactions] AS T;
注意事项
同一时间发生多笔交易
上述查询将“之前”定义为:
P.TransactionDate < T.TransactionDate
因此,与当前交易具有相同 TransactionDate 的付款不会被视为上一笔付款。这样处理通常更安全,因为仅凭相同的时间无法判断记录的先后顺序。
如果业务规则规定时间相同时,TransID 较小的记录先发生,就需要同时根据 TransactionDate 和 TransID 判断顺序。不过,如果返回值仍然只有日期,同一时间下的结果看起来会与当前交易日期相同。更稳妥的做法是让 TransactionDate 保存足够精确的时间,或者增加明确的交易顺序字段。
Null 交易日期
如果当前记录的 TransactionDate 为 Null,以下比较条件不会匹配任何记录:
P.TransactionDate < T.TransactionDate
因此,PreviousPaymentDate 也会是 Null。
查询性能
相关子查询会为每条外层记录查找历史付款。数据量较大时,建议为以下字段建立索引:
TenantIDTransactionTypeTransactionDate
如果 Access 支持,并且数据规模确实需要进一步优化,可以考虑为这些字段建立复合索引。复合索引的实际效果取决于数据分布和查询计划,应使用真实数据进行测试。
备注:内容仅供参考。
