【问题标题】:Solution to macro-variable length exceeding maximum allowed error宏变长度超过最大允许误差的解决方法
【发布时间】:2021-07-26 16:00:30
【问题描述】:

有一个 SAS 程序已经运行了一段时间,但我现在面临宏变量长度问题。我将尝试恢复程序的功能:

/* Buffing implicit macro-variable: */
proc sql noprint;
    select quote(trim(col))  into :implicit separated by " "
    from have
    where col contains "%";

/* Buffing valid_from macro-variable, format 16. to bypass 
   scientific notation */
proc sql noprint;
    select VALID_FROM format=16. into :valid_from separated by " "
    from have
    where col contains "%";

/* Buffing valid_to macro-variable, format 16. to bypass 
   scientific notation */
proc sql noprint;
    select VALID_TO format=16. into :valid_to separated by " "
    from have
    where col contains "%";
quit;

/* If &implicit. is not empty, then retrieve implicit col */
%if %sysevalf(%quote(&implicit.)=,boolean) = 0 %then %do;
    /* Loop on each col */
    %do i=1 %to %sysfunc(countw(&implicit.," "));
        /* Initializing the current expression, valid_from, valid_to */
        %let current_expression = %scan(&implicit.,&i.," ");
        %let current_valid_from = %scan(&valid_from.,&i.," ");
        %let current_valid_to = %scan(&valid_to.,&i.," ");

        %let _timer_start = %sysfunc(datetime());
        
        /* Retrieve current implicit col */
        /* And the corresponding valid_from and valid_to */
        data to_append;
            set BIG_TABLE
            (where=(upcase(col) like "&current_expression."));
            VALID_FROM = &current_valid_from.;
            VALID_TO = &current_valid_to.;
        run;
        
        /* End timer */
        data _null_;
            dur = datetime() - &_timer_start;
            put '<< Retrieved implicit col:' 
                "&current_expression." '. Time:' dur time13.2 ' >>';
        run;

    /* Append to the corresponding corporate_store */
    proc append base=want data=to_append;run;
    
    /* Delete append table */
    proc datasets lib=work nolist;delete to_append;quit;run;
    %end; /* End loop on each col */
%end;

/* If &implicit. macro-variable is empty, then there are no implicit col to retrieve */
%else %do;
    %put << No implicit col to retrieve... >>;
%end;

有关信息,&amp;implicit. 宏变量如下所示:A[100][%][10] B[10][%][%],其目的是从 BIG_TABLE 获取所有符合条件的行,如:A[100][10][10]A[100][20][10] 等等...

但是,今天&amp;implicit. 宏变量的长度超过了最大长度(65534),我收到以下错误消息:

ERROR: The length of the value of the macro variable IMPLICIT (65540) exceeds the maximum length (65534). The value has been 
       truncated to 65534 characters. 

我在Create several SAS macro variable lists from single dataset 上遇到了@Tom 的解决方案,并决定复制它:

%let n_per_list=100;
/* Buffing &implicit. */
data _null_;
    length idlist $32000;
    length macrolist $1000;
    retain macrolist;

    do i=1 to &n_per_list. until (eof);
        set have(where=(col contains "%")) end=eof;
        idlist=catx(' ',idlist,quote(trim(col)));
    end;

    listno+1;
    call symputx(cats('implicit',listno),idlist);
    macrolist=catx(' ',macrolist,cats('&','implicit',listno));
    call symputx('implicit',macrolist);
run;

/* Buffing valid_from macro-variable, format 16. to bypass 
   scientific notation */
data _null_;
    length idlist $32000;
    length macrolist $1000;
    retain macrolist;

    do i=1 to &n_per_list. until (eof);
        set have(where=(col contains "%")) end=eof;
        format valid_from 16.;
        idlist=catx(' ',idlist,valid_from);
    end;

    listno+1;
    call symputx(cats('valid_from',listno),idlist);
    macrolist=catx(' ',macrolist,cats('&','valid_from',listno));
    call symputx('valid_from',macrolist);
run;

/* Buffing valid_to macro-variable, format 16. to bypass 
   scientific notation */
data _null_;
    length idlist $32000;
    length macrolist $1000;
    retain macrolist;

    do i=1 to &n_per_list. until (eof);
        set have(where=(col contains "%")) end=eof;
        format valid_to 16.;
        idlist=catx(' ',idlist,valid_to);
    end;

    listno+1;
    call symputx(cats('valid_to',listno),idlist);
    macrolist=catx(' ',macrolist,cats('&','valid_to',listno));
    call symputx('valid_to',macrolist);
