如果宏变量为空,则跳过代码块

时间:2014-06-30 17:56:17

标签: sas sas-macro

我正在使用下面的SAS代码创建一个宏变量。它存储了一个数据名列表,我需要在特定变量中替换某些值。

proc sql noprint;
select distinct data_name
into :data_repl separated by ' '
from TP_attribute_matching
where Country="&Country_Name" and Replace_this ne ' ';
quit;

如果data_repl为空,我想跳过以下2个块。这两个块遍历该数据集中的每个数据集和变量,然后用y替换x。

/*Block 1*/
%do i=1 %to %_count_(word=&data_repl);
proc sql noprint;
select var_name,
   Replace_this,
   Replace_with
into :var_list_repl_&i. separated by ' ',
     :repl_this_list_&i. separated by '@',
     :repl_with_list_&i. separated by '@'
     from TP_attribute_matching
where Replace_this ne ' ' and data_name="%scan(&data_repl,&i.)";
quit;

/* Block 2 */
%do i=1 %to %_count_(word=&data_repl);
data sasdata.%scan(&data_repl,&i);
set sasdata.%scan(&data_repl,&i);
 %do j=1 %to %_count_(word=&&var_list_repl_&i.);
   %let from=%scan("&&repl_this_list_&i.",&j,'@');
   %let to=%scan("&&repl_with_list_&i.",&j,'@');
   %scan(&&var_list_repl_&i.,&j)=translate(%scan(&&var_list_repl_&i.,&j),&to,&from); 
 %end;
run;
%end;

我怎么做这个?我正在经历%SKIP,如果然后离开,但还是无法解决这个问题。

2 个答案:

答案 0 :(得分:2)

%IF%DO是只能在宏内使用的宏语句:

%macro DoSomething;
%if "&data_repl" ne "" %then %do;
    /*Block 1*/
    %do i=1 %to %_count_(word=&data_repl);
    proc sql noprint;
    select var_name,
       Replace_this,
       Replace_with
    into :var_list_repl_&i. separated by ' ',
         :repl_this_list_&i. separated by '@',
         :repl_with_list_&i. separated by '@'
         from TP_attribute_matching
    where Replace_this ne ' ' and data_name="%scan(&data_repl,&i.)";
    quit;

    /* Block 2 */
    %do i=1 %to %_count_(word=&data_repl);
    data sasdata.%scan(&data_repl,&i);
    set sasdata.%scan(&data_repl,&i);
     %do j=1 %to %_count_(word=&&var_list_repl_&i.);
       %let from=%scan("&&repl_this_list_&i.",&j,'@');
       %let to=%scan("&&repl_with_list_&i.",&j,'@');
       %scan(&&var_list_repl_&i.,&j)=translate(%scan(&&var_list_repl_&i.,&j),&to,&from); 
     %end;
    run;
    %end;

%end;
%mend;

%DoSomething

编辑: 您可以使用PROC SQL中的计数(& SQLOBS宏变量)

,而不是检查字符串
%let SQLOBS=0; /* reset SQLOBS */
%let data_repl=; /* initialize data_repl,
                    would not be defined in case when no rows returned */

proc sql noprint;
select distinct data_name
into :data_repl separated by ' '
from TP_attribute_matching
where Country="&Country_Name" and Replace_this ne ' '
and not missing(data_name);
quit;

%let my_count = &SQLOBS; /* keep the record count from last PROC SQL */
...

%if &my_count gt 0 %then %do;
...
...
%end;

如果您已有主宏,则无需定义新内容(我不确定您现在要求的内容)。

答案 1 :(得分:0)

首先,这是另一个很好的例子,列表处理基础将简化代码,而不必担心您的实际问题。稍后会详细说明。

其次,这些循环通常被编码的方式类似于

%do ... %while &macrovar ne ;

如果它开始为空则检查为空并且根本不执行循环。 &macrovar会有扫描结果。 IE:

%let scan_result = %scan(&Data_repl.,1);
%do i = 1 %to %_count_... while &scan_result ne ; *perhaps minus one, not sure what %_count_() does exactly;
  ... code
  %let scan_result=%scan(&data_Repl.,&i+1);
%end;

回到列表处理,你最终要做的是:

data &dataset.;
 set &dataset.;
 [for some set of &variables,&tos, &froms]
 &variable. = translate(&variable.,&to.,&from.);
 [/set of variables]
run;

所以你需要的是几个宏。假设您有一个

的数据集
<dataset> <varname> <to> <from>

你可以很容易地调用它。两种方式:

将其作为一组嵌套的宏/调用运行。这有点麻烦,但可能更容易理解。

 %macro do_dataset(data=);
  proc sql noprint;
    select cats('%convert_Var(var=',varname,',to=',to,',from=',from,')')
      into :convertlist separated by ' '
      from dataset_with_conversions
      where dataset="&data.";
  quit;

  data &data;
   set &data;
   &convertlist.;
  run;
 %mend do_dataset;

%macro convert_var(var=,to=,from=);
&var. = translate(&var.,"&to.","&from.");
%mend convert_var;

proc sql noprint;
select cats('%do_dataset(data=',dataset,')') 
 into :dslist separated by ' '
 from dataset_with_conversions;
quit;

&dslist;

其次,您可以使用call execute(而不是两个不同的步骤)在一个datastep中完成所有这些操作。 IE,执行by dataset语句,然后执行first.dataset执行data <dataset>;(填写)和last.dataset执行run,否则执行翻译。< / p>

更复杂,但一次通过解决方案 - 取决于您喜欢的舒适度,它们通常应该类似。