2017-01-09 222 views
1

基本上我正在写一个宏,将作为参数我的输入表,输出表和一个变量列表。我的变量列表显示为一个参数,为此我使用空格字符作为分隔符。 我的宏应该将我的列表分隔成nbvar宏 - 变量,它将包含我的(SAS)变量的名称。然后,我使用datastep将我的(SAS)变量从其原始字符格式输入到数值中。SAS宏:循环来创建变量

这里是我的一段代码:

%macro convert_car_to_num(input,output,listvar); 

/* First I split my list into nbvar variables named var&i 
%qscan to avoid macro resolution of names, not really necessary here 
but still works fine. My delimiter is space character, hence 
%str() in the %qscan*/ 

%let nbvar=%sysfunc(countw(&listvar)); 
%do i = 1 %to &nbvar; 
    %let var&i=%qscan(&listvar,&i,%str()); 
%end; 

/*Here is my data step. &&var&i_num is resolved just fine*/ 
data &output; 
set &input; 
%do i = 1 %to &nbvar; 
    &&var&i.._num = input(&&var&i,BEST16.); 
%end; 
run; 

%mend; 

由于& &变种&我.._ NUM和& & VAR &我都解决了,我希望我的代码工作,但我的日志显示:

varname_num

解析名称“varname”加下划线。我发现后有一点点:

错误180-322:语句无效或使用不正确的顺序。

这通常是错位分号的标准错误。然而,我知道我的宏观变量都解决了,因为MPRINT显示:

MPRINT(CONVERT_CAR_TO_NUM):(varname的,BEST16)varname_num =输入

注:受宏观变量 “VAR26” 行产生。

MPRINT(CONVERT_CAR_TO_NUM):run;

其中,varname是我列表中第26个变量的正确名称,表示分辨率工作得很好。

为了让我更无法理解的,同一段代码,我将表明:

&&var&i.. = input(&&var&i,BEST16.); 

DOES编译,即使它不符合预期的结果结束(变量仍然是char )。

类似地,用相同的代码:

&&var&i.._num = &&var&i; 

不任一编译。

我也测试了改变我的宏观变量的名称num_ & & &变种i或n & &变种&我,甚至是第一次声明一个宏观变量“名”,其中将包括& & VAR &我,都是为了同样的效果。不选择与初始变量相同的名称似乎会导致代码显示180错误。

我想问题在于试图声明一个变量,知道我写的以前和类似的一段代码确实有效,datastep是一个比较(将变量列表中的缺失值也变为零) :

data &output; 
set &input; 
    %do i = 1 %to &nbvar; 
     if &&var&i = . then &&var&i = 0; 
    %end; 
run; 

但对于这种同一段代码,如果我尝试(使用任何名称再次,对于这个问题)创建一个新的变量,写作:

if num_&&var&i = . then &&var&i = 0; 

我发现我自己的解决名称再次加下划线,但现在指向以下错误:

ERROR 22-322:语法错误,在需要下列之一:,!!,&,(,*,**,+, - ,/,;,<, < =,<> =,>,> =,AND,EQ,GE,GT,IN,LE,LT,MAX,MIN,NE,NG,NL,NOTIN,OR [,^ =,{,|,||, ,〜=。

我一直在抓我的头,浏览网无济于事,所以谢谢你的想法。

回答

1

这是SAS未能自动解除引用值的问题。我了解到的规则是,如果您的SAS代码(由MPRINT显示)看起来有效,但您遇到错误,请尝试不加引号。

在你的情况下,更改为:

%unquote(&&var&i.._num) = input(&&var&i,BEST16.); 

使代码工作。当然,根据你的评论,你可能不需要%qscan这是引入有问题的引用字符。如果您将其更改为%scan,则不需要%unquote()它,因为它不会被首先引用。

也同意@Foxer的方法使用单个宏变量将i_th变量存储在列表中。也会建议制作这些%局部变量以避免冲突。可能是这样的:

%macro convert_car_to_num(input,output,listvar); 
    %local i vari; 

    data &output; 
    set &input; 
    %do i = 1 %to %sysfunc(countw(&listvar,%str())); 
     %let vari=%scan(&listvar,&i,%str()); 
     &vari._num=input(&vari,best16.); 
    %end; 
    run; 

%mend; 
+0

这正是我所寻找的解释。我希望使用%qscan时要格外小心,以确保潜在的其他用户不会与奇怪的名称“混淆”,但我没有完全意识到%qscan实际引用的含义,以避免任何意外的解决方案。 – Alan

+0

独特的临时变量的想法是一个很好的想法,但实际上我需要在循环之外的所有变量。至于做出一个独特的循环: %do i = 1%to%sysfunc(countw(&listvar,%str())); 我确实认为它好得多,但由于我可能与其他人共享这些宏,我更喜欢他们分解这些步骤,以免混淆人并使其更容易用于其他目的。 – Alan

+0

我仍然有一个询问:如果我确实需要%qscan来避免不良分辨率,我仍然可以使用: %unquote(&& var&i .._ num) 我的猜测是否定的,因为不加引用会导致潜在的不需要解析度。我错了吗 ?如果不是,我将如何处理? (真相被告知这是一个混乱的情况,我只是试图完全理解宏的工作以及可用于防止意外结果的工具)。 不过,非常感谢您的第一个正确的答案 – Alan

0

下面给出你需要的东西吗?我的猜测是,你有太多的事情在不同的if-then-do声明:

%macro new(input,output,listvar); 
data &output; set &input; 
%do i=1 %to %sysfunc(countw(&listvar.)); 
    %let var=%scan(&listvar.,&i.); 
     var&i._num = input(&var.,BEST16.); 
%end; 
run; 
%mend; 

%new(have,want,&listvar.); 

下面也可以做你想做的,如果你想创建的每个变量中的单个宏变量你遍历(虽然在这种情况下,它可能不值得,但只是显示为其他应用的另一个有用的方法):

** put variables into dataset **; 
proc sql noprint; 
    create table vars 
    as select name,type 
    from dictionary.columns 
    where upcase(libname)="WORK" and 
     upcase(memname)="HAVE" and 
     type = "char"; 
quit; 

** create total count and separate macro variable for each variable **; 
data _null_; set vars end=last; 
    by name; 
    i+1; 
    call symputx('name'||strip(put(i,8.)), name); 
     if last then call symputx('count',i); 
run; 

%put &count.; 
%put &name1.; 
%put &name2.; 
%put &name3.; 

** loop over each variable using the total count **; 
%macro new(input,output); 
data &output; set &input; 
%do i=1 %to &count.; 
    &&name&i.._num = input(&&name&i,BEST16.); 
%end; 
run; 

%mend; 

%new(have,want); 
+0

您的回答是正确的,因为错误的来源是由%qscan func实现的引用,因为%scan对我的直接需求工作得很好。您的简短版本是我的目标是为自己编写,但由于各种原因(主要是我可能会共享代码,并且我确实需要为每个变量分别设置一个宏变量),我倾向于保留更长的时间,但对于其他用户可能更清晰。 我打算看看你的sql版本,但在我看来,我不能选择我想输入哪些变量,这是我需要的核心(某些var在我的初始数据集中是正确的char)。 – Alan

+0

我可以找到方法,例如首先创建一个只包含我想输入的var的数据集,但是我发现它无法使用即用型解决方案的目的。 不过,感谢所有的想法和评论 – Alan