楼主: Tigflanker
4491 6

[问答] 求助data步中的宏返回值传递 [推广有奖]

  • 8关注
  • 18粉丝

副教授

49%

还不是VIP/贵宾

-

威望
0
论坛币
2321 个
通用积分
9.9128
学术水平
179 点
热心指数
194 点
信用等级
167 点
经验
27443 点
帖子
622
精华
0
在线时间
851 小时
注册时间
2011-3-27
最后登录
2023-5-14

楼主
Tigflanker 发表于 2014-7-22 10:53:41 |AI写论文
100论坛币
求助大家个问题:

是这样,我做个小宏,目的是返回一个计算好的值串,然后在存到某个data步中的某个变量中。

我初步的打算是这样:

  1. %macro count(in=adsl,where=);
  2.   %global countx;
  3.   proc sql noprint;
  4.     select count(distinct subjid) into: count from &in.
  5.     where &where.
  6.     ;       
  7.   quit;
  8. &count. (%sysfunc(round(&count. * 100 / 20,.1)))
  9. %mend;
复制代码

宏中的“&count. (%sysfunc(round(&count. * 100 / &N.,.1)))”为返回值,本来打算这样用:

  1. data out1;
  2.   set out1 end = last;
  3.   output;
  4.   
  5.   if last then do;
  6.         col = reslove("%count(in=adsl,where=age < 65);");
  7.         output;
  8.   end;
  9. run;
复制代码

结果失败。。。。。。。

换成这样:

  1. %macro count(in=adsl,where=);
  2.   %global countx;
  3.   proc sql noprint;
  4.     select count(distinct subjid) into: count from &in.
  5.     where &where.
  6.     ;       
  7.   quit;
  8. %let countx = &count. (%sysfunc(round(&count. * 100 / &N.,.1)));
  9. %mend;
复制代码

然后这样用:

  1. data out1;
  2.   set out1 end = last;
  3.   output;
  4.   
  5.   if last then do;
  6.     call execute('%count(in=adsl,where=age < 65);');
  7.         col = symget("countx");
  8.         id1 = 1;
  9.         id3 = 6;
  10.         output;
  11.        
  12.     call execute('%count(in=adsl,where=age >= 65);');
  13.         col = symget("countx");
  14.         id1 = 1;
  15.         id3 = 7;
  16.         output;
  17.   end;
  18. run;
复制代码

依然失败。。。。。。。。。

所以我想问两个问题:

1. A计划中,reslove给我返回的是宏中的SQL过程Code,而不是我预留下来的值,我想问下为什么?

2. B计划中,我看到call execute是在data步的编译过程中执行的,所以我两个条件age < 65 and age >= 65的宏变量countx的值是一样的;我想问为什么?

谢谢。

最佳答案

pobel 查看完整内容

1. 宏执行的产品是SAS代码。楼主的宏执行后,PROC SQL语句,以及后面的 n(%) 都会作为宏的结果返回。 data test; code="%count(in=adsl,where=age < 65);"; put code=; run; 如果是需要宏只返回最后的n(%),那就需要前面的整个计算都用宏语句来完成。 2. 首先,call execute语句中对宏的调用不是在编译过程中执行的,而是: a. 其中的宏语句,如%LET语句,是在data步执行过程中为countx赋值的; b. 其中的SQL ...
关键词:data步 Data 返回值 proc sql Distinct
Bye SAS.
若有缘,能重聚。

沙发
pobel 在职认证  发表于 2014-7-22 10:53:42
1.
宏执行的产品是SAS代码。楼主的宏执行后,PROC SQL语句,以及后面的 n(%) 都会作为宏的结果返回。
data test;
   code="%count(in=adsl,where=age < 65);";
  put code=;
run;

如果是需要宏只返回最后的n(%),那就需要前面的整个计算都用宏语句来完成。

2.
首先,call execute语句中对宏的调用不是在编译过程中执行的,而是:
a. 其中的宏语句,如%LET语句,是在data步执行过程中为countx赋值的;
b. 其中的SQL语句,是在data out1这个data步执行完毕后才开始执行。也就是说,宏对COUNTX的“赋值”,其实是在SQL语句执行之前。

