是否可以使这种形式的宏起作用?
%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中需要返回值的情况下执行传统的函数逻辑...
答案 0 :(得分:3)
正如Richard所写,函数式宏发出SAS代码。开发函数样式宏的一般规则是它们仅包含宏语言语句。它们包含的任何SAS代码都会被发出。从历史上看,这使得编写函数式宏非常困难/烦恼,该宏将像处理DATA步骤一样处理数据。幸运的是,SAS添加了一个功能 DOSUBL ,该功能使编写在“侧边会话”中执行SAS代码并发出结果的函数式宏更加容易。参见Rick Langston's paper。
这里是一个函数样式宏的示例,该宏使用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将被调用3次,并将返回每个数据集中的记录数。
table count
---------------------------
sashelp.shoes 395
sashelp.class 19
sashelp.prdsale 1440
在解释PROC SQL步骤时看不到宏调用,因为该宏调用被单引号隐藏了。然后,在SELECT语句执行时,resolve函数调用宏,将table
的值作为参数值传递,并且该宏发出记录计数。这类似于使用数据来驱动宏调用的CALL EXECUTE方法。
答案 1 :(得分:1)
您声明要:
对数据集的每次观察运行一些相当复杂的逻辑
为此,您应该使用SAS语言而不是宏处理器或PROC SQL。您可以使用数据步骤。或者,对于更复杂的逻辑,您应该查看PROC DS2。
答案 2 :(得分:1)
听起来像您可能想使用proc fcmp
创建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;
答案 3 :(得分:0)
宏函数不返回值。宏函数可以“发出”源代码,
对于要在SQL中“执行”操作的情况,您可以编写 SQL视图,然后该
%sysfunc(open())
和%sysfunc(set())
和%sysfunc(getvarn())
和%sysfunc(getvarc())
。 这种技术并非可以利用所有SQL功能-select something into :result
必须是带有select something
的视图,而宏getvarc
才能读取结果。
以open / set / get方式进行的访问不会引起步骤边界的发生,因此宏处理可以按照其逻辑进行,并最终发出用于代码段级别使用的源代码。 (使用者是处理宏代码,隐式编译和运行SAS步骤的SAS执行程序)