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

SAS PROC SQL - calculate a column using a value returned from macro program

我想自动执行以下日期计算:向表示 YYYYMM 形式日期的给定数值变量添加(或减去)X 个月,即 201901 代表 2019 年 1 月。 示例:201901 + 13 个月 = 202002

下面的宏returns想要的值(&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 为负数时)。这样的宏会让我们的生活更轻松。

如果您是 运行 相对较新的 SAS 版本,您应该将其作为 FCMP 函数而不是宏函数共享。

proc fcmp 允许您创建(和保存)可从数据步和 proc sql(以及通过 %sysfunc() 之类的东西)调用的用户定义函数。

这是一个 fcmp 函数的示例,该函数 returns 指定两个数字之间的随机数:

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);

听起来您正在尝试将 201,801 之类的数字视为代表 2018 年的第一个月,然后添加月份数并使用相同的 "style".

如果你想在宏代码中使用数字字符串,你可以创建一个这样的宏:

%macro add_months_macro(date,months);
%sysfunc(intnx(month,%sysfunc(inputn(&date.01,yymmdd8)),&months),yymmn6)
%mend;

但是如果您想要一种可以在普通 SAS 语句中使用变量值的方法,那么根本不要使用 %sysfunc()。而是直接使用宏生成 SAS 代码来直接调用函数。

%macro add_months_sas(date,months);
input(put(intnx('month',input(cats(&date,'01'),yymmdd8.),&months),yymmn6.),6.)
%mend;

那么您的 WHERE 子句将如下所示:

WHERE %add_months_sas(T1.old_date, T1.x_months) > 201801 

但是你真的应该只是将数字转换为实际日期,然后使用 INTNX() 函数添加月份。 那么根本不需要宏.

WHERE intnx('month',T1.old_date, T1.x_months) > '01JAN2018'd