2

我想知道我可以将一些代码合并到一个PROC SQL语句中,而不是几个背靠背的SQL语句。

我正在使用宏来计算参与者在研究同意日期的年龄,类似于此处此处提供的内容。我尝试对宏的功能进行故障排除,并使用%sum宏计算了婴儿出生时的总重量(以盎司为单位)(效果很好……)。但是,在尝试计算年龄时,宏不起作用。

但是,如果我在新SQL语句中使用宏,它就可以正常工作。

下面的代码有效:

%macro months(somedate,birth);
intck('month',&birth,&somedate) 
         - (day(&somedate) < day(&birth))
%mend months;

%macro days(somedate,birth);
intck('day',&birth,&somedate) 
         - (day(&somedate) < day(&birth))
%mend days;

%macro sum(part1, part2);
&part1*16 + &part2
%mend sum;


**********  bringing in data from outside tables  ;
proc sql;
  create table demos as
    select      x.*,    infcondt2 as c_dt, 
                y.*,    datepart(visitdt)   as v_dt format date9. ,
                        datepart(birthdt)   as b_dt format date9. ,
                        birthweightlbs as lbs,
                        birthweightoz as oz,

                        lbs*16 + oz as tot_oz,
                        %sum(lbs,oz) as tot_oz_m

    from    enrolled as x, 
            demographics as y

    where x.center = y.center and x.id = y.id  ;
    quit;

**********  calculating age in months and in days  ;
proc sql;
create table demos2 as
select  * ,
        %months(c_dt, b_dt) as age_m ,
        %days(c_dt, b_dt) as age_d 
from demos;
quit;


**********  creating age groupings by months: 0-3 and 3-6  ;
proc sql;
create table demos3 as
select  * ,
        case
          when age_m le 3 then 1
          when age_m le 6 and age_m gt 3 then 2
          else 3
          end as age_interval
from demos2;
quit;

有没有办法把它合并成一个语句?就像是:

proc sql;
  create table demos as
    select      x.*,    infcondt2 as c_dt, 
                y.*,    datepart(visitdt)   as v_dt format date9. ,
                        datepart(birthdt)   as b_dt format date9. ,
                        birthweightlbs as lbs,
                        birthweightoz as oz,

                        lbs*16 + oz as tot_oz,
                        %sum(lbs,oz) as tot_oz_m,
                        %months(c_dt, b_dt) as age_m,
                        %days(c_dt, b_dt) as age_d, 
                        case
                            when age_m le 3 then 1
                            when age_m le 6 and age_m gt 3 then 2
                            else 3
                            end as age_interval

    from    enrolled as x, 
            demographics as y

    where x.center = y.center and x.id = y.id  ;
    quit;
4

2 回答 2

3

如果要使用之前在同一 SQL 语句中创建的字段,则需要使用calculated关键字。IE:

proc sql;
select age*2 as double_Age, calculated double_age/2 as normal_age from sashelp.class;
quit;

仅当有实际计算时才需要计算 - 即,对于 b_Dt。c_dt 只是对 infcondt2 的重命名,所以可以互换使用 c_dt(或 infcondt2),不能使用 CALCUALTED。

data test;
input dt1 :date9. dt2 :date9.;
datalines;
01JAN2010 01FEB2011
01DEC2011 03FEB2012
;;;;
run;

%macro months(somedate,birth);
intck('month',&birth,&somedate) - (day(&somedate) < day(&birth))
%mend months;

proc sql;
create table test2 as
select dt1 -1 as b_dt, dt2 as c_dt, %months(calculated b_dt, c_dt) as third
from test;
quit;

也就是说,如果您有 9.2 或更早版本,则不再需要调整日期 - 查看 INTCK 的文档。有一个可选参数(在 9.3 中称为 METHOD,我认为 9.2 将其称为不同的东西)允许您强制它使用连续的月份概念而不是离散的概念(计算月初是离散的,例如,作为过去的默认值)。

另外,我不明白 DAY 宏的意义——不仅是 DAYs 整数(所以你可以使用普通减法减去这两个数字),而且你为什么要像 %month 那样减去日/日?正如我刚刚讨论的那样,这是为了纠正每月的一部分,并且几天都不需要(它会在某些日期<出生时产生错误的答案)。

正确代码示例:

%macro months(somedate,birth);
intck('month',&birth,&somedate) 
         - (day(&somedate) < day(&birth))
%mend months;

%macro days(somedate,birth);
intck('day',&birth,&somedate) 
         - (day(&somedate) < day(&birth))
%mend days;

%macro sum(part1, part2);
&part1*16 + &part2
%mend sum;

data enrolled;
input
id infcondt2 :date9.
;
datalines;
1 01JAN2011
2 02JAN2011
3 03MAR2011
;;;;
run;
data demographics;
input
id
birthweightlbs
birthweightoz
birthdt :datetime17.
;
datalines;
1 8 14 04MAR2011:15:13:14
2 7 13 05MAR2011:15:13:14
3 6 15 06MAR2011:15:13:14
;;;;
run;


proc sql;
  create table demos as
    select      x.*,    infcondt2 as c_dt, 
                y.*,    datepart(birthdt)   as b_dt format date9. ,
                        birthweightlbs as lbs,
                        birthweightoz as oz,
                        lbs*16 + oz as tot_oz,
                        %sum(lbs,oz) as tot_oz_m,
                        %months(c_dt, calculated b_dt) as age_m,
                        c_dt - calculated b_dt as age_d, /* %days is almost certainly wrong here */
                        case
                            when calculated age_m le 3 then 1
                            when 3 le calculated age_m le 6 then 2
                            else 3
                            end as age_interval

    from    enrolled as x, 
            demographics as y

    where x.id = y.id  ;
    quit;
于 2013-01-07T16:53:15.567 回答
3

如果您想对proc sql变量执行复杂的数据步骤逻辑,我知道的最好方法是使用proc fcmp定义函数而不是宏。

例如

proc fcmp outlib=work.util.Dates;
    function months(somedate, birth);
        return (intck('month',&birth,&somedate) - (day(&somedate) < day(&birth)));
    endsub;
run;

options cmplib=work.util;


proc sql;
create table demos as
select      x.*,    infcondt2 as c_dt, 
            y.*,    datepart(visitdt)   as v_dt format date9. ,
                    datepart(birthdt)   as b_dt format date9. ,
                    birthweightlbs as lbs,
                    birthweightoz as oz,

                    lbs*16 + oz as tot_oz,                        
                    months(c_dt, b_dt) as age_m,
                    case
                        when age_m le 3 then 1
                        when age_m le 6 and age_m gt 3 then 2
                        else 3
                        end as age_interval

from    enrolled as x, 
        demographics as y

where x.center = y.center and x.id = y.id  ;
quit;

您可以使用months()您在data步骤中创建的功能proc sql,也可以在其他一些地方使用。

于 2013-01-07T18:17:13.147 回答