SAS - 调用执行
我已经使用 callexecute
调用宏来逐行写入输出文件,但它只写入了输出文件中的最后一行。
%Macro INPS(ipdsn);
filea = &ipdsn;
%put MACRO: ipdsn -->: &ipdsn;
%put MACRO: ipdsn -->: filea;
newHostDSN = prxchange (re_iPat, -1, trim(&filea));
do i=1 to f_count;
set Var_Patterns(keep=Pat_Name Pat_Value) point=i nobs=f_count;
re_vPat = cats('s/\$', Pat_Name, '(\.)?/', Pat_Value, '/i');
newHostDSN = prxchange (re_vPat, -1, trim(newHostDSN));
end;
%Mend;
data _null_;
files = 'AAAAAAAAAAAAAA,BBBBBBBBBBBBBB';
f_count = countw(files);
do i=1 to f_count;
file = scan(files, i, ',');
put 'DATA STEP: ipdsn -->: ' file;
CALL EXECUTE (cats( '%INPS(', file, ');' ));
end;
run;
输出:
DATA STEP: ipdsn -->: AAAAAAAAAAAAAA
MACRO: ipdsn -->: AAAAAAAAAAAAAA
MACRO: ipdsn -->: filea
DATA STEP: ipdsn -->: BBBBBBBBBBBBBB
MACRO: ipdsn -->: BBBBBBBBBBBBBB
MACRO: ipdsn -->: filea
我想将数据步骤值(文件名)存储在宏(filea)内的变量中,并将其用于宏中的其他验证(newhostdsn 和 do)。知道我该怎么做吗?
I have used call execute
to call a macro to write the output file line by line but it has written only the last line in the output file.
%Macro INPS(ipdsn);
filea = &ipdsn;
%put MACRO: ipdsn -->: &ipdsn;
%put MACRO: ipdsn -->: filea;
newHostDSN = prxchange (re_iPat, -1, trim(&filea));
do i=1 to f_count;
set Var_Patterns(keep=Pat_Name Pat_Value) point=i nobs=f_count;
re_vPat = cats('s/\
output:
DATA STEP: ipdsn -->: AAAAAAAAAAAAAA
MACRO: ipdsn -->: AAAAAAAAAAAAAA
MACRO: ipdsn -->: filea
DATA STEP: ipdsn -->: BBBBBBBBBBBBBB
MACRO: ipdsn -->: BBBBBBBBBBBBBB
MACRO: ipdsn -->: filea
I want to store the data step value (file name) in a variable inside macro(filea) and use it for other validation in macro (newhostdsn and do). any idea how can i do this?
, Pat_Name, '(\.)?/', Pat_Value, '/i');
newHostDSN = prxchange (re_vPat, -1, trim(newHostDSN));
end;
%Mend;
data _null_;
files = 'AAAAAAAAAAAAAA,BBBBBBBBBBBBBB';
f_count = countw(files);
do i=1 to f_count;
file = scan(files, i, ',');
put 'DATA STEP: ipdsn -->: ' file;
CALL EXECUTE (cats( '%INPS(', file, ');' ));
end;
run;
output:
I want to store the data step value (file name) in a variable inside macro(filea) and use it for other validation in macro (newhostdsn and do). any idea how can i do this?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
它将立即执行。
致电EXECUTE 文档
使用您的示例:
日志输出:
It will execute immediately.
CALL EXECUTE documentation
Using your example:
Log Output:
这里的问题是您并没有真正理解 SAS 变量(和宏变量)的工作原理。
CALL EXECUTE
的作用是告诉 SAS 在数据步骤完成后立即执行callexecute
内的代码。您的示例代码包含数据步骤行,但它们不在数据步骤内 - 它们只是在开放代码内执行。将它们放入数据步骤中,它们就会正常执行。这会将正确的值放入
newHostDSN
中。现在,还有其他重要的事情:宏语句确实在运行“之前”执行。如果您的宏比较复杂,这一点非常重要。
请参阅以下代码。
保留注释掉的部分,运行两次。第一次,它会起作用 - 除非你会收到一大堆警告
&age
不存在 - 但它会正确地将各种内容放入日志中,年龄 12,年龄 13,等等。第二次就不会做同样的事情了!您不会收到有关
&age
不存在的警告 - 但每次执行都将具有相同的年龄,即早期运行的最后一个年龄。这是因为,第一次,它不会将
&age
符号转换为任何内容 - 它将其保留为&age
,因为还没有值。这样,当proc sql; 时select into
创建&age
,它有效 - 因为这样它就解决了。然而,第二次,
&age
存在!这意味着当它创建调用执行
时,它就能够立即解析&age
- 无需等待。因此,您将得到 15(任何运行之前&age
的当前值)。这不是您想要的!现在取消注释
%symdel Age;
。这会删除年龄符号,使每次运行都像第一次一样 - 它可以工作,但有关&age
的警告无法解决。你该如何解决这个问题?嗯,一种方法是使用
%symdel
语句。这会删除年龄,因此您确信它不会过早解决。这并不是最好的方法,但它确实有效。更好的是使用
%nrstr
,它对解析器“隐藏”年龄。现在,年龄直到稍后才得到解决 - 在
调用执行
调用宏之后。第三,您可以在
调用执行
中执行相同的操作!这将从
调用执行
解析器中隐藏整个宏。这在计划中是最简单的——一切都会在预期的时间稍后发生。您还可以使用
callexecute
以外的其他方法来执行宏 - 例如,您可以使用我的select into
语法来创建一个宏变量来执行所有执行。这里的
namelist
宏变量实际上包含所有宏执行的文本 - 因此只需在开放代码中运行该宏变量即可调用它们,就像您将它们全部键入一样。这有优点(同时执行)和缺点(特别是限制为 60k 字符)。您还可以将调用写入文本文件并%include
该文本文件。为什么你的例子没有失败?因为它使用的宏参数不是宏变量,这就是原因。如果 ipdsn 作为单独的宏变量而不是参数存在,它将被解析 - 并且无法工作,这最有可能是您在实际中看到的情况例子。
The issue here is that you're not really understanding how SAS variables (and macro variables) work.
What
CALL EXECUTE
does is tells SAS to execute the code inside thecall execute
immediately after the data step completes. Your example code contains data step lines, but they're not inside a data step - they're just executed inside open code. Put them in a data step, and they'll execute fine.That puts the right value inside
newHostDSN
.Now, there is something else important: the macro statements do execute "before" the run. This is pretty important if your macro is more complicated.
See the following code.
Leaving the commented out part out, run it twice. The first time, it will work - except you'll get a whole bunch of warnings that
&age
does not exist - but it will correctly put various things to the log, age 12, age 13, et cetera.The second time, it won't do the same thing! You won't get the warning about
&age
not existing - but every single one of the executions will be the same age, the last age from the earlier run.That is because, the first time, it's not converting
&age
the symbol into anything - it leaves it as&age
, since there's no value yet. That way, when theproc sql; select into
creates&age
, it works - because then it's resolved.However, the second time,
&age
exists! That means that when it creates thecall execute
, it is able to resolve&age
right then - no need to wait. So you get 15 (the present value of&age
before anything runs) substituted in. That's not what you want!Now uncomment
%symdel age;
. That deletes the age symbol, making every run like the first - it works, but with the warnings about&age
not resolving.How can you fix this? Well, one way is to use that
%symdel
statement. That deletes age, so you know for sure it won't be prematurely resolved. That's not really the best way, but it works.Better, is to use
%nrstr
, which "hides" age from the parser.Now, age is not resolved until later on - after the macro has been called by the
call execute
.Third, you can do the same thing inside the
call execute
!This would hide the whole macro from the
call execute
parser. This is easiest in the scheme of things - everything happens later, at the expected time.You also could use something other than
call execute
to execute your macros - for example, you could use myselect into
syntax to create a macro variable to do all of the executions.Here the
namelist
macro variable actually contains the text for all of the macro executions - so just running that macro variable in open code calls them all as if you'd typed them all out. This has advantages (simultaneous execution) and disadvantages (limited to 60k characters in particular). You could also write the calls out to a text file and%include
that text file.Why didn't your example fail? Because it was using a macro parameter that wasn't a macro variable, that's why. If
ipdsn
had existed as a separate macro variable, not a parameter, it would be resolved - and fail to work, which is most likely what you're seeing in your real example.