在PROC SQL中使用宏变量/语言

时间:2018-01-09 17:07:19

标签: sql oracle sas

我使用PROC SQL进行Oracle数据库查询(虽然我不是数据库人员,所以我不能比这更具体),我们经常应用自动加载的库中的格式。我想知道是否有更快的方式来编程这些类型的查询,例如,让我说在视图中我有一个名为prim_disease_cd的变量,我想把它拉出来,应用格式(具有同名)并称之为prim_disease_cd。现在我会做

put(a.prim_disease_cd, prim_disease_cd.) as prim_disease_cd

有没有办法可以使用宏语言来缩短它?到目前为止,我一直没有成功,但我们经常这样做,看起来效率很低。基本上我想要一个宏,它接受一个视图/数据集a和一个变量X并将" put(a.X,X。)应用为X"

此外,无论如何,如果有的话,我可以为日期实施这样的事情,那将是很好的,即替换

datepart(a.(var_name)) as (var_name) format mmddyy10.

感谢您提供的任何帮助。

2 个答案:

答案 0 :(得分:1)

您可以创建简单的宏来执行这两项操作。仅发出类似语句的一部分的宏通常称为宏函数或函数样式宏。确保不要发出任何分号。例如,您可以制作这两个宏。

%macro decode(alias);
  %local varname ;
  %let varname=%scan(&alias,-1,.);
  put(&alias,&varname..) as &varname
%mend; 
%macro datepart(alias);
  %local varname ;
  %let varname=%scan(&alias,-1,.);
  datepart(&alias) as &varname format yymmdd10.
%mend; 

然后您的SQL查询可能如下所示:

create table want as 
select a.patid
     , %decode(a.prim_disease_cd)
     , %datepart(a.onset_date)
from oralib.diagnosis a
;

您可能会发现使用这些将使您的SAS代码更难维护。可能更容易找到一种方法来自动生成编辑器中的文本。或运行一个程序,从元数据生成文本,然后将其复制并粘贴到您的程序中。

PS不要将MDY(或DMY)格式用于日期。这会让你的欧洲(或美国)朋友感到困惑。

答案 1 :(得分:0)

如果需要在针对Oracle数据的未来查询中使用<concept>_cd代码值,我会说创建一个新变量,例如<concept>_value<concept>

如果Oracle查询中的编码数据一致地命名,例如仅<concept>_cd,则可以让宏检查提取的数据并创建SAS视图,该视图通过SAS格式应用从代码到值的映射。由于您从Oracle中提取编码值,因此Oracle中可能有一个或多个查找表将代码映射到值,并且可能您的SAS格式是根据该数据构建的。

在您的用例中,将代码转换为值实质上是对假定的查找表执行左连接。我假设您正在执行代码映射,以便更容易执行子集选择。

如果您只报告数据,则可能只需要将格式应用于代码变量本身。下面是一个示例宏,它根据命名约定<concept>_cd

处理查询结果并执行代码来映射值映射
data code_lookups;
length id 8 fmt $31 desc $50 ;
input id & fmt & desc;
datalines;
1   country_cd   US
2   country_cd   Canada
10  color_cd     Green
11  color_cd     Blue
12  color_cd     Red
20  footwear_cd  Shoes
21  footwear_cd  Socks
22  footwear_cd  Laces
run;  

proc format cntlin=code_lookups(rename=(fmt=fmtname id=start desc=label));
run;

data have(label="Some result from Oracle with unmapped codes");
  input item_id country_cd color_cd footwear_cd;
datalines;
1 1 11 22
2 2 11 21
3 1 12 22
3 1 10 20
run;

%macro auto_codemap (data=, out=, out_struct=view, map_func=new_var);

  %local dsid i l p q varname;
  %let dsid = %sysfunc(open(&data));

  %if &map_func ne format_only and &map_func ne new_var %then %do;
    %put ERROR: &=map_func unknown.;
  %end;

  proc sql;
    create &out_struct &out as 
    select
      %do i = 1 %to %sysfunc(attrn(&dsid,nvar));
        %if &i > 1 %then %str(,);
        %let varname = %sysfunc(varname(&dsid,&i));
        &varname

        %let l = %length(&varname);
        %if &l > 3 %then %do;
          %let p = %eval(&l-3);
          %let q = %eval(&l-2);
          %if %substr(%upcase(&varname),&q) = _CD %then %do;

            %if &map_func = format_only %then %do;
              format=%str(&varname).
            %end;
            %else %if &map_func = new_var %then %do;
              , put(&varname, %str(&varname).) as %substr(&varname,1,&p)
            %end;
          %end;
        %end;
      %end;
    from &data
    ;
  quit;

  %let dsid = %sysfunc(close(&dsid));
%mend;

options mprint;

%auto_codemap (data=have, out=want)
proc print data=want;
run;

%auto_codemap (data=have, out=want2, map_func=format_only)
proc print data=want2;
run;