调用执行时出现 SAS 宏错误
SAS Macro error with call execute
我使用以下代码生成过去 1 天、7 天、1 个月、3 个月和 6 个月的 运行 个特征总数。
LIBNAME A "C:\Users\James\Desktop\data\Base Data";
LIBNAME DATA "C:\Users\James\Desktop\data\Data1";
%MACRO HELPER(P);
data a1;
set data.final_master_&P. ;
QUERY = '%TEST('||STRIP(DATETIME)||','||STRIP(PARTICIPANT)||');';
CALL EXECUTE(QUERY);
run;
%MEND;
%MACRO TEST(TIME,PAR);
proc sql;
select SUM(APP_1), SUM(APP_2), sum(APP_3), SUM(APP_4), SUM(APP_5) INTO :APP_1_24, :APP_2_24, :APP_3_24, :APP_4_24, :APP_5_24
FROM A1
WHERE DATETIME BETWEEN INTNX('SECONDS',&TIME.,-60*60*24) AND &TIME.;
/* 7 Days */
select SUM(APP_1), SUM(APP_2), sum(APP_3), SUM(APP_4), SUM(APP_5) INTO :APP_1_7DAY, :APP_2_7DAY, :APP_3_7DAY, :APP_4_7DAY, :APP_5_7DAY
FROM A1
WHERE DATETIME BETWEEN INTNX('SECONDS',&TIME.,-60*60*24*7) AND &TIME.;
/* One Month */
select SUM(APP_1), SUM(APP_2), sum(APP_3), SUM(APP_4), SUM(APP_5) INTO :APP_1_1MONTH, :APP_2_1MONTH, :APP_3_1MONTH, :APP_4_1MONTH, :APP_5_1MONTH
FROM A1
WHERE DATETIME BETWEEN INTNX('SECONDS',&TIME.,-60*60*24*7*4) AND &TIME.;
/* Three Months */
select SUM(APP_1), SUM(APP_2), sum(APP_3), SUM(APP_4), SUM(APP_5) INTO :APP_1_3MONTH, :APP_2_3MONTH, :APP_3_3MONTH, :APP_4_3MONTH, :APP_5_3MONTH
FROM A1
WHERE DATETIME BETWEEN INTNX('SECONDS',&TIME.,-60*60*24*7*4*3) AND &TIME.;
/* Six Months */
select SUM(APP_1), SUM(APP_2), sum(APP_3), SUM(APP_4), SUM(APP_5) INTO :APP_1_6MONTH, :APP_2_6MONTH, :APP_3_6MONTH, :APP_4_6MONTH, :APP_5_6MONTH
FROM A1
WHERE DATETIME BETWEEN INTNX('SECONDS',&TIME.,-60*60*24*7*4*6) AND &TIME.;
quit;
DATA T;
PARTICIPANT = &PAR.;
DATETIME = &TIME;
APP_1_24 = &APP_1_24.;
APP_2_24 = &APP_2_24.;
APP_3_24 = &APP_3_24.;
APP_4_24 = &APP_4_24.;
APP_5_24 = &APP_5_24.;
APP_1_7DAY = &APP_1_7DAY.;
APP_2_7DAY = &APP_2_7DAY.;
APP_3_7DAY = &APP_3_7DAY.;
APP_4_7DAY = &APP_4_7DAY.;
APP_5_7DAY = &APP_5_7DAY.;
APP_1_1MONTH = &APP_1_1MONTH.;
APP_2_1MONTH = &APP_2_1MONTH.;
APP_3_1MONTH = &APP_3_1MONTH.;
APP_4_1MONTH = &APP_4_1MONTH.;
APP_5_1MONTH = &APP_5_1MONTH.;
APP_1_3MONTH = &APP_1_3MONTH.;
APP_2_3MONTH = &APP_2_3MONTH.;
APP_3_3MONTH = &APP_3_3MONTH.;
APP_4_3MONTH = &APP_4_3MONTH.;
APP_5_3MONTH = &APP_5_3MONTH.;
APP_1_6MONTH = &APP_1_6MONTH.;
APP_2_6MONTH = &APP_2_6MONTH.;
APP_3_6MONTH = &APP_3_6MONTH.;
APP_4_6MONTH = &APP_4_6MONTH.;
APP_5_6MONTH = &APP_5_6MONTH.;
FORMAT DATETIME DATETIME.;
RUN;
PROC APPEND BASE=DATA.FLAGS_&par. DATA=T;
RUN;
%MEND;
%helper(1);
如果我在创建 a1 数据集时使用 (obs=) 限制 %helper 宏中的观察数量,则此代码运行完美。但是,当我对 obs 数没有限制时,即对数据集 a1 中的每一行执行 %test 宏时,我得到错误。在 SAS EG 中,状态栏挂在 "running data step" 后,我得到一个 "server disconnected" 弹出窗口,而在 Base SAS 9.4 上,我得到的错误是 none 的宏变量已被创建在proc sql 中。
我很困惑,因为代码对于有限数量的观察工作正常,但在尝试整个数据集时它会挂起或出错。我这样做的数据集有大约 130,000 个观察值。
您的实际问题的答案是您只是生成了过多的宏代码,甚至可能只是花费了太多时间。您这样做的方式将在 O=n^2 级别上运行,因为您基本上是在对每条记录和每条记录进行笛卡尔连接,然后再进行一些记录。 130,000 * 130,000 是一个相当不错的数字,除此之外,您实际上为每 130,000 行打开 SQL 环境几次。哎哟
解决方案是以不太慢的方式进行,或者如果是,至少不会有太多开销的方式。
快速解决方案是不进行笛卡尔连接,或者限制需要连接的数量。一个好的解决方案是重组问题,不需要比较每条记录,而是考虑每个日历日,比如一个时期,尤其是在超过 24 小时的时期(24 小时你可以按照上面的方式做,但不是其他四个)。 1 个月、3 个月等,您真的需要弄清楚一天中的时间吗?可能不会有太大区别。如果你能摆脱它,那么你可以使用内置的 PROCs 来预编译所有可能的 1 个月时间段、所有可能的 3 个月时间段等,然后加入适当的时间段。但这不适用于其中的 130,000 个;它可能只有在您可以将其限制为每天一次时才有效。
如果您必须在第二级(或更糟)执行此操作,您需要做的是避免笛卡尔连接,而是跟踪您已经看到的各种记录和总和。算法的简短解释是:
每一行:
- 将此行的值添加到滚动总和(在队列的末尾)
- 检查队列的当前项是否在周期之外;如果是,从滚动和中减去它,并检查下一个项目(重复直到不在周期之外),更新当前队列位置
- Return此时的总和
这通常需要检查每一行两次(除了在奇数边界处,由于月份的天数不同,因此在多次迭代中没有弹出任何行)。这在 O=n 时间上运行,比笛卡尔连接快得多,而且需要的 memory/space 少得多(笛卡尔连接可能需要命中磁盘 space)。
此解决方案的哈希版本如下。这将是我认为比较每一行的最快解决方案。请注意,我有意让测试数据每一行都有 1,每天都有相同的行数;这让您可以很容易地看到它是如何按行方式工作的。 (例如,每 24 小时周期有 481 行,因为我每天准确地制作 480 行,而 481 包括昨天的同一时间 - 如果您将 lt
更改为 le
它将是 480,如果您愿意不包括昨天的同一时间)。您可以看到基于 'month' 的周期在月份变化的边界处会有稍微奇怪的结果,因为“01FEB20xx”到“01MAY20xx”周期的天数(因此行数)比“01JUL20xx”到“01OCT20xx”少得多' 期间,例如;最好是 30/90/180 天。
data test_data;
array app[5] app_1-app_5;
do _i = 1 to 130000;
dt_var = datetime() - _i*180;
do _j = 1 to dim(app);
*app[_j] = floor(rand('Uniform')*6); *generate 0 to 5 integer;
app[_j]=1;
end;
output;
end;
format dt_var datetime17.;
run;
proc sort data=test_data;
by dt_var;
run;
%macro add(array=);
do _i = 1 to dim(app);
&array.[_i] + app[_i];
end;
%mend add;
%macro subtract(array=);
do _i = 1 to dim(app);
&array.[_i] + (-1*app[_i]);
end;
%mend subtract;
%macro process_array_add(array=);
array app_&array. app_&array._1-app_&array._5;
%add(array=app_&array.);
%mend process_array_add;
%macro process_array_subtract(array=, period=, number=);
if _n_ eq 1 then do;
declare hiter hi_&array.('td');
rc_&array. = hi_&array..first();
end;
else do;
rc_&array. = hi_&array..setcur(key:firstval_&array.);
end;
do while (intnx("&period.",dt_var,&number.,'s') lt curr_dt_var and rc_&array.=0);
%subtract(array=app_&array.);
rc_&array. = hi_&array..next();
end;
retain firstval_&array.;
firstval_&array. = dt_var;
%mend process_array_subtract;
data want;
set test_data;
* if _n_ > 10000 then stop;
curr_dt_var = dt_var;
array app[5] app_1-app_5;
if _n_ eq 1 then do;
declare hash td(ordered:'a');
td.defineKey('dt_var');
td.defineData('dt_var','app_1','app_2','app_3','app_4','app_5');
td.defineDone();
end;
rc_a = td.add();
*start macro territory;
%process_array_add(array=24h);
%process_array_add(array=1wk);
%process_array_add(array=1mo);
%process_array_add(array=3mo);
%process_array_add(array=6mo);
%process_array_subtract(array=24h,period=DTDay, number=1);
%process_array_subtract(array=1wk,period=DTDay, number=7);
%process_array_subtract(array=1mo,period=DTMonth, number=1);
%process_array_subtract(array=3mo,period=DTMonth, number=3);
%process_array_subtract(array=6mo,period=DTMonth, number=6);
*end macro territory;
rename curr_dt_var=dt_var;
format curr_dt_var datetime21.3;
drop dt_var rc: _:;
output;
run;
这是一个纯数据步骤非哈希版本。在我的机器上,它实际上比散列解决方案更快;我怀疑它在带有 HDD 的机器上实际上并没有更快(我有一个 SSD,所以点访问并不比散列访问慢很多,而且我避免加载散列)。如果您不太了解或根本不了解散列,我建议您使用它,因为它更容易进行故障排除,并且它的缩放比例相似。对于大多数行,它访问 11 行,当前行和其他五行两次(一行,减去它,然后另一行),总共读取 130k 行大约一百万次。 (与笛卡尔的大约 170 亿次读取相比...)
我用“_2”作为宏的后缀,以区别于散列解决方案中的宏。
data test_data;
array app[5] app_1-app_5;
do _i = 1 to 130000;
dt_var = datetime() - _i*180;
do _j = 1 to dim(app);
*app[_j] = floor(rand('Uniform')*6); *generate 0 to 5 integer;
app[_j]=1;
end;
output;
end;
format dt_var datetime17.;
run;
proc sort data=test_data;
by dt_var;
run;
%macro add_2(array=);
do _i = 1 to dim(app);
&array.[_i] + app[_i];
end;
%mend add;
%macro subtract_2(array=);
do _i = 1 to dim(app);
&array.[_i] + (-1*app[_i]);
end;
%mend subtract;
%macro process_array_add_2(array=);
array app_&array. app_&array._1-app_&array._5; *define array;
%add_2(array=app_&array.); *add current row to array;
%mend process_array_add_2;
%macro process_array_sub_2(array=, period=, number=);
if _n_ eq 1 then do; *initialize point variable;
point_&array. = 1;
end;
else do; *do not have to do this _n_=1 as we only have that row;
set test_data point=point_&array.; *set the row that we may be subtracting;
end;
do while (intnx("&period.",dt_var,&number.,'s') lt curr_dt_var and point_&array. < _N_); *until we hit a row that is within the period...;
%subtract_2(array=app_&array.); *subtract the rows values;
point_&array. + 1; *increment the point to look at;
set test_data point=point_&array.; *set the new row;
end;
%mend process_array_sub_2;
data want;
set test_data;
*if _n_ > 10000 then stop; *useful for testing if you want to check time to execute;
curr_dt_var = dt_var; *save dt_var value from originally set record;
array app[5] app_1-app_5; *base array;
*start macro territory;
%process_array_add_2(array=24h); *have to do all of these adds before we start subtracting;
%process_array_add_2(array=1wk); *otherwise we have the wrong record values;
%process_array_add_2(array=1mo);
%process_array_add_2(array=3mo);
%process_array_add_2(array=6mo);
%process_array_sub_2(array=24h,period=DTDay, number=1); *now start checking to subtract what we need to;
%process_array_sub_2(array=1wk,period=DTDay, number=7);
%process_array_sub_2(array=1mo,period=DTMonth, number=1);
%process_array_sub_2(array=3mo,period=DTMonth, number=3);
%process_array_sub_2(array=6mo,period=DTMonth, number=6);
*end macro territory;
rename curr_dt_var=dt_var;
format curr_dt_var datetime21.3;
drop dt_var _:;
output; *unneeded in this version but left for comparison to hash;
run;
我使用以下代码生成过去 1 天、7 天、1 个月、3 个月和 6 个月的 运行 个特征总数。
LIBNAME A "C:\Users\James\Desktop\data\Base Data";
LIBNAME DATA "C:\Users\James\Desktop\data\Data1";
%MACRO HELPER(P);
data a1;
set data.final_master_&P. ;
QUERY = '%TEST('||STRIP(DATETIME)||','||STRIP(PARTICIPANT)||');';
CALL EXECUTE(QUERY);
run;
%MEND;
%MACRO TEST(TIME,PAR);
proc sql;
select SUM(APP_1), SUM(APP_2), sum(APP_3), SUM(APP_4), SUM(APP_5) INTO :APP_1_24, :APP_2_24, :APP_3_24, :APP_4_24, :APP_5_24
FROM A1
WHERE DATETIME BETWEEN INTNX('SECONDS',&TIME.,-60*60*24) AND &TIME.;
/* 7 Days */
select SUM(APP_1), SUM(APP_2), sum(APP_3), SUM(APP_4), SUM(APP_5) INTO :APP_1_7DAY, :APP_2_7DAY, :APP_3_7DAY, :APP_4_7DAY, :APP_5_7DAY
FROM A1
WHERE DATETIME BETWEEN INTNX('SECONDS',&TIME.,-60*60*24*7) AND &TIME.;
/* One Month */
select SUM(APP_1), SUM(APP_2), sum(APP_3), SUM(APP_4), SUM(APP_5) INTO :APP_1_1MONTH, :APP_2_1MONTH, :APP_3_1MONTH, :APP_4_1MONTH, :APP_5_1MONTH
FROM A1
WHERE DATETIME BETWEEN INTNX('SECONDS',&TIME.,-60*60*24*7*4) AND &TIME.;
/* Three Months */
select SUM(APP_1), SUM(APP_2), sum(APP_3), SUM(APP_4), SUM(APP_5) INTO :APP_1_3MONTH, :APP_2_3MONTH, :APP_3_3MONTH, :APP_4_3MONTH, :APP_5_3MONTH
FROM A1
WHERE DATETIME BETWEEN INTNX('SECONDS',&TIME.,-60*60*24*7*4*3) AND &TIME.;
/* Six Months */
select SUM(APP_1), SUM(APP_2), sum(APP_3), SUM(APP_4), SUM(APP_5) INTO :APP_1_6MONTH, :APP_2_6MONTH, :APP_3_6MONTH, :APP_4_6MONTH, :APP_5_6MONTH
FROM A1
WHERE DATETIME BETWEEN INTNX('SECONDS',&TIME.,-60*60*24*7*4*6) AND &TIME.;
quit;
DATA T;
PARTICIPANT = &PAR.;
DATETIME = &TIME;
APP_1_24 = &APP_1_24.;
APP_2_24 = &APP_2_24.;
APP_3_24 = &APP_3_24.;
APP_4_24 = &APP_4_24.;
APP_5_24 = &APP_5_24.;
APP_1_7DAY = &APP_1_7DAY.;
APP_2_7DAY = &APP_2_7DAY.;
APP_3_7DAY = &APP_3_7DAY.;
APP_4_7DAY = &APP_4_7DAY.;
APP_5_7DAY = &APP_5_7DAY.;
APP_1_1MONTH = &APP_1_1MONTH.;
APP_2_1MONTH = &APP_2_1MONTH.;
APP_3_1MONTH = &APP_3_1MONTH.;
APP_4_1MONTH = &APP_4_1MONTH.;
APP_5_1MONTH = &APP_5_1MONTH.;
APP_1_3MONTH = &APP_1_3MONTH.;
APP_2_3MONTH = &APP_2_3MONTH.;
APP_3_3MONTH = &APP_3_3MONTH.;
APP_4_3MONTH = &APP_4_3MONTH.;
APP_5_3MONTH = &APP_5_3MONTH.;
APP_1_6MONTH = &APP_1_6MONTH.;
APP_2_6MONTH = &APP_2_6MONTH.;
APP_3_6MONTH = &APP_3_6MONTH.;
APP_4_6MONTH = &APP_4_6MONTH.;
APP_5_6MONTH = &APP_5_6MONTH.;
FORMAT DATETIME DATETIME.;
RUN;
PROC APPEND BASE=DATA.FLAGS_&par. DATA=T;
RUN;
%MEND;
%helper(1);
如果我在创建 a1 数据集时使用 (obs=) 限制 %helper 宏中的观察数量,则此代码运行完美。但是,当我对 obs 数没有限制时,即对数据集 a1 中的每一行执行 %test 宏时,我得到错误。在 SAS EG 中,状态栏挂在 "running data step" 后,我得到一个 "server disconnected" 弹出窗口,而在 Base SAS 9.4 上,我得到的错误是 none 的宏变量已被创建在proc sql 中。
我很困惑,因为代码对于有限数量的观察工作正常,但在尝试整个数据集时它会挂起或出错。我这样做的数据集有大约 130,000 个观察值。
您的实际问题的答案是您只是生成了过多的宏代码,甚至可能只是花费了太多时间。您这样做的方式将在 O=n^2 级别上运行,因为您基本上是在对每条记录和每条记录进行笛卡尔连接,然后再进行一些记录。 130,000 * 130,000 是一个相当不错的数字,除此之外,您实际上为每 130,000 行打开 SQL 环境几次。哎哟
解决方案是以不太慢的方式进行,或者如果是,至少不会有太多开销的方式。
快速解决方案是不进行笛卡尔连接,或者限制需要连接的数量。一个好的解决方案是重组问题,不需要比较每条记录,而是考虑每个日历日,比如一个时期,尤其是在超过 24 小时的时期(24 小时你可以按照上面的方式做,但不是其他四个)。 1 个月、3 个月等,您真的需要弄清楚一天中的时间吗?可能不会有太大区别。如果你能摆脱它,那么你可以使用内置的 PROCs 来预编译所有可能的 1 个月时间段、所有可能的 3 个月时间段等,然后加入适当的时间段。但这不适用于其中的 130,000 个;它可能只有在您可以将其限制为每天一次时才有效。
如果您必须在第二级(或更糟)执行此操作,您需要做的是避免笛卡尔连接,而是跟踪您已经看到的各种记录和总和。算法的简短解释是:
每一行:
- 将此行的值添加到滚动总和(在队列的末尾)
- 检查队列的当前项是否在周期之外;如果是,从滚动和中减去它,并检查下一个项目(重复直到不在周期之外),更新当前队列位置
- Return此时的总和
这通常需要检查每一行两次(除了在奇数边界处,由于月份的天数不同,因此在多次迭代中没有弹出任何行)。这在 O=n 时间上运行,比笛卡尔连接快得多,而且需要的 memory/space 少得多(笛卡尔连接可能需要命中磁盘 space)。
此解决方案的哈希版本如下。这将是我认为比较每一行的最快解决方案。请注意,我有意让测试数据每一行都有 1,每天都有相同的行数;这让您可以很容易地看到它是如何按行方式工作的。 (例如,每 24 小时周期有 481 行,因为我每天准确地制作 480 行,而 481 包括昨天的同一时间 - 如果您将 lt
更改为 le
它将是 480,如果您愿意不包括昨天的同一时间)。您可以看到基于 'month' 的周期在月份变化的边界处会有稍微奇怪的结果,因为“01FEB20xx”到“01MAY20xx”周期的天数(因此行数)比“01JUL20xx”到“01OCT20xx”少得多' 期间,例如;最好是 30/90/180 天。
data test_data;
array app[5] app_1-app_5;
do _i = 1 to 130000;
dt_var = datetime() - _i*180;
do _j = 1 to dim(app);
*app[_j] = floor(rand('Uniform')*6); *generate 0 to 5 integer;
app[_j]=1;
end;
output;
end;
format dt_var datetime17.;
run;
proc sort data=test_data;
by dt_var;
run;
%macro add(array=);
do _i = 1 to dim(app);
&array.[_i] + app[_i];
end;
%mend add;
%macro subtract(array=);
do _i = 1 to dim(app);
&array.[_i] + (-1*app[_i]);
end;
%mend subtract;
%macro process_array_add(array=);
array app_&array. app_&array._1-app_&array._5;
%add(array=app_&array.);
%mend process_array_add;
%macro process_array_subtract(array=, period=, number=);
if _n_ eq 1 then do;
declare hiter hi_&array.('td');
rc_&array. = hi_&array..first();
end;
else do;
rc_&array. = hi_&array..setcur(key:firstval_&array.);
end;
do while (intnx("&period.",dt_var,&number.,'s') lt curr_dt_var and rc_&array.=0);
%subtract(array=app_&array.);
rc_&array. = hi_&array..next();
end;
retain firstval_&array.;
firstval_&array. = dt_var;
%mend process_array_subtract;
data want;
set test_data;
* if _n_ > 10000 then stop;
curr_dt_var = dt_var;
array app[5] app_1-app_5;
if _n_ eq 1 then do;
declare hash td(ordered:'a');
td.defineKey('dt_var');
td.defineData('dt_var','app_1','app_2','app_3','app_4','app_5');
td.defineDone();
end;
rc_a = td.add();
*start macro territory;
%process_array_add(array=24h);
%process_array_add(array=1wk);
%process_array_add(array=1mo);
%process_array_add(array=3mo);
%process_array_add(array=6mo);
%process_array_subtract(array=24h,period=DTDay, number=1);
%process_array_subtract(array=1wk,period=DTDay, number=7);
%process_array_subtract(array=1mo,period=DTMonth, number=1);
%process_array_subtract(array=3mo,period=DTMonth, number=3);
%process_array_subtract(array=6mo,period=DTMonth, number=6);
*end macro territory;
rename curr_dt_var=dt_var;
format curr_dt_var datetime21.3;
drop dt_var rc: _:;
output;
run;
这是一个纯数据步骤非哈希版本。在我的机器上,它实际上比散列解决方案更快;我怀疑它在带有 HDD 的机器上实际上并没有更快(我有一个 SSD,所以点访问并不比散列访问慢很多,而且我避免加载散列)。如果您不太了解或根本不了解散列,我建议您使用它,因为它更容易进行故障排除,并且它的缩放比例相似。对于大多数行,它访问 11 行,当前行和其他五行两次(一行,减去它,然后另一行),总共读取 130k 行大约一百万次。 (与笛卡尔的大约 170 亿次读取相比...)
我用“_2”作为宏的后缀,以区别于散列解决方案中的宏。
data test_data;
array app[5] app_1-app_5;
do _i = 1 to 130000;
dt_var = datetime() - _i*180;
do _j = 1 to dim(app);
*app[_j] = floor(rand('Uniform')*6); *generate 0 to 5 integer;
app[_j]=1;
end;
output;
end;
format dt_var datetime17.;
run;
proc sort data=test_data;
by dt_var;
run;
%macro add_2(array=);
do _i = 1 to dim(app);
&array.[_i] + app[_i];
end;
%mend add;
%macro subtract_2(array=);
do _i = 1 to dim(app);
&array.[_i] + (-1*app[_i]);
end;
%mend subtract;
%macro process_array_add_2(array=);
array app_&array. app_&array._1-app_&array._5; *define array;
%add_2(array=app_&array.); *add current row to array;
%mend process_array_add_2;
%macro process_array_sub_2(array=, period=, number=);
if _n_ eq 1 then do; *initialize point variable;
point_&array. = 1;
end;
else do; *do not have to do this _n_=1 as we only have that row;
set test_data point=point_&array.; *set the row that we may be subtracting;
end;
do while (intnx("&period.",dt_var,&number.,'s') lt curr_dt_var and point_&array. < _N_); *until we hit a row that is within the period...;
%subtract_2(array=app_&array.); *subtract the rows values;
point_&array. + 1; *increment the point to look at;
set test_data point=point_&array.; *set the new row;
end;
%mend process_array_sub_2;
data want;
set test_data;
*if _n_ > 10000 then stop; *useful for testing if you want to check time to execute;
curr_dt_var = dt_var; *save dt_var value from originally set record;
array app[5] app_1-app_5; *base array;
*start macro territory;
%process_array_add_2(array=24h); *have to do all of these adds before we start subtracting;
%process_array_add_2(array=1wk); *otherwise we have the wrong record values;
%process_array_add_2(array=1mo);
%process_array_add_2(array=3mo);
%process_array_add_2(array=6mo);
%process_array_sub_2(array=24h,period=DTDay, number=1); *now start checking to subtract what we need to;
%process_array_sub_2(array=1wk,period=DTDay, number=7);
%process_array_sub_2(array=1mo,period=DTMonth, number=1);
%process_array_sub_2(array=3mo,period=DTMonth, number=3);
%process_array_sub_2(array=6mo,period=DTMonth, number=6);
*end macro territory;
rename curr_dt_var=dt_var;
format curr_dt_var datetime21.3;
drop dt_var _:;
output; *unneeded in this version but left for comparison to hash;
run;