如何筛选指定日期区间内有交易的账户的全部历史记录?
需求与问题说明
现有一张包含Account(账户)、Sale(销售额)、Date(日期)字段的交易表,数据如下:
| Account | Sale | Date |
|---|---|---|
| A | $5 | 2023-Jan-01 |
| A | $8 | 2023-Feb-15 |
| B | $2 | 2023-Mar-03 |
| A | $7 | 2023-Apr-10 |
| A | $9 | 2024-Jan-01 |
当指定日期范围为2023-Apr-01至2023-Apr-30时,期望得到:该日期范围内有交易的账户(比如账户A)的全部历史交易记录,包括区间内及之前的所有记录。
尝试过两种方法但都不符合需求:
- 直接执行
SELECT * FROM 交易表 WHERE Date < '2023-Apr-30',会包含账户B的记录,不符合要求; - 用窗口函数
MAX(Date) OVER (PARTITION BY Account ORDER BY Date) AS Max_Date后,执行SELECT * WHERE Max_Date < '2023-Apr-30',但账户A的Max_Date是2024-Jan-01,结果为空,也不对。
解决办法
方法1:子查询筛选目标账户
先找出在指定日期范围内有交易的账户,再关联原表获取这些账户的所有历史记录:
SELECT t.* FROM 交易表 t INNER JOIN ( -- 筛选出目标日期范围内有交易的账户 SELECT DISTINCT Account FROM 交易表 WHERE Date BETWEEN '2023-Apr-01' AND '2023-Apr-30' ) target_accounts ON t.Account = target_accounts.Account -- 只保留该账户在目标日期及之前的记录 WHERE t.Date <= '2023-Apr-30';
逻辑直观易懂,适配大多数数据库场景。
方法2:窗口函数标记符合条件的账户
换一种窗口函数用法,给每个账户的所有记录打上「是否在目标区间有交易」的标记,再筛选:
WITH account_with_flag AS ( SELECT *, -- 标记该账户是否在目标日期范围内有交易 MAX(CASE WHEN Date BETWEEN '2023-Apr-01' AND '2023-Apr-30' THEN 1 ELSE 0 END) OVER (PARTITION BY Account) AS has_target_transaction FROM 交易表 ) SELECT Account, Sale, Date FROM account_with_flag WHERE has_target_transaction = 1 AND Date <= '2023-Apr-30';
只要该账户在目标区间有交易,其下所有记录的标记都会是1,后续筛选标记为1且日期不超区间的记录即可。
方法3:EXISTS子查询
用EXISTS判断当前账户是否在目标日期范围内有交易,写法简洁:
SELECT t.* FROM 交易表 t WHERE EXISTS ( SELECT 1 FROM 交易表 t2 WHERE t2.Account = t.Account AND t2.Date BETWEEN '2023-Apr-01' AND '2023-Apr-30' ) AND t.Date <= '2023-Apr-30';
数据库优化器通常能高效处理这类关联查询,性能表现较好。
内容的提问来源于stack exchange,提问作者SQL_Noob
相关产品推荐
相关产品推荐

