我想动态创建宏以查询事务数据集。我有一个包含一组参数( parameter_data )和交易数据( txs )的表。对于参数数据中的每一行,我想创建一个可以调用以查询数据的宏。
参数数据:
data parameter_data;
input macro_name $ parameter_name $ parameter_value $;
datalines;
A Person_ID 1
B TX_ID 2
;
交易数据:
data txns;
input Person_ID $ TX_ID $ TX_Amount $;
datalines;
John Sales 1123
Mary Acctng 34
John Sales 23
Mary Sales 2134
;
在这里,我尝试创建一个宏,该宏应根据参数数据动态创建宏。 “内部宏”是根据参数数据创建的宏。
%macro outerMacro;
/*loop through each row in the parameter table to get the detail of the macro we want to create*/
%DO ROW = 1 %To 2;
data _NULL_;
set parameter_data;
if _N_ = ROW then do;
call symputx('parameter_name',parameter_name);
call symputx('parameter_value',parameter_value);
end;
run;
/*define inner macro parameters*/
%let macroName = myMacro; /*set the name of the macro we want to create*/
%let innerMacroStart = macro ¯oName.; /*set the macro name to start the macro definition*/
%let innerMacroEnd = mend ¯oName;
%&&innerMacroStart.; /*start the inner macro*/
/*body of the macro*/
data output;
set txns;
&¶meter_name = &¶meter_value;
/*so here effectively for the first row in the parameter table we are filtering where person_id = John*/
run;
%&&innerMacroEnd.; /*end the inner macro*/
%mend outerMacro;
%&&outerMacroName.;
似乎SAS无法解析%innerMacroStart行。非常感谢您的帮助。
谢谢!
答案 0 :(得分:0)
如果目标只是对数据进行子集化,那么生成宏变量而不是实际宏可能会更好。尝试这样的事情。
data _null_;
set parameter_data ;
call symputx(macro_name,catx(' ','where also'
,parameter_name,'=',quote(trim(parameter_value)),';'));
run;
然后在需要时通过扩展宏变量使用生成的where语句。像这样:
data output ;
set txns;
&a
run;
如果您确实要生成宏定义,则可能只想使用数据步骤将代码写入文件,然后%include该文件以编译宏。这将比宏逻辑更容易调试。
让我们修复您的参数文件以更好地匹配您的测试数据。 Person_ID和TX_ID是交易数据集中的字符变量。您可能需要添加逻辑或更改参数文件,以使其能够处理数字和字符变量的测试。现在,我只是使其生成的代码假定PARAMETER_NAME引用了一个字符变量,因此PARAMETER_VALUE将需要添加引号以使其成为字符串文字。
data parameter_data;
input macro_name :$32. parameter_name :$32. parameter_value $:200.;
datalines;
A Person_ID John
B TX_ID Acctng
;
data txns;
input Person_ID $ TX_ID $ TX_Amount $;
datalines;
John Sales 1123
Mary Acctng 34
John Sales 23
Mary Sales 2134
;
现在,让我们运行一个数据步骤为所有宏生成代码。如果为每个宏定义了多个“参数”,我添加了使用AND
的逻辑。
filename code temp;
data _null_;
set parameter_data ;
by macro_name ;
file code ;
if first.macro_name then put
'%macro ' macro_name ';'
/ 'data output;'
/ ' set txns;'
/ ' where ' @
;
else put ' and ' @ ;
put parameter_name '=' parameter_value :$quote. @ ;
if last.macro_name then put
';'
/ 'run;'
/ '%mend ' macro_name ';'
;
run;
现在只需使用%include来编译宏。
%include code / source2 ;
NOTE: %INCLUDE (level 1) file CODE is file C:\...\#LN00048.
432 +%macro A ;
433 +data output;
434 + set txns;
435 + where Person_ID ="John" ;
436 +run;
437 +%mend A ;
438 +%macro B ;
439 +data output;
440 + set txns;
441 + where TX_ID ="Acctng" ;
442 +run;
443 +%mend B ;
NOTE: %INCLUDE (level 1) ending.
现在您可以使用宏了。
445 options mprint;
446 %a ;
MPRINT(A): data output;
MPRINT(A): set txns;
MPRINT(A): where Person_ID ="John" ;
MPRINT(A): run;
NOTE: There were 2 observations read from the data set WORK.TXNS.
WHERE Person_ID='John';
NOTE: The data set WORK.OUTPUT has 2 observations and 3 variables.
447 %b ;
MPRINT(B): data output;
MPRINT(B): set txns;
MPRINT(B): where TX_ID ="Acctng" ;
MPRINT(B): run;
NOTE: There were 1 observations read from the data set WORK.TXNS.
WHERE TX_ID='Acctng';
NOTE: The data set WORK.OUTPUT has 1 observations and 3 variables.
答案 1 :(得分:0)
我在每个代码块之前都添加了一条注释,但实际上是:
我假设参数观察值不超过999个,这由seq
控制。
您可以检查文件“ inner_macro.sas”以查看宏定义。
笔记本电脑。尝试时,请确保使用自己的路径代替<your-path>
(出现两次):
/* set up parameters */
data parameters;
infile datalines dlm=',';
input var : $8.
operator : $8.
value : $8.
;
datalines;
name,eq,"John"
age,gt,12
weight,eq,0
;
/* read parameters and generate a macro definition for each obs, written to a file */
data _null_;
file '<your-path>/inner_macro.sas';
set parameters;
seq = put(_n_,z3.);
put '%macro inner_' seq ';';
put ' where ' var operator value ';';
put '%mend inner_' seq ';';
put;
run;
/* %include (submits code in file) all of the macro definitions */
%include '<your-path>/inner_macro.sas';
options mprint;
/* invoke the macro with the required data sets */
data class1;
set sashelp.class;
%inner_001;
run;
data class2;
set sashelp.class;
%inner_002;
run;
data class3;
set sashelp.class;
%inner_003;
run;