SAS-动态创建宏

时间:2018-10-08 07:47:29

标签: dynamic macros sas nested

我想动态创建宏以查询事务数据集。我有一个包含一组参数( 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 &macroName.; /*set the macro name to start the macro definition*/
%let innerMacroEnd = mend &macroName;

%&&innerMacroStart.; /*start the inner macro*/

    /*body of the macro*/
    data output;
    set txns;
    &&parameter_name = &&parameter_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行。非常感谢您的帮助。

谢谢!

2 个答案:

答案 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)

我在每个代码块之前都添加了一条注释,但实际上是:

  1. 参数设置。
  2. 宏生成。
  3. %include。
  4. 调用任何所需的宏。

我假设参数观察值不超过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;