SAS PROC SQL-使用从宏程序返回的值

时间:2019-03-11 21:37:14

标签: sas sas-macro proc-sql

我想自动执行以下日期计算:将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为负数时)。这样的宏可以使我们的生活更轻松。

2 个答案:

答案 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 }