我想自动执行以下日期计算:将X个月添加(或减去)X个月到给定的数字变量中,该变量表示YYYYMM格式的日期,即201901代表2019年1月。 例如:201901 + 13个月= 202002
以下宏返回所需的值(&id_mes_n)
%macro suma_meses(id_mes_ini, n_meses);
%let anio_ini = %sysfunc(floor(&id_mes_ini/100)); /*get year*/
%let mes_ini = %sysfunc(mod (&id_mes_ini,100)); /*get month*/
%let aux = %eval(12*&anio_ini + &mes_ini + &n_meses);
%let anio_n = %sysfunc(floor(&aux/12)); /*calculate new year*/
%let mes_n = %sysfunc(mod (&aux,12)); /*calculate new month*/
%if &mes_n = 0 %then %do; /*correction for month 12*/
%let id_mes_n = %eval(100*(&anio_n-1)+ 12);
%end;
%else %do;
%let id_mes_n = %eval(100*&anio_n + &mes_n);
%end;
&id_mes_n /*returned value*/
%mend;
%suma_meses(201901, 13) /*returns 202002*/
我想在PROC SQL中使用宏,如下所示:
PROC SQL;
CREATE TABLE want AS
SELECT T1.*, %suma_meses(T1.old_date, T1.x_months) AS new_date
FROM have T1
WHERE %suma_meses(T1.old_date, T1.x_months) > 201801 ;
QUIT;
可以做到吗? 由于这种类型的计算对于我所在地区的人员(我们不是管理员,工程师等)来说是一项经常性的任务,因此其想法是与其他用户共享该宏以简化语法。换句话说,我们希望使代码更具可读性,避免复制粘贴问题,并使非高级用户摆脱严重的计算错误XD(尤其是当涉及子查询且X为负数时)。这样的宏可以使我们的生活更轻松。
答案 0 :(得分:1)
如果运行的是相对较新版本的SAS,则应将其作为FCMP函数而不是宏函数来共享。
proc fcmp
允许您创建(并保存)用户定义的函数,这些函数可从数据步骤和proc sql
(以及通过%sysfunc()
之类的内部)中调用。
下面是fcmp
函数的示例,该函数返回指定的两个数字之间的随机数:
proc fcmp outlib=work.funcs.funcs;
function randbetween(min,max);
return ( min + floor( ( 1 + max - min ) * rand("uniform") ) );
endsub;
run;
示例用法:
data example;
do cnt=1 to 5;
x = randbetween(1,100);
output;
end;
run;
结果:
Obs cnt x
1 1 8
2 2 93
3 3 98
4 4 97
5 5 12
如果您收到SAS关于其无法识别您的功能的任何投诉,则可能需要使用以下方式更新您的选项:options cmplib = (work.funcs);
答案 1 :(得分:1)
听起来像您正在尝试将201,801之类的数字视为代表2018年的第一个月,然后添加多个月份并使用相同的“样式”生成一个数字。
如果您要使用宏代码中的数字字符串来执行此操作,则可以创建如下这样的宏:
%sysfunc()
但是您想要一种可以与普通SAS语句中的变量值一起使用的方法,然后根本不使用%macro add_months_sas(date,months);
input(put(intnx('month',input(cats(&date,'01'),yymmdd8.),&months),yymmn6.),6.)
%mend;
。相反,只需使用宏来生成SAS代码即可直接调用函数。
WHERE %add_months_sas(T1.old_date, T1.x_months) > 201801
所以您的WHERE子句如下:
INTNX()
但是您实际上应该只将数字转换为实际日期,然后使用WHERE intnx('month',T1.old_date, T1.x_months) > '01JAN2018'd
函数添加月份。然后根本不需要宏。
{Set Db = CurrentDb()
Set rstblStaffExt = Db.OpenRecordset("tblStaffExt", dbOpenDynaset)
Do While Not rstblStaffExt.EOF
rstblStaffExt.Edit
rstblStaffExt!PreviousKey = rstblStaffExt!Key
rstblStaffExt!Returning = " “ ‘Works
rstblStaffExt!Leaving = " " ‘Works
rstblStaffExt!DayandTimeRequested = " " ‘Does not Work
rstblStaffExt!DayandTimeRequested = rstblStaffExt!ShiftRequestedDefault ‘Does not Work
‘The from field has one blank record in each to match the receiving field
rstblStaffExt!DayandTimeRequested = 25 ‘Does not Work
‘The 25 is key to a single record that could be used
rstblStaffExt.Update
rstblStaffExt.MoveNext
Loop }