[英]function style macro in SAS with PROC SQL?
是否可以使这种形式的宏起作用?
%macro tableMath(input1,input2);
%local result;
proc sql; ---some code here using inputs--- quit;
proc sql; ---more code here--- quit;
proc sql;
select something into: result
quit;
&result
%mend;
我想对数据集的每次观察运行一些相当复杂的逻辑,并且在执行此操作之前,我使用的任何其他语言都是将其封装在一个函数中,该函数每次调用都会返回结果-我我不确定如何在SAS中执行此逻辑。
编辑:input1和input2将是数据集的列,结果将用于在程序另一部分的其他宏中创建新列。 我不需要特定的代码解决方案,我只是不了解如何在SAS中需要返回值的情况下执行传统的函数逻辑...
正如Richard所写的那样,函数样式的宏会发出SAS代码。 开发函数样式宏的一般规则是它们仅包含宏语言语句。 它们包含的任何SAS代码都会被发出。 从历史上看,这使得编写函数式宏非常困难/烦恼,该宏将像处理DATA步骤一样处理数据。 幸运的是,SAS添加了一个函数DOSUBL ,该函数使编写在“侧边会话”中执行SAS代码并发出结果的函数式宏更加容易。 请参阅Rick Langston的论文 。
这是一个函数样式宏的示例,该宏使用DOSUBL对表中的记录数进行计数,并发出该计数。 (这是获得记录计数的一种非常低效的方法,仅是在SQL中执行操作的示例)。
%macro SQLcount(table);
%local rc emit;
%let rc=%sysfunc(dosubl(%nrstr(
proc sql noprint;
select count(*) into :emit trimmed
from &table
quit;
)));
&emit
%mend ;
可以像这样使用:
proc sql ;
select name
,%SQLcount(sashelp.shoes) as ShoeCount /*emits 395*/
from sashelp.class
;
quit ;
运行上述步骤时,它将从sashelp.class返回19行名称,并且ShoeCount的值将为每行395。 请注意,宏SQLcount仅执行一次。 在编译/解释PROC SQL步骤时,将看到对SQLcount的调用,并执行了该宏并发出395。该步骤变为:
proc sql ;
select name
,395 as ShoeCount /*emits 395*/
from sashelp.class
;
quit ;
DOSUBL使用“辅助会话”执行代码,这使您可以在辅助会话中执行PROC SQL步骤,而主会话正在解释PROC SQL步骤。
从您的问题中我无法确定您是否想要这种用例。 您可能需要一个函数样式的宏,您可以在其中从表中将值传递给它,并使该宏在每个值上执行并返回某些内容。 假设您有一个表,该表是一个表名列表,并且想要使用SQL获取每个表中的记录数:
data mytables ;
input table $20. ;
cards ;
sashelp.shoes
sashelp.class
sashelp.prdsale
;
quit ;
您可以通过使用resolve()函数从数据构建宏调用,将宏的执行延迟到SELECT语句执行之前来完成:
proc sql ;
select table
,resolve('%SQLcount('||table||')') as count
from mytables
;
quit ;
这样,SQLcount将被调用三次,并将返回每个数据集中的记录数。
table count
---------------------------
sashelp.shoes 395
sashelp.class 19
sashelp.prdsale 1440
解释PROC SQL步骤时看不到宏调用,因为该宏调用被单引号隐藏。 然后,在SELECT语句执行时,resolve函数调用宏,将table
的值作为参数值传递,并且该宏发出记录计数。 这类似于使用数据来驱动宏调用的CALL EXECUTE方法。
您声明要:
对数据集的每次观察运行一些相当复杂的逻辑
为此,您应该使用SAS语言而不是宏处理器或PROC SQL。 您可以使用数据步骤。 或者,对于更复杂的逻辑,您应该查看PROC DS2。
听起来您可能想使用proc fcmp
创建proc fcmp
函数。 这基本上是一种创建自己的SAS函数的方法,该函数可在proc sql
和data
步骤中使用。 例如:
/******************************************************************************
** PROGRAM: COMMON.FCMP_DIV.SAS
**
** DESCRIPTION: PERFORMS A MATHEMATICAL DIVISION BUT WILL RETURN NULL IF THE
** NUMERATOR OR DENOMINATOR IS MISSING (OR IF THE DIVISOR IS 0).
**
******************************************************************************/
proc fcmp outlib=common.funcs.funcs;
function div(numerator, denominator);
if numerator eq . or denominator in (0,.) then do;
return(.);
end;
else do;
return(numerator / denominator);
end;
endsub;
run;
用法示例(示例是数据步骤,但在SQL中同样有效):
data x;
x1 = div(1,0);
x2 = div(1,.);
x3 = div(1,1);
x4 = div(0,0);
x5 = div(0,.);
x6 = div(0,1);
x7 = div(.,0);
x8 = div(.,.);
x9 = div(.,1);
put _all_;
run;
宏函数不返回值。 宏函数可以“发出”源代码,
对于要在SQL中“执行”操作的情况,可以编写SQL视图 ,然后
%sysfunc(open())
并 %sysfunc(set())
和 %sysfunc(getvarn())
和 %sysfunc(getvarc())
。 并非所有的SQL功能都可以通过这种技术使用-在select something into :result
必须是带有select something
的视图,并且宏将使用getvarc
读取结果。
以open / set / get方式进行的访问不会引起步骤边界的发生,因此宏处理可以按照其逻辑进行,并最终发出源代码以供摘要使用。 (使用者是处理宏代码,隐式编译和运行SAS步骤的SAS执行程序)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.