另外,%let语句为countx赋值时应该借用了已经存在的宏变量count,也就是之前的某个步骤中产生的宏变量count。楼主可以在data out;语句之前加%symdel count/nowarn; 来验证。
已有 1 人评分论坛币 学术水平 热心指数 信用等级 收起 理由
Tigflanker + 5 + 3 + 3 + 3 应该已讲解清楚,回头细看,谢谢!!

总评分: 论坛币 + 5  学术水平 + 3  热心指数 + 3  信用等级 + 3   查看全部评分

藤椅
zhanglianbo35 发表于 2014-7-22 12:56:48
大概改成这样的就行了,宏的思路没必要弄得很复杂,
%macro count(in=, where= );
  proc sql noprint;
  select count(distinct subjid) into: count from &in.
  where %bquote(&where)
     ;        
  quit;
%let countx= &count. (%sysfunc(round(%sysevalf(&count  * 100 / 20) ,.1)));
data out1;
   set out1 end = last;
   output;
   if last then do;
     col = symget(countx);
     output;
   end;
%mend;
%countx(in=adsl, where= age < 65)
已有 1 人评分论坛币 学术水平 热心指数 信用等级 收起 理由
Tigflanker + 5 + 3 + 3 + 3 谢谢,不过我还是希望小巧的嵌入式宏。

总评分: 论坛币 + 5  学术水平 + 3  热心指数 + 3  信用等级 + 3   查看全部评分

板凳
zhanglianbo35 发表于 2014-7-22 13:00:26
where= age >5 因为有大于号(特殊字符),得用%bquote mark掉,然后在宏的执行阶段起作用
已有 1 人评分论坛币 学术水平 热心指数 信用等级 收起 理由
Tigflanker + 5 + 3 + 3 + 3 整体作为宏参返回布尔结果,仅有一个运算符.

总评分: 论坛币 + 5  学术水平 + 3  热心指数 + 3  信用等级 + 3   查看全部评分

报纸
Tigflanker 发表于 2014-7-22 19:24:36
pobel 发表于 2014-7-22 13:53
1.
宏执行的产品是SAS代码。楼主的宏执行后,PROC SQL语句,以及后面的 n(%) 都会作为宏的结果返回。
da ...
谢谢。

换句话说,就是如果一个宏里面交杂有过程步或者data步,

那么对于返回值,他就连同其他语句作为宏编译和执行(宏语句)过后的产物;

对于execute执行就是他还是会等到所在data步的结尾来执行收集到的execute命令。

是这样么?

地板
pobel 在职认证  发表于 2014-7-23 07:20:47
Tigflanker 发表于 2014-7-22 19:24
谢谢。

换句话说,就是如果一个宏里面交杂有过程步或者data步,
是这样的。

宏的任务就是产生SAS语句,再交回到SAS执行。这里的SAS语句是指那些除了宏语句之外的所有字符。比如%let,%do,%if之类的宏语句,会在宏执行时“用掉”。剩下的包括过程步,data步的代码,abcdefghi之类的字符,甚至和宏语句无关的分号,都会作为宏执行的结果,一同返回。

对于call execute(),我一直把它理解成‘data步中的宏’,它可以根据变量的值来构建代码。call execute()参数中的SAS语句(data步,proc步等)都会放到其所在的data步之后依次执行。而其中如果涉及到宏的语句,包括宏的调用,其执行时间需视情况而定。

7
pobel 在职认证  发表于 2014-7-23 07:56:35
Tigflanker 发表于 2014-7-22 19:24
谢谢。

换句话说,就是如果一个宏里面交杂有过程步或者data步,
是这样的。

宏的任务就是产生SAS语句,再交回到SAS执行。这里的SAS语句是指那些除了宏语句之外的所有字符。包括proc步,data步,abcde,12345,或者是和宏语句无关的分号等等。

对于call execute(), 个人理解就是data步中的宏,它可以根据变量的值来构建代码。其参数中的SAS语句,例如proc步或data步,会放到call execute所在的data步之后依次执行。如果其参数还涉及到了宏语句,包括宏调用,那执行情况需要视情况而定。
已有 1 人评分论坛币 学术水平 热心指数 信用等级 收起 理由
Tigflanker + 5 + 3 + 3 + 3 明白了,谢谢:)

总评分: 论坛币 + 5  学术水平 + 3  热心指数 + 3  信用等级 + 3   查看全部评分

您需要登录后才可以回帖 登录 | 我要注册

本版微信群
加好友,备注cda
拉您进交流群
GMT+8, 2025-12-31 11:39