按 account_number 判断日期是否位于两个日期之间
数据阿明
结论
先按 acct_num 和 biiling_date 排序,每个账户只保留日期最早的两条记录。再用这两条记录的 billing cycle date 确定区间上下界,检查 tran_date 是否落在区间内。账户必须至少有两次 billing cycle,且交易日期在区间内,才会保留这两条记录。
SAS 实现
先确保日期已读取为 SAS 日期值,而不是字符:
data have;
input acct_num
biiling_date :date9.
tran_date :date9.;
format biiling_date tran_date date9.;
datalines;
1111 23FEB2020 27FEB2020
1111 23MAR2020 27FEB2020
2222 17MAR2020 22MAR2020
2222 27APR2020 22MAR2020
2222 27MAY2020 22MAR2020
3333 23JUL2018 02JUN2022
3333 23AUG2018 02JUN2022
;
run;
1. 按账户和 billing cycle date 排序
proc sort data=have out=have_sorted;
by acct_num biiling_date;
run;
这里将“前两次 occurrence”理解为日期最早的两次。如果 occurrence 指原始数据中的行顺序,应先创建行号,再按行号排序,而不是按 biiling_date 排序。
2. 每个账户只保留前两条记录
data first_two;
set have_sorted;
by acct_num;
if first.acct_num then occurrence = 0;
occurrence + 1;
if occurrence <= 2;
run;
进入新账户时,occurrence 会重置。因此,账户 2222 的第三条记录会在这一步被删除。
3. 确定区间并筛选账户
proc sql;
create table want as
select a.acct_num,
a.biiling_date,
a.tran_date
from first_two as a
inner join
(
select acct_num,
min(biiling_date) as start_date format=date9.,
max(biiling_date) as end_date format=date9.
from first_two
group by acct_num
having count(*) = 2
) as b
on a.acct_num = b.acct_num
where a.tran_date between b.start_date and b.end_date
order by a.acct_num, a.biiling_date;
quit;
结果如下:
1111 23FEB2020 27FEB2020
1111 23MAR2020 27FEB2020
2222 17MAR2020 22MAR2020
2222 27APR2020 22MAR2020
为什么 account 3333 会被删除
账户 3333 的日期区间是:
23JUL2018 至 23AUG2018
它的 tran_date 是 02JUN2022,不在这个区间内,所以连接后的两条记录都不满足 WHERE 条件。
注意事项
-
SAS 日期必须是数值型日期。如果原始字段是字符,需要先用
input(character_date, date9.)转换。 -
BETWEEN包含两个边界,相当于:start_date <= tran_date <= end_date -
账户至少需要有两条记录。
having count(*) = 2会排除只有一次 billing cycle 的账户。 -
这段代码以同一账户的
tran_date保持一致为前提。如果同一账户可能有多个不同的tran_date,需要进一步确定是逐行判断,还是只要任意一个交易日期落入区间,就保留该账户的前两条记录。 -
字段名沿用了示例中的
biiling_date。如果实际字段名是billing_date,需要统一替换。
备注:内容仅供参考。
