我正在使用下面的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,如果然后离开,但还是无法解决这个问题。
答案 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 ¯ovar ne ;
如果它开始为空则检查为空并且根本不执行循环。 ¯ovar
会有扫描结果。 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>
更复杂,但一次通过解决方案 - 取决于您喜欢的舒适度,它们通常应该类似。