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
我想自动执行以下日期计算:向表示 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