run;

但我收到以下错误,因为它仍然会将我的宏截断为允许的最大长度:

ERROR: A character operand was found in the %EVAL function or %IF condition where a numeric operand is required. The condition was:

因此,我想知道是否有绕过此错误的技巧,或者是否有更有效的方法来做到这一点。我正在考虑使用哈希表进行查找,但我不确定它是否能处理类似的情况。

请注意,have 相当小(大约 3000 行),BIG_TABLE 大约有 80M 行。

【问题讨论】:

  • 您打算如何处理超过 64K 字节长的字符串?您链接的示例用法只是将字符串用作生成的 SAS 代码的一部分。请注意,生成的代码均不包含任何大于 SAS 限制的 32K 字节字符串文字的字符串文字。
  • 您能解释一下您尝试使用原始程序从数据中生成的 SAS 代码吗?我认为您似乎只是在尝试将文本转换为从/到数字。为什么不直接定义两个 INFORMATS 而不是使用宏变量?
  • @Tom 基本上我有一个数据have,其中有一列col 填充了要在SAS 代码中使用的类似条件(例如A[100][%][10])。我正在尝试检索所有符合这种条件的行(例如BIG_TABLE 中的col,如A[100][10][10]A[100][20][10]
  • 什么是VALID_FROM和VALID_TO?
  • 我认为字符串文字会导致以下 SAS 行中的问题:%if %sysevalf(%quote(&amp;implicit.)=,boolean) = 0 %then %do;%do i=1 %to %sysfunc(countw(&amp;implicit.," ")); 因为如果我在宏之外尝试,它会给我ERROR: The text expression length (65559) exceeds maximum length (65534). The text expression has been truncated to 65534 characters.

标签: sas


【解决方案1】:

消除创建如此大的宏变量的需要的一种方法是将数据保留在数据集中。

您似乎正在尝试对 HAVE 数据集中的每个观察值执行类似的操作。

%macro to_append(expression,valid_from,valid_to);

data to_append;
  set BIG_TABLE;
  where upcase(col) like &expression ;
  VALID_FROM = &valid_from.;
  VALID_TO = &valid_to.;
run;

%put << Retrieved implicit col: &expression
 %sysfunc(putn(%sysfunc(datetime())-&_timer_start,time13.2)) >> ; 

proc append base=want data=to_append force;
run;

%mend to_append; 

因此,只需使用数据集为每个观察生成一个宏调用。也许通过使用 CALL EXECUTE()。

data _null_;
  set have;
  call execute(cats
    ('%nrstr(%to_append)'
    ,'(',quote(trim(col),"'")
    ,',',valid_from
    ,',',valid_to
    ,')'
    )
  );
run;

或者只是将代码写入文件并 %include 。

filename code temp;
data _null_;
   set have;
   put '%to_append(' "'" col +(-1) "'," valid_from ',' valid_to ')';
run;
%include code / source2;

注意:在宏调用中包含 COL 值周围的单引号将阻止宏处理器尝试解释 % 字符。

还有“宏数组”方法。就我个人而言,我认为这种方法不值得努力,因为直接使用数据更容易。这个想法是创建 N 个单独的宏变量,而不是将 N 个值连接到一个宏变量中。

proc sql noprint;
  select quote(trim(col),"'"), valid_from, valid_to
    into :expression1-,:valid_from1-,:valid_to1-
    from have
  ;
%let n=&sqlobs;
quit;

%do i=1 %to &n ;

data to_append;
  set BIG_TABLE;
  where upcase(col) like &&expression&i ;
  VALID_FROM = &&valid_from&i;
  VALID_TO = &&valid_to&i;
run;
...
%end ;
       

【讨论】:

  • 我会做这些,甚至使用proc sql; select ... into :callstr from ... ; quit; &amp;callstr;。除了用宏语言解析字符串之外的任何东西!
  • @Joe proc sql; select ... into :callstr from ... ; quit; &amp;callstr; 是我使用的
  • @Kermit 不,不是 - 您正在创建一个大宏字符串,然后对其进行解析。我建议按照 Tom 所说的去做,并将这些 调用 放入字符串中。不过,它可能仍有限制,具体取决于其他细节,但您可以在宏内移动表达式的选择。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-02-19
  • 2012-04-07
  • 1970-01-01
  • 1970-01-01
  • 2011-02-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多