【问题标题】:Two variables in a macro [SAS]宏中的两个变量 [SAS]
【发布时间】:2015-08-05 23:05:12
【问题描述】:

所以,我想要一个包含其他宏的宏。

代码如下:`

    proc sql NOPRINT ; 
        select id into :l_id separated by ' ' from work.AMOSTRACHU;
        select count(*) into :nr_reg separated by ' ' from tdata.work.AMOSTRACHU;
    quit;

    * check;
    %put l_id=&l_id nr_reg=&nr_reg;


    %macro ciclo_first();
    %do n=1 %to &nr_reg; 
    %let ref=%scan(&l_id,&n);
    %put ref=&ref;


    proc sql; 
    select recetor into : lsus&ref separated by ' ' from tdata.5pct_&ref;
    select count(*) into :nrsus&ref separated by ' ' from tdata.5pct_&ref;
    quit;

    %put lsus&ref=&lsus&ref;
    %put nrsus&ref=&nrsus&ref;

    %MACRO CICLO_PF_SUSref();
%do n=1 %to &nrsus&ref %by 1;
%let sus=%scan(&lsus&ref,&n);
%put sus=&sus;
%LET I = %EVAL(14);
%DO %WHILE (&I<=24);

*my code (depends on &i and &sus)* (works fine alone) 

%LET I = %EVAL(&I+1);

%END;
%END;
%MEND;
%CICLO_PF_SUSref;

%MACRO CICLO_PF_SUS_CSRANK();
%do n=1 %to &nrsus&refm %by 1;
%let sus=%scan(&lsus&ref,&n);
%put sus=&sus;

%CICLO_PF_SUSPEITOSrefmsisdn;

    %CICLO_PF_SUS_CSRANK;

我的代码(仅取决于 &sus)/

%END;
%MEND;
%CICLO_PF_SUS_CSRANK;

    %end;
    %mend;
    %ciclo_first;`

我认为主要的问题在于这部分:

%put lsus&ref=&lsus&ref;
    %put nrsus&ref=&nrsus&ref;

关于那个的错误是:

在 %EVAL 函数或 %IF 条件中找到一个字符操作数 其中需要数字操作数。条件是: &nrsus&参考

我怎样才能改变它才能工作?我知道依赖两个的东西是没有意义的,比如&nrsus&ref。

第一个警告和错误出现在这里:

ref=15
WARNING: Apparent symbolic reference LSUS not resolved.
lsus15=&lsus15 WARNING: Apparent symbolic
reference NRSUS not resolved.
nrsus15=&nrsus15 ERROR: Expected semicolon not
found.  The macro will not be compiled.

我该如何解决这个问题?没有想法,使这个宏功能化以避免运行 100 次真的很有用。

更新 [06.08.2015]

我有一张有 100 个数字的表格,在

'work.amostrachu'.

我创建了宏 ciclo_first 以便为该列表运行其他 2 个宏。因为,如果我用我想要的数字手动替换&amp;ref,它就可以正常工作。

假设'work.amostrachu'有:

ID 1 2 3 (...) 直到 n=100

那么,这部分:

 proc sql; 
         select recetor into : lsus&ref separated by ' ' from work.5pct_&ref;
         select count(*) into :nrsus&ref separated by ' ' from work.5pct_&ref;
         quit;

我想获取work.5pct_&amp;ref 的“recetor”列上的元素。

对于ID=1,我将获得lsus1,例如由3个数字(124,564,859)组成

