PROC SQL "SELECT INTO" 不创建宏变量

PROC SQL "SELECT INTO" does not create macro variable

我 运行 遇到了使用 proc sql select into : 逻辑创建宏变量的问题。代码似乎非常简单,但我应该注意到导致问题的宏是从其他几个宏调用的。

这是导致问题的代码段。

%do year_num=1 %to 5;
    %if &year_num=1 %then %let min_date = %eval(&max2.-17);
    %else %let min_date = %eval(&min_date.-12);

    data tmp;
    set bf(firstobs=&min_date obs=%eval(11+&min_date));
    run;

    data tmp2;
    set bf(firstobs=%eval(5+&min_date) obs=%eval(7+&min_date));
    run;

    proc sql noprint;
    select sum(EP), sum(ExpectedLoss)
      into :totep, :totexpt
    from tmp;

    select sum(EP), sum(ExpectedLoss)
      into :partep, :partexpt
    from tmp2;
    quit;

    %put _LOCAL_;

    *Other code...;

%end;

由于某些原因,变量 toteptotexptparteppqrtexpt 没有被创建,我在日志中找不到任何有用的信息这可能会阐明情况。

这是日志的一部分,包括 _LOCAL_.

的输出
SYMBOLGEN:  Macro variable YEAR_NUM resolves to 1
SYMBOLGEN:  Macro variable MAX2 resolves to 96
MPRINT(BFMETHOD):   data tmp;
SYMBOLGEN:  Macro variable MIN_DATE resolves to 79
SYMBOLGEN:  Macro variable MIN_DATE resolves to 79
MPRINT(BFMETHOD):   set bf(firstobs=79 obs=90);
MPRINT(BFMETHOD):   run;
MPRINT(BFMETHOD):   data tmp2;
SYMBOLGEN:  Macro variable MIN_DATE resolves to 79
SYMBOLGEN:  Macro variable MIN_DATE resolves to 79
MPRINT(BFMETHOD):   set bf(firstobs=84 obs=86);
MPRINT(BFMETHOD):   run;
MPRINT(BFMETHOD):   proc sql noprint;
MPRINT(BFMETHOD):   select sum(EP), sum(ExpectedLoss) into :totep, :totexpt from tmp;
MPRINT(BFMETHOD):   select sum(EP), sum(ExpectedLoss) into :partep, :partexpt from tmp2;
MPRINT(BFMETHOD):   quit;
BFMETHOD I 12
BFMETHOD DSET all
BFMETHOD SEAS_MIN 0.6
BFMETHOD YEAR_NUM 1
BFMETHOD SEAS_MAX 1.66666666666666
BFMETHOD MIN_DATE 79

data tmp;     set bf(firstobs=79 obs=90);     run;

NOTE: There were 12 observations read from the data set WORK.BF.
NOTE: The data set WORK.TMP has 12 observations and 35 variables.
NOTE: Compressing data set WORK.TMP increased size by 100.00 percent.
      Compressed is 2 pages; un-compressed would require 1 pages.
NOTE: DATA statement used (Total process time):
      real time           0.00 seconds
      cpu time            0.00 seconds

109       +    data tmp2;     set bf(firstobs=84 obs=86);     run;

NOTE: There were 3 observations read from the data set WORK.BF.
NOTE: The data set WORK.TMP2 has 3 observations and 35 variables.
NOTE: Compressing data set WORK.TMP2 increased size by 100.00 percent.
      Compressed is 2 pages; un-compressed would require 1 pages.
NOTE: DATA statement used (Total process time):
      real time           0.00 seconds
      cpu time            0.00 seconds


109       +                                                             proc sql noprint;
109       +                                                                                   select sum(EP), sum(ExpectedLoss)       into :totep, :totexpt     from tmp;
109       +
     select sum(EP), sum(ExpectedLoss)       into :partep, :partexpt     from tmp2;
109       +
     quit;
NOTE: PROCEDURE SQL used (Total process time):
      real time           0.00 seconds
      cpu time            0.00 seconds

如果我从 proc sql 语句中删除 noprint,则会输出正确的值,所以我不确定发生了什么。任何帮助将不胜感激。

您的问题几乎可以肯定与执行时间有关。特别是在使用 call execute 时,您很容易 运行 遇到计时问题,即 SAS 处理器在为宏变量赋予有用值之前对其进行解析。

这是一个简化的例子。我专门制作了一个数据集,以便您可以看到何时发生(这不是必要的步骤,也不会影响示例,它只是一个有用的日志条目)。

注意当宏 运行 单独运行时,一切都如您所愿;但是当它是 运行 和 call execute 时,%put 在 宏实际执行之前执行

第三个示例使用 %nrstr 强制 SAS 在实际 运行 之前不尝试解析宏 - 这导致它被正确提交。

实际上,第一个 call execute 版本让 SAS 处理宏文本,然后将其提交给 sas.exe - 你并不真的想要。添加 %nrstr 可以解决这个问题。

%macro do_something();
    %local mlist;
    data class_m;
      set sashelp.class;
      where sex='M';
    run;

    proc sql;
      select name into :mlist separated by ' '
      from class_m;
    quit;

    %put &=mlist;
%mend do_something;

%put Macro run on its own;
%do_something;


%put Macro run via call execute;
options mprint symbolgen;
data _null_;
  set sashelp.class;
  if _n_=1 then call execute('%do_something()');
  stop;
run;

%put Macro run with nrstr and call execute;
data _null_;
  set sashelp.class;
  if _n_=1 then call execute('%nrstr(%do_something())');
  stop;
run;