SAS中带有PROC SQL的函数样式宏?

时间:2018-07-13 20:09:37

标签: sql sas sas-macro

是否可以使这种形式的宏起作用?

    %macro tableMath(input1,input2);
    %local result;
    proc sql; ---some code here using inputs--- quit;
    proc sql; ---more code here--- quit;
    proc sql;
    select something into: result
    quit;
    &result
    %mend;

我想对数据集的每次观察运行一些相当复杂的逻辑,而在执行此操作之前,我使用的任何其他语言都是将其封装在一个函数中,该函数每次调用时都会返回结果- -我不确定如何在SAS中执行此逻辑。

编辑:input1和input2将是数据集的列,结果将用于在程序另一部分的其他宏中创建新列。我不需要特定的代码解决方案,我只是根本不了解应该如何在SAS中需要返回值的情况下执行传统的函数逻辑...

4 个答案:

答案 0 :(得分:3)

正如Richard所写,函数式宏发出SAS代码。开发函数样式宏的一般规则是它们仅包含宏语言语句。它们包含的任何SAS代码都会被发出。从历史上看,这使得编写函数式宏非常困难/烦恼,该宏将像处理DATA步骤一样处理数据。幸运的是,SAS添加了一个功能 DOSUBL ,该功能使编写在“侧边会话”中执行SAS代码并发出结果的函数式宏更加容易。参见Rick Langston's paper

这里是一个函数样式宏的示例,该宏使用DOSUBL对表中的记录数进行计数,并发出该计数。 (这是获取记录计数的一种非常低效的方法,仅是在SQL中执行操作的示例。)

%macro SQLcount(table);
  %local rc emit; 

  %let rc=%sysfunc(dosubl(%nrstr(
     proc sql noprint;
      select count(*) into :emit trimmed
      from &table
     quit;
  )));

  &emit 
%mend ;

它可以像这样使用:

proc sql ;
  select name
        ,%SQLcount(sashelp.shoes) as ShoeCount  /*emits 395*/
  from sashelp.class
  ;
quit ;

运行上述步骤时,它将从sashelp.class返回19行名称,并且ShoeCount的值将为每行395。请注意,宏SQLcount仅执行一次。在编译/解释PROC SQL步骤时,可以看到对SQLcount的调用,并且该宏被执行并发出395。该步骤变为:

proc sql ;
  select name
        ,395 as ShoeCount  /*emits 395*/
  from sashelp.class
  ;
quit ;

DOSUBL使用“辅助会话”执行代码,该代码使您可以在辅助会话中执行PROC SQL步骤,而主会话正在解释PROC SQL步骤。

从您的问题中我无法确定您是否想要这种用例。您可能需要一个函数样式的宏,您可以在其中从表中将值传递给它,并使该宏在每个值上执行并返回某些内容。假设您有一个表,该表是一个表名列表,并且想要使用SQL获取每个表中的记录数:

data mytables ;
  input table $20. ;
  cards ;
sashelp.shoes
sashelp.class
sashelp.prdsale
;
quit ;

您可以通过使用resolve()函数从数据构建宏调用,将宏的执行延迟到SELECT语句执行之前来实现:

proc sql ;
  select table
        ,resolve('%SQLcount('||table||')') as count
  from mytables
  ;
quit ;

这样,SQLcount将被调用3次,并将返回每个数据集中的记录数。

table                 count
---------------------------
sashelp.shoes         395
sashelp.class         19
sashelp.prdsale       1440

在解释PROC SQL步骤时看不到宏调用,因为该宏调用被单引号隐藏了。然后,在SELECT语句执行时,resolve函数调用宏,将table的值作为参数值传递,并且该宏发出记录计数。这类似于使用数据来驱动宏调用的CALL EXECUTE方法。

答案 1 :(得分:1)

您声明要:

  

对数据集的每次观察运行一些相当复杂的逻辑

为此,您应该使用SAS语言而不是宏处理器或PROC SQL。您可以使用数据步骤。或者,对于更复杂的逻辑,您应该查看PROC DS2。

答案 2 :(得分:1)

听起来像您可能想使用proc fcmp创建FCMP函数。从根本上讲,这是创建自己的SAS功能的一种方法,可在proc sqldata步骤中使用。例如:

/******************************************************************************
** PROGRAM:  COMMON.FCMP_DIV.SAS
**
** DESCRIPTION: PERFORMS A MATHEMATICAL DIVISION BUT WILL RETURN NULL IF THE
**              NUMERATOR OR DENOMINATOR IS MISSING (OR IF THE DIVISOR IS 0).
**
******************************************************************************/

proc fcmp outlib=common.funcs.funcs;

  function div(numerator, denominator);

    if numerator eq . or denominator in (0,.) then do;
      return(.);
    end;
    else do;
      return(numerator / denominator);
    end;

  endsub;
run;

示例用法(示例是数据步骤,但在SQL中同样有效):

data x;
  x1  = div(1,0);
  x2  = div(1,.);
  x3  = div(1,1);

  x4  = div(0,0);
  x5  = div(0,.);
  x6  = div(0,1);

  x7  = div(.,0);
  x8  = div(.,.);
  x9  = div(.,1);

  put _all_;
run;

答案 3 :(得分:0)

宏函数不返回值。宏函数可以“发出”源代码,

  • 是一个或多个步骤,
  • 这是将代码合并到语句中的摘要,
  • 这是一个或多个步骤的一部分,

对于要在SQL中“执行”操作的情况,您可以编写 SQL视图,然后该

  • %sysfunc(open())
  • 开头
  • 已处理
    • %sysfunc(set())
    • %sysfunc(getvarn())
    • %sysfunc(getvarc())

这种技术并非可以利用所有SQL功能-select something into :result必须是带有select something的视图,而宏getvarc才能读取结果。

以open / set / get方式进行的访问不会引起步骤边界的发生,因此宏处理可以按照其逻辑进行,并最终发出用于代码段级别使用的源代码。 (使用者是处理宏代码,隐式编译和运行SAS步骤的SAS执行程序)