然后,%MACRO CICLO_PF_SUSref(); 将输入这 3 个数字(可能是 4 或 5 或其他数字)。 (在这里,我可能会错误地从 'work.5pct_&amp;ref 调用我想要的元素列表)。

那么,前一个宏的输出就是这个宏的输入:%MACRO CICLO_PF_SUS_CSRANK。 这就是全部。

%MACRO CICLO_PF_SUSref()%MACRO CICLO_PF_SUS_CSRANK 工作正常,只要我用 id 替换 &amp;ref。这就是为什么我试图创建一个宏来为初始列表运行这两个宏。如果您有最好的想法,我将不胜感激。

所以,我想要一些可以让我运行这两个宏(%MACRO CICLO_PF_SUSref() 和 `%MACRO CICLO_PF_SUS_CSRANK)的东西:

 proc sql NOPRINT ; 
                select id into :l_id separated by ' ' from work.AMOSTRACHU;
                select count(*) into :nr_reg separated by ' ' from tdata.work.AMOSTRACHU;
            quit;

[更新 10.08.2015]

好的,只需阅读建议的答案并进行处理。

我有一个列表,其中包含 100 个客户的标识(数字),让我们调用每个客户:ref。那是在 WORK.AMOSTRACHU 上。

我编写了以下代码并且它有效,并将帮助我向您解释我想要什么:

proc sql NOPRINT ; 
    select id into :l_id separated by ' ' from work.AMOSTRACHU;
    select count(*) into :nr_reg separated by ' ' from work.AMOSTRACHU;
quit;

* check;
%put l_id=&l_id nr_reg=&nr_reg;


%macro lista_ent();
%do n=1 %to &nr_reg; 
%put n=&n;
%let ref=%scan(&l_id,&n);
%put ref=&ref;

proc sql; 
select recetor into :listae&ref SEPARATED BY ' ' from work.e5pct_id&ref;
select count(*) into :nre&ref separated by ' ' from work.e5pct_id&ref;
quit;

%end;
%mend;
%lista_ent;

将显示前 3 个案例的输出(共 100 个,work.amostrachu 中的起始列表),它是 SAS 中的结果部分:

Recetor 
507
723
955
-page break- 
3
-page break-
380
500
675
977
984
-page break-
5
-page break-
200
225
351
488
698
781
927
-page break-
7

所以,我有数据 work.e5pct_id&ref 的“recetor”列的“值”以及每个 ref 有多少个值。 (我已经向您展示了前 3 个裁判的结果,但我有 100 个)。

现在,第一个宏:

%MACRO CICLO_M_PF_ref();
%local me n i;
%do n=1 %to nre&ref %by 1;
%let me=%scan(listae&ref,&n);
%put me=&me;
%LET I = %EVAL(14);
%DO %WHILE (&I<=24);

proc sql; 
create table work.smthng_&I as
select * from 
work.wtv&I
WHERE A=&me OR B=&me;RUN; 

PROC APPEND
DATA=work.smthng_&I
BASE=work.pf_&me
FORCE;
RUN; 


%LET I = %EVAL(&I+1);

%END;
%END;
%MEND;

%CICLO_M_PF_ref;

我对 & 和 && 的所有疑问都在这里。

所以,有了数据:我有我的第一个 ref,其“recetor”列的结果是

Recetor 
    507
    723
    955
    -page break- 
    3

所以,我想为每个值运行该代码。首先是“507”,然后是“723”,然后是“955”,我想对所有裁判都这样做。

因此,当宏完成运行我的这 3 的代码时,我希望宏跳到第二个参考,然后运行我的代码以获取第二个参考的“recetor”列的值:380,500,675,977 和 984。

我使用了这个代码:

 proc sql; 
    select recetor into :listae&ref SEPARATED BY ' ' from work.e5pct_id&ref;
    select count(*) into :nre&ref separated by ' ' from work.e5pct_id&ref;
    quit;

因为每个 ref 都有不同的值,并且它们的数量可能不同,就像我向您展示的那样。所以,这要告诉宏运行它nre&amp;ref 次以及列表中的所有值listae&amp;ref

错误如下:

错误:在 %EVAL 函数或 %IF 中找到字符操作数 需要数字操作数的条件。条件是: nre&ref 错误:%DO T 循环的 %TO 值无效。错误:宏 CICLO_M_PF_REF 将停止执行。

【问题讨论】:

  • 您通常不会嵌套宏。我很难跟上,你能提供示例数据和预期输出吗?
  • 首先我有一个包含 100 个客户的列表。我想在他们身上运行 %MACRO CICLO_PF_SUS&ref。然后,在这个宏(100 个表)的输出上,我用一些查询运行另一个宏。这两个宏在“大宏”之外可以正常工作。
  • 同意 Reeza。嵌套宏定义是个坏主意。嵌套宏调用很好。要解决您的错误消息,请尝试 &&nrsus&ref 和 &&lsus&ref。
  • 您有%do ... ; 语句错过了%end;%macro ... ; 语句错过了%mend;。如果你解决了这个问题并正确缩进你的代码,如果你仍然有错误,我会看看。
  • Dirk Horsten,实际上它们并没有丢失,我只是忘记粘贴宏的结尾部分。我会更新这个问题,试图更好地解释我想要什么,并欢迎关于如何解决这个问题的新想法。

标签: variables macros sas


【解决方案1】:

我无法完全遵循您想要的输出和宏,但这里有一些我注意到的事情。

  1. 您的宏都没有参数。如果您更改宏以获取参数,您可以单独调用它们,这可能有助于简化您的流程。

我想你想要这样的东西:

%macro def1(param1);
...
%mend;

%macro def2(param2);
...
%mend;

%macro execute();

%do i=1 to 100;
   %def1(param1);
   %def2(param2);
%end;
%mend;

这似乎仍然有点尴尬,所以如果你能用你的数据解释你的过程,总体上可能会有更好的方法。

【讨论】:

  • 丽莎,谢谢你的帮助。我尝试使用它,并写了一个更新(10.08.2015),其中包含更多示例,以便更好地向您解释我想从数据中获得什么。
【解决方案2】:

我看到了一些您可以解决的问题,但没有测试数据很难评估。

  • 当试图显示宏变量 x&i 的值时,您需要加倍前缀 &。因此,如果 I=1 且 X1 = FRED,则 &&x&i = FRED。
  • 从 SQL 将值推入宏变量时,使用自动宏变量 SQLOBS 来获取记录计数。无需再次运行查询即可获得计数。
  • 您不能在多个宏变量中选择 COUNT(*)。 SQL 只会返回一个计数。
  • SAS 数据集或变量名称不能以数字开头 (tdata.5pct_&ref) 或包含句点 (tdata.work.AMOSTRACHU)。
  • 不要嵌套宏定义。您可以嵌套调用,但嵌套 定义只会导致混乱。

您的实际嵌套宏没有多大意义。引入的这个变量是什么?它似乎是一个常数。

为什么不将它们编码为外部宏的一部分?如果只在一个地方调用它们,则不需要将它们分开。

  • 如果确实嵌套它们,请确保将本地宏变量定义为本地,以防止覆盖可能存在于外部宏范围中的同名宏变量的值。例如,您的 %DO 循环的 N 循环变量。

首先定义你的子程序宏。

%MACRO CICLO_PF_SUSref(ref_list);
* CICLO_PF_SUSref ;
  %local n sus; 
  %do n=1 %to %sysfunc(countw(&ref_list,%str( )));
    %let sus=%scan(&ref_list,&n);
    %put NOTE: &sysmacroname N=&n SUS=&sus;
  %end;
%MEND CICLO_PF_SUSref;

%MACRO CICLO_PF_SUS_CSRANK(ref_list);
* CICLO_PF_SUS_CSRANK ;
  %local n sus ;
  %do n=1 %to %sysfunc(countw(&ref_list,%str( )));
    %let sus=%scan(&ref_list,&n);
    %put NOTE: &sysmacroname N=&n SUS=&sus;
    %put NOTE: Call macro named: CICLO_PF_SUSPEITOSrefmsisdn;
  %end;
%MEND CICLO_PF_SUS_CSRANK;

然后是你的主宏。

%macro ciclo_first(id_list);
* Start ciclo_first ;
  %local n id ;
  %do n=1 %to %sysfunc(countw(&id_list,%str( ))); 
    %let id=%scan(&id_list,&n);
    proc sql noprint; 
        select recetor into : lsus&id separated by ' ' from pct_&id;
    %let nrsus&id = &sqlobs ;
    quit;
    %put NOTE: Current ID=&id ;
    %put NOTE: &&nrsus&id records read from PCT_&ID ;
    %put NOTE: Value List LSUS&id  = &&LSUS&id ;
    %CICLO_PF_SUSref(&&lsus&id);
    %CICLO_PF_SUS_CSRANK(&&lsus&id);
  %end;
* End ciclo_first ;
%mend ciclo_first;

然后设置一些数据并调用主宏。

* Setup test data ;
data AMOSTRACHU;
  do id=1 to 2; output; end;
run;
data PCT_1 ;
  do recetor='A','B';
    output;
  end;
run;
data PCT_2 ;
  do recetor='C','D';
    output;
  end;
run;

options mprint;
%ciclo_first(1 2);

【讨论】:

  • 汤姆,谢谢你的帮助。我尝试使用它,并写了一个更新(10.08.2015),其中包含更多示例,以便更好地向您解释我想从数据中获得什么。
  • 您还没有解释为什么要这样做。因此,您在一个文件中拥有 id 列表。然后你有每个 REF 的值列表(为什么它们在不同的文件中),但是你在做什么呢?为什么会有如此疯狂的 DO 循环?看起来你想编码 %DO i=14 %TO 24;。 14 和 24 是什么意思?既然 %DO 循环中的代码没有引用 &I,那么为什么要对同一个查询进行 11 个副本?
猜你喜欢
  • 1970-01-01
  • 2018-05-17
  • 1970-01-01
  • 2013-06-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多