**************************************************************************************************** * PROGRAM OVERVIEW **************************************************************************************************** * * PROGRAM: ms_cidadenom.sas * Created (mm/dd/yyyy): 12/19/2014 * *-------------------------------------------------------------------------------------------------- * PURPOSE: * This macro will compute denominators. * * Program inputs: * -Many datasets created by ms_cidanum * * Program outputs: * -The DPLocal.&RUNID._DenomCounts output table * * PARAMETERS: * * Programming Notes: * * *-------------------------------------------------------------------------------------------------- * CONTACT INFO: * Sentinel Coordinating Center * info@sentinelsystem.org * ***************************************************************************************************; %macro ms_cidadenom(); %put =====> MACRO CALLED: ms_cidadenom ; /*Only compute denominators if OUTPUTDENOM ne N and USERSTRATA file is specified and contains relevant tables*/ %ISDATA(dataset=userstrata_denom); %if "&outputdenom" ne "N" and %eval(&nobs.>0) %then %do; /*Timing*/ %ms_starttimer(timestart=denomruntime); /*---------------------------------------------------*/ /* Original enrollment periods */ /*---------------------------------------------------*/ *If death censoring is required, it was already applied (Enr_End was previously truncated by CIDAnum); data worktemp._denomorig&Group. (keep=PatId EligEpisode Enr_Start Enr_End) worktemp._denom&Group.(keep=PatId DenomEnrStartdt DenomEnrEnddt EligEpisode); set worktemp.enr_&enrollmentnum.; where Enr_End>=&startdate.; format Enr_Start Enr_End DenomEnrStartDt DenomEnrEndDt date9.; length Enr_Start Enr_End DenomEnrStartDt DenomEnrEndDt 4; * Resctrict eligibility to Study period (minus maximum of required lookbacks); DenomEnrStartDt=Enr_Start; * Initially truncate start eligibility enrollment start by max of lookback periods; DenomEnrStartDt=DenomEnrStartDt + &ENRDAYS.; DenomEnrEndDt=Enr_End; if DenomEnrEndDt >= DenomEnrStartDt; rename episode=EligEpisode; run; /*---------------------------------------------------*/ /* Inclusion required (POV3 Incl) for eligibility */ /*---------------------------------------------------*/ %if &excl_incl = Y %then %do; *For EACH condition, shave periods for all subconditions; %let MAXCOND=; proc sql noprint; select max(cond) into: maxcond from _IT&INCLUSIONCODES.; quit; %put &=MAXCOND; %DO COND=1 %TO &MAXCOND.; *Determine how many levels of subconditions needed and if condition is an inclusion; %let MAXSUBCOND=; proc sql noprint; select max(subcond), max(CondInclusion) into :maxsubcond, :inclusion from _IT&INCLUSIONCODES. (where=(COND=&COND.)); quit; %put &=MAXSUBCOND &=INCLUSION; /*Create &cond specific dataset*/ proc copy in=worktemp out=work memtype=data; select _denom&Group.; quit; proc datasets library=work noprint; change _denom&Group.=_Denom&Group._&cond.; quit; %DO SUBCOND=1 %TO &MAXSUBCOND.; *Determine if subcond is an inclusion or exclusion; %let SUBINCLUSION=0; %let codedays = 1; %let subcumdose = 0; %let subminafdd = 0; %let submaxafdd = 0; proc sql noprint; select max(SubCondInclusion), codedays, max(mincumdose), max(maxafdd), max(minafdd) into: subinclusion, : codedays, : subcumdose, : submaxafdd, : subminafdd from _IT&INCLUSIONCODES. (where=(COND=&COND. and SUBCOND=&SUBCOND.)); quit; %put &=SUBINCLUSION; *Merge time periods for each subcondition and shave for each; %IF &SUBINCLUSION. = 1 %THEN %DO; data _EligIncl_&subcond.; format EligStart EligEnd date9.; length EligStart EligEnd 4; %if %eval(&codedays.) > 1 %then %do; retain id; %end; ; set _inclexcl (where =(COND=&COND. and subcond=&SUBCOND.)); by patid adate expiredt; *When cumdose or afdd specified create a de-duped inclexcl dataset. This is necessary for codedays computation; %if &computepov3cumdose. = Y | &computepov3afdd. = Y %then %do; if not first.expiredt then delete; %end; EligStart=ADate-coalesce(CondTo,99999); if dateonly = 'N' then do; EligEnd=Expiredt-coalesce(CondFrom,-99999); end; else do; EligEnd=ADate-coalesce(CondFrom,-99999); end; if EligStart<=EligEnd; %if %eval(&codedays.) > 1 %then %do; lag_adate = lag (adate); if first.patid then id=1; else if lag_adate ne adate then id+1; %end; keep PatId EligStart EligEnd %if %eval(&codedays.) > 1 %then %do; id %end; ; run; *only keep time periods that meet codedays criteria; %if %eval(&codedays.) = 1 %then %do; data _overlap_spans_&subcond.; set _EligIncl_&subcond.; run; %end; %else %do; proc sql noprint; create table _overlap_spans_&subcond.(where=(eligstart <=eligend) rename=overlap_start=eligstart rename=overlap_end=eligend) as select distinct a1.patid, max(a1.eligstart %do ref = 2 %to &codedays.; ,a&ref..eligstart %end;) as overlap_start format date9., min(a1.eligEnd %do ref = 2 %to &codedays.; ,a&ref..eligEnd %end;) as overlap_end format date9. from _EligIncl_&subcond. as a1 %do ref = 2 %to &codedays.; , _EligIncl_&subcond. as a&ref. %end; where a1.Patid %do ref = 2 %to &codedays.; = a&ref..PatId %end; and (a1.id %do ref = 2 %to &codedays.; < a&ref..id %end;); quit; %end; %MergeTimePeriods(dataset=_overlap_spans_&subcond., DateStart=EligStart, DateEnd=EligEnd); %ms_shaveoutside(reffile=_overlap_spans_&subcond., refstart=EligStart, refend=EligEnd, KeepPartBf=Y, ToShaveFile=_Denom&Group._&cond., ToShaveStart=DenomEnrStartDt, ToShaveEnd=DenomEnrEndDt, shaverx=N, outfile=_Denom&Group._&cond.); /* If mincumdose or average filled cumulative dose is specified then restrict eligibility periods */ %if %sysevalf(&subcumdose. > 0) | %sysevalf(&subminafdd. > 0) | %sysevalf(&submaxafdd. > 0) %then %do; %ms_dose_denom (infile = _denom&group._&cond. ,condvalue = &cond. ,subcondvalue = &subcond. ,subcumdose = &subcumdose. ,submaxafdd = &submaxafdd. ,subminafdd = &subminafdd); %ms_shaveoutside(reffile=_inclexcl_cumdose, refstart=eligcumdosestart, refend=eligcumdoseend, KeepPartBf=Y, ToShaveFile=_Denom&Group._&cond., ToShaveStart=DenomEnrStartDt, ToShaveEnd=DenomEnrEndDt, shaverx=N, outfile=_Denom&Group._&cond.(drop=eligstart eligend eligcumdoseend eligcumdosestart)); %end; %else %do; *Drop refstart and refend since _Denom&Group can be looped; data _Denom&Group._&cond.; set _Denom&Group._&cond.(drop=eligstart eligend); run; %end; %END;*If subinclusion=1; %IF &SUBINCLUSION. = 0 %THEN %DO; data _UneligExcl_&subcond.; format UneligStart UneligEnd date9.; length UneligStart UneligEnd 4; %if %eval(&codedays.) > 1 %then %do; retain id; %end; ; set _inclexcl (where =(COND=&COND. and subcond=&SUBCOND.)); by patid adate expiredt; *When cumdose or afdd specified create a de-duped inclexcl dataset. This is necessary for codedays computation; %if &computepov3cumdose. = Y | &computepov3afdd. = Y %then %do; if not first.expiredt then delete; %end; UneligStart=ADate-coalesce(CondTo,99999); if dateonly = 'N' then do; UneligEnd=Expiredt-coalesce(CondFrom,-99999); end; if dateonly = 'Y' then do; UneligEnd=Adate-coalesce(CondFrom,-99999); end; if UneligStart<=UneligEnd; %if %eval(&codedays.) > 1 %then %do; lag_adate = lag (adate); if first.patid then id=1; else if lag_adate ne adate then id+1; %end; keep PatId UneligStart UneligEnd %if %eval(&codedays.) > 1 %then %do; id %end; ; run; *only keep time periods that meet codedays criteria; %if %eval(&codedays.) = 1 %then %do; data _overlap_spans_&subcond.; set _UneligExcl_&subcond.; run; %end; %else %do; proc sql noprint; create table _overlap_spans_&subcond.(where=(Uneligstart <=Uneligend) rename=overlap_start=Uneligstart rename=overlap_end=Uneligend) as select distinct a1.patid, max(a1.UneligStart %do ref = 2 %to &codedays.; ,a&ref..Uneligstart %end;) as overlap_start format date9., min(a1.UneligEnd %do ref = 2 %to &codedays.; ,a&ref..UneligEnd %end;) as overlap_end format date9. from _UneligExcl_&subcond. as a1 %do ref = 2 %to &codedays.; , _UneligExcl_&subcond. as a&ref. %end; where a1.Patid %do ref = 2 %to &codedays.; = a&ref..PatId %end; and (a1.id %do ref = 2 %to &codedays.; < a&ref..id %end;); quit; %end; %MergeTimePeriods(dataset=_overlap_spans_&subcond., DateStart=UneligStart, DateEnd=UneligEnd); *Verify if there is data or else e.r.r.o.r when shaving; %ISDATA(dataset=_UneligExcl_&subcond.); %IF %EVAL(&NOBS.>=1) %THEN %DO; %ms_shaveinside(reffile=_Denom&Group._&cond., refstart=DenomEnrStartDt, refend=DenomEnrEndDt, id=EligEpisode, ToShaveFile=_overlap_spans_&subcond., ToShaveStart=UneligStart, ToShaveEnd=UneligEnd, outfile=_Denom&Group._&cond.); %end; /* If mincumdose or average filled cumulative dose is specified then restrict eligibility periods */ %if %sysevalf(&subcumdose. > 0) | %sysevalf(&subminafdd. > 0) | %sysevalf(&submaxafdd. > 0) %then %do; %ms_dose_denom (infile = _denom&group._&cond. ,condvalue = &cond. ,subcondvalue = &subcond. ,subcumdose = &subcumdose. ,submaxafdd = &submaxafdd. ,subminafdd = &subminafdd); %isdata(dataset=_inclexcl_cumdose); %if %eval(&nobs.>0) %then %do; %ms_shaveinside(reffile=_Denom&Group._&cond., refstart=DenomEnrStartDt, refend=DenomEnrEndDt, id=EligEpisode, ToShaveFile=_inclexcl_cumdose , ToShaveStart=eligcumdosestart, ToShaveEnd=eligcumdoseend, outfile=_Denom&Group._&cond.); %end; %end; %END;*If subinclusion=0; %END;*loop on subcond; %put &=INCLUSION; %IF &INCLUSION.=1 %THEN %DO; proc append base=_Denom&Group._STACK_INC data=_Denom&Group._&cond.(keep=patid DenomEnrStartDt DenomEnrEndDt eligepisode) force; run; %END; %IF &INCLUSION.=0 %THEN %DO; proc append base=_Denom&Group._STACK_EXCL data=_Denom&Group._&cond.(keep=patid DenomEnrStartDt DenomEnrEndDt eligepisode) force; run; %END; %END;*End Loop Cond; *Output dataset for inclusion=1 and for exclusions=0 and then (a) shaveoutside (b) shaveinside denom; *For inclusions, need to merge periods; *First shaveoutside denom file but need to merge inclusion periods together; %IF %SYSFUNC(exist(_Denom&Group._STACK_INC))=1 %THEN %DO; %MergeTimePeriods(dataset=_Denom&Group._STACK_INC, DateStart=DenomEnrStartDt, DateEnd=DenomEnrEndDt); *_Denom&Group._STACK_INC includes all time periods where the potential index dates will meet at least one of the cond inclusions; proc datasets library=work noprint; modify _Denom&Group._STACK_INC; rename DenomEnrStartDt=DTSTART DenomEnrEndDt=DTEND; quit; %ms_shaveoutside(reffile=_Denom&Group._STACK_INC, refstart=DTSTART, refend=DTEND, /*id=EligEpisode,*/ KeepPartBf=Y, ToShaveFile=worktemp._denom&Group., ToShaveStart=DenomEnrStartDt, ToShaveEnd=DenomEnrEndDt, shaverx=N, outfile=worktemp._denom&Group./*_incl*/); %END; %IF %SYSFUNC(exist(_Denom&Group._STACK_EXCL))=1 %THEN %DO; *merge all periods of ineligibilities; %MergeTimePeriods(dataset=_Denom&Group._STACK_EXCL, DateStart=DenomEnrStartDt, DateEnd=DenomEnrEndDt); *_Denom&Group._STACK_EXCL includes all time periods where the potential index dates will meet at least one of the cond exclusions; proc datasets library=work noprint; modify _Denom&Group._STACK_EXCL; rename DenomEnrStartDt=DTSTART DenomEnrEndDt=DTEND; quit; *remove all these periods from the ELIG; %ms_shaveinside(reffile=worktemp._denom&Group., refstart=DenomEnrStartDt, refend=DenomEnrEndDt, id=EligEpisode, ToShaveFile=_Denom&Group._STACK_EXCL, ToShaveStart=DTSTART, ToShaveEnd=DTEND, outfile=worktemp._denom&Group.); %END; proc sort data=worktemp._denom&Group. out=worktemp._denom&Group. nodupkey; by patid DenomEnrStartDt DenomEnrEndDt eligepisode; run; %END;*If there are inclusion codes for this group; /*------------------------------------------------------------- Create separate prevalance and incidence cidadenom datasets -------------------------------------------------------------*/ %macro cidadenom_prev_inc (l=, ds_suffix =, where_clause = ); /*---------------------------------------------------*/ /* Group Index (POV1) to remove from eligibility */ /*---------------------------------------------------*/ %if %eval(&l.=1) %then %do; data worktemp._temp&group.; set worktemp._denom&Group.; run; %end; %if %eval(&l.=2) %then %do; data worktemp._denom&Group.; set worktemp._temp&group.; run; proc datasets nowarn noprint lib = worktemp; delete _temp&group.; quit; %end; %global previnc_washper; /* Need to use washper2 when autoprev = Y */ %if %str("&autoprev.") = %str("Y") and %str("&ds_suffix") = "" %then %do; %let previnc_washper = &washper2.; %end; %else %do; %let previnc_washper = &washper.; %end; %ISDATA(dataset=_groupindex); %IF %EVAL(&NOBS.>=1) & (%EVAL(&previnc_washper. ne 0)) %THEN %DO; data _UneligGroupIndex; set _groupindex; format UneligStart UneligEnd date9.; length UneligStart UneligEnd 4; UneligStart=ADate + 1; * Added a +1 so a member can remain eligible the day of index date; UneligEnd=ExpireDt + min(&previnc_washper.,99999); if UneligStart<=UneligEnd; keep PatId UneligStart UneligEnd; run; %MergeTimePeriods(dataset=_UneligGroupIndex, DateStart=UneligStart, DateEnd=UneligEnd); %ms_shaveinside(reffile=worktemp._denom&Group., refstart=DenomEnrStartDt, refend=DenomEnrEndDt, id=EligEpisode, ToShaveFile=_UneligGroupIndex, ToShaveStart=UneligStart, ToShaveEnd=UneligEnd, outfile=worktemp._denom&Group.); %END; /*---------------------------------------------------*/ /* Follow-up Event (POV5) to remove from eligibility */ /*---------------------------------------------------*/ %ISDATA(dataset=_fupevent);*Will only apply to type 2 analysis; %IF %EVAL(&NOBS.>=1) %THEN %DO; data _UneligFupEvent; set _fupevent; format UneligStart UneligEnd date9.; length UneligStart UneligEnd 4; UneligStart=sum(ADate, - &BLACKOUTPER., 1); * Added a +1 so a member can be eligible the day of event; if dateonly = 'N' then do; UneligEnd=ExpireDt + min(&FUPWASHPER.,99999); end; if dateonly = 'Y' then do; UneligEnd=Adate + min(&FUPWASHPER.,99999); end; if UneligStart<=UneligEnd; keep PatId UneligStart UneligEnd; run; %MergeTimePeriods(dataset=_UneligFupEvent, DateStart=UneligStart, DateEnd=UneligEnd); %ms_shaveinside(reffile=worktemp._denom&Group., refstart=DenomEnrStartDt, refend=DenomEnrEndDt, id=EligEpisode, ToShaveFile=_UneligFupEvent, ToShaveStart=UneligStart, ToShaveEnd=UneligEnd, outfile=worktemp._denom&Group.); %END; /*-----------------------------------------------------*/ /* Follow-up Washout (POV6) to remove from eligibility */ /*-----------------------------------------------------*/ %ISDATA(dataset=_fupwash); %IF %EVAL(&NOBS.>=1) %THEN %DO; data _UneligFupWash; set _fupwash; format UneligStart UneligEnd date9.; length UneligStart UneligEnd 4; UneligStart=ADate + 1; * Added a +1 so a member can remain eligible the day of index date; if dateonly = 'N' then do; UneligEnd=ExpireDt + min(&FUPWASHPER.,99999); end; if dateonly = 'Y' then do; UneligEnd=Adate + min(&FUPWASHPER.,99999); end; if UneligStart<=UneligEnd; keep PatId UneligStart UneligEnd; run; %MergeTimePeriods(dataset=_UneligFupWash, DateStart=UneligStart, DateEnd=UneligEnd); %ms_shaveinside(reffile=worktemp._denom&Group., refstart=DenomEnrStartDt, refend=DenomEnrEndDt, id=EligEpisode, ToShaveFile=_UneligFupWash, ToShaveStart=UneligStart, ToShaveEnd=UneligEnd, outfile=worktemp._denom&Group.); %END; *this macro is to avoid having to output one record per interval per stratification level which for certain partners, can become quite large.; %macro CreateSums(infile=,outfile=,by=,dimout=,timeperiod=month,numtimeperiod=&nummonths.); proc sort data = &infile.(keep= Patid DenomEnrStartdt DenomEnrEnddt &by.) out=_temp; by &by. patid; run; data _temp; set _temp; By &by. PatId; array _NumPtsYM(*) _NumPtsYM1-_NumPtsYM&numtimeperiod.; *Pts level temporary vector to avoid double counting patients in same year/month or year/quarter; array _NumPtsY(*) _NumPtsY1-_NumPtsY&numyears.; *Pts level temporary vector to avoid double counting patients in same year; array NumPtsYM(*) NumPtsYM1-NumPtsYM&numtimeperiod.; *accumator of unique patient in the same year/month or year/quarter; array NumPtsY(*) NumPtsY1-NumPtsY&numyears.; *accumator of unique patient in the same year; %if "&outputdenom" = "Y" %then %do; array NumMemDaysYM(*) NumMemDaysYM1-NumMemDaysYM&numtimeperiod.; *accumator of unique days in the same year/month or year/quarter; array NumMemDaysY(*) NumMemDaysY1-NumMemDaysY&numyears.; *accumator of unique days in the same year; %end; %do p=1 %to &numtimeperiod.; %let p1=%eval(&p.+1); if %MS_PeriodsOverlap(period1=DenomEnrStartDt DenomEnrEndDt,period2=&&&timeperiod.PER&p. &&&timeperiod.PER&p1.-1) then do; _NumPtsYM(&p.)=1; %if "&outputdenom" = "Y" %then %do; NumMemDaysYM(&p.)=sum(NumMemDaysYM(&p.),Min(DenomEnrEndDt,&&&timeperiod.PER&p1.-1)-max(DenomEnrStartDt,&&&timeperiod.PER&p.)+1); %end; end; %end; %do p=1 %to &numyears.; %let p1=%eval(&p.+1); if %MS_PeriodsOverlap(period1=DenomEnrStartDt DenomEnrEndDt,period2=&&YEARPER&p. &&YEARPER&p1.-1) then do; _NumPtsY(&p.)=1; %if "&outputdenom" = "Y" %then %do; NumMemDaysY(&p.)=sum(NumMemDaysY(&p.),Min(DenomEnrEndDt,&&YEARPER&p1.-1)-max(DenomEnrStartDt,&&YEARPER&p.)+1); %end; end; %end; if last.PatId then do; do i = 1 to &NUMYEARS.; NumPtsY(i)=sum(NumPtsY(i),_NumPtsY(i)); end; do i = 1 to &numtimeperiod.; NumPtsYM(i)=sum(NumPtsYM(i),_NumPtsYM(i)); end; call missing(of _Num:); end; if last.&dimout. then do; output; call missing(of Num:); end; keep &by. Num:; retain Num: _Num:; run; %ISDATA(dataset=_temp); %IF %EVAL(&NOBS.=0) %THEN %DO; proc sql noprint; insert into _temp set NumPtsYM1=.; quit; %END; proc transpose data=_temp %if "&outputdenom" = "Y" %then %do; (drop=NumMemDays:) %end; out=_PTS prefix=NumPts; by &by.; run; %if "&outputdenom" = "Y" %then %do; proc transpose data=_temp(drop=NumPts:) out=_Days prefix=NumMemDays; by &by.; run; %end; /* Set mergenoby to nowarn to avoid triggering an e.r.r.o.r. or w.a.r.n.i.n.g. at this step */ options mergenoby=nowarn; data &outfile.; length &timeperiod. year 3; %if "&outputdenom" = "Y" %then %do; merge _Days(rename=_NAME_=_Days_) _PTS(rename=_NAME_=_PTS_); *No by; %end; %else %do; set _PTS(rename=_NAME_=_PTS_); %end; if _PTS_=:"NumPtsYM" then do; per=input(tranwrd(_PTS_, 'NumPtsYM' , ''),best.); date=intnx("&timeperiod.",&ExpPeriodStartDt.,per-1,'begin'); %if %str("&timeperiod.") = %str("quarter") %then %do; length quarter 3; quarter = qtr(date); %end; %else %do; &timeperiod.=&timeperiod.(date); %end; year=year(date); end; else do; per=input(tranwrd(_PTS_, 'NumPtsY' , ''),best.); date=intnx('year',&ExpPeriodStartDt.,per-1,'begin'); year=year(date); end; Rename %if "&outputdenom" = "Y" %then %do; NumMemDays1=DenNumMemDays %end; NumPts1=DenNumPts; keep year &timeperiod. &by. Num:; run; /* Reset mergenoby to original value (as stored in macro variable) */ options mergenoby=&mergenoby.; proc datasets nowarn noprint lib=work; delete _days _pts _temp; quit; %mend CreateSums; /*-----------------------------------------------------*/ /* Make sure the number of enrollment days remaining */ /* after each potential elig days is sufficient */ /*-----------------------------------------------------*/ * Get first Index Dates and Event Dates to handle member days correctly according to CohortDef; proc sql noprint; create table _Denom as select den.PatId, den.EligEpisode, den.Enr_Start, den.Enr_End, min(lst.IndexDt) as FIndexDt format date9. length=4, min(lst.FEventDt) as FEventDt format date9. length=4 from worktemp._denomOrig&Group. as den left join _ptsmasterlist &where_clause. as lst on den.PatId=lst.PatId group by den.PatId, den.EligEpisode, den.Enr_Start, den.Enr_end order by PatId, EligEpisode; quit; proc sort data = worktemp._denom&Group.(keep=PatId EligEpisode DenomEnrStartdt DenomEnrEnddt) out=_denom&Group.; by PatId EligEpisode; run; data _denom&Group.; merge _denom&Group.(in=a keep=PatId EligEpisode DenomEnrStartDt DenomEnrEndDt) _Denom; by PatId EligEpisode; format AdjustedEnrEndDt date9.; length AdjustedEnrEndDt 4; if a; * Adjust eligibility end date; AdjustedEnrEndDt = min(Enr_End, &censordate.) - Max(0,&MinEpisDur. - 1,&MinDaySupp. - 1,&BlackoutPer.,&reqdaysaftind., &reqdaysaftepi.+max(&MinEpisDur. - 1,&MinDaySupp. - 1,&BlackoutPer.)); DenomEnrEndDt = min(DenomEnrEndDt,AdjustedEnrEndDt); drop AdjustedEnrEndDt; /*secondary episode observation window*/ /*remove invalid time due to obsfrom-obsto enrollment/data availability criteria*/ if DenomEnrStartDt < enr_start + max(0,-1*&obs_from_index.,-1*&obs_from_epiend.) then DenomEnrStartDt = enr_start + max(0,-1*&obs_from_index.,-1*&obs_from_epiend.); if DenomEnrEndDt > min(enr_end, &censordate.) - max(0,&obs_to_index., &obs_to_epiend.) then DenomEnrEndDt = min(enr_end, &censordate.) - max(0,&obs_to_index., &obs_to_epiend.); if "&COHORTDEF."="01" then DenomEnrEndDt=min(DenomEnrEndDt,FIndexDt); if "&COHORTDEF."="03" then DenomEnrEndDt=min(DenomEnrEndDt,FEventDt); MemberDays = DenomEnrEndDt - DenomEnrStartDt + 1; * Because DenomEnrEndDt can have been truncated, keep only the observations with positive member days; if MemberDays>0; run; /*---------------------------*/ /* Add DOB/SEX/Race/Hispanic */ /*---------------------------*/ *Demogs; proc sql noprint; create table worktemp._denom&Group. as select distinct pts.*, birth_date, case when sex in('F', 'M') then sex else 'O' end as sex, race, hispanic, zip, zip_date from worktemp.enr_&enrollmentnum. as DEM inner join _denom&Group. as pts on DEM.patid = pts.patid; quit; /** Zip Codes **/ %if "&geog." = "Y" %then %do; proc sql noprint; create table _zip&Group. as select pts.*, lkup.statecode, lkup.hhs_region, lkup.cb_region from worktemp._denom&Group. as pts left join infolder.&zipfile. as lkup on pts.zip = lkup.zip order by pts.patid; quit; data worktemp._denom&Group.(drop=statecode cb_region hhs_region); length zip3 state hhs_reg cb_reg $7; set _zip&Group.; if missing(zip) then do; zip3 = 'Missing'; state = 'Missing'; hhs_reg = 'Missing'; cb_reg = 'Missing'; end; else if missing(statecode) then do; zip3 = 'Invalid'; state = 'Invalid'; hhs_reg = 'Invalid'; cb_reg = 'Invalid'; end; else do; zip3 = substr(strip(zip),1,3); state = statecode; cb_reg = cb_region; hhs_reg = hhs_region; if statecode ne '' and missing(hhs_region) then do; hhs_reg = 'Other'; end; if statecode ne '' and missing(cb_reg) then do; cb_reg = 'Other'; end; end; run; %END; %else %do; data worktemp._denom&Group.; set worktemp._denom&Group.; length zip3 state cb_reg hhs_reg $7 Zip_uncertain $1; zip3 = ''; state = ''; cb_reg = ''; hhs_reg = ''; Zip_uncertain = ''; run; %end; *truncate periods such that all interval lies in Minage-MaxAge; data worktemp._denom&Group.; set worktemp._denom&Group.; format MinAgeDt MaxAgeDt sfup date9.; length MinAgeDt MaxAgeDt sfup 4; MinAgeDt = intnx(scan("&AGETYP.",1),birth_date,&MINAGE.,'sameday'); if &MAXAGE.=99999 then MaxAgeDt=intnx('Years',birth_date,110,'sameday'); else MaxAgeDt= intnx(scan("&AGETYP.",&NBSTRAT.),birth_date,&MAXAGE.+1,'sameday'); *Member not meetin minimum age yet; if MinAgeDt > DenomEnrStartDt then DenomEnrStartDt=MinAgeDt; *can be pushed beyond DenomEnrEndDt; *Member has reached or will reach will reach maxage ; if MaxAgeDt <= DenomEnrEndDt then DenomEnrEndDt=MaxAgeDt-1; *can be pushed before DenomEnrStartDt; *Adjust; if DenomEnrStartDt <= DenomEnrEndDt; /* At this point, each day in the DenomEnrStartDt-DenomEnrEndDt intervals represents a potential index date if the patients would have started one of the study drugs. Now, we need to restrict only to the ExpPeriodStartDt-ExpPeriodEndDt period. This will simplify accumulating days for year and year/Month strata, especially if the ExpPeriodStartDt day is not the first day of the month and or the first month of the year */ sfup=input("&ExpPeriodStartDt.", best.); DenomEnrStartDt=max(DenomEnrStartDt,&ExpPeriodStartDt.); DenomEnrEndDt=min(DenomEnrEndDt,&ExpPeriodEndDt.); if DenomEnrStartDt<=DenomEnrEndDt; patient=1; %if "&outputdenom" = "Y" %then %do; MemberDays=DenomEnrEndDt-DenomEnrStartDt+1; %end; run; /*Save denominators for future processing*/ *Never Exposed Cohort; %if "&NEVEREXPOSEDCOHORT." = "Y" %then %do; data worktemp._nvrexp&Group.; set worktemp._denom&Group.; run; %end; *create individual denom contribution to final table; *need to do this individually to make sur we dont multiple-count *patients in the presence of different strata; /* If no observations in _denom&group, square the table */ %ISDATA(dataset=worktemp._denom&Group.); %IF %EVAL(&NOBS.=0) %THEN %DO; *Square table; %ms_squaredtableshell(squarevars = sex agegroupnum race hispanic %if "&geog" = "Y" %then %do; zip_uncertain %end; %if %index(%lowcase(&allstrat.), zip3) > 0 %then %do; zip3 %end; %if %index(%lowcase(&allstrat.), state) > 0 %then %do; state %end; %if %index(%lowcase(&allstrat.), hhs_reg) > 0 %then %do; hhs_reg %end; %if %index(%lowcase(&allstrat.), cb_reg) > 0 %then %do; cb_reg %end; ,analysis= N); data worktemp._denom&Group.; set worktemp._denom&Group. _mastersquare; patient=0; run; %END; /*macro to sum denominators for each stratification*/ %macro demomlevel(levelvars=, indataset=, outdataset=, where=1, createsumsby=, createsumsdimout=, createsumsinfile=); data _denomlevel; set userstrata_denom; where %if &ds_suffix. eq _prev %then %do; tableid in ("t2cidaprev", "t2itsprev") %end; %else %do; tableid not in ("t2cidaprev", "t2itsprev") %end; and levelvars = "&levelvars."; call symputx('denomlevel', levelid); run; * Check if level is required in userstrata file; %ISDATA(dataset=_denomlevel); %if %eval(&nobs.>=1) %then %do; * Check if level needs the CreateSums macro output; %if %length(&createsumsby.) > 0 %then %do; %ISDATA(dataset=&indataset.); %if %eval(&nobs.=0) %then %do; %CreateSums(infile=&createsumsinfile., outfile=&indataset., by=&createsumsby., dimout=&createsumsdimout. /* quarter periods */ %if %index(&levelvars., quarter) > 0 %then %do; ,timeperiod=quarter ,numtimeperiod=&numquarters. %end; /* geographic should not produce month/quarter output */ %if %index(&levelvars., zip_uncertain) > 0 or %index(&levelvars., zip3) > 0 or %index(&levelvars., state) > 0 or%index(&levelvars., hhs_reg) > 0 or %index(&levelvars., cb_reg) > 0 %then %do; ,timeperiod=month ,numtimeperiod=0 %end; ); %end; %end; %else %do; proc means data=&indataset. nway noprint missing; var %if "&outputdenom" = "Y" %then %do; MemberDays %end; Patient; class &levelvars. PatId; where &where.; output out=&outdataset.(drop=_:) %if "&outputdenom" = "Y" %then %do; sum(MemberDays)=DenNumMemDays %end; max(Patient)=DenNumPts; run; %end; proc means data= %if %length(&createsumsby.) > 0 %then %do; &indataset. %end; %else %do; &outdataset. %end; nway noprint missing; var %if "&outputdenom" = "Y" %then %do; DenNumMemDays %end; DenNumPts; %if %length(&levelvars.) > 0 %then %do; class &levelvars; %end; where &where.; output out=&outdataset.(drop=_:) %if "&outputdenom" = "Y" %then %do; sum(DenNumMemDays)= %end; sum(DenNumPts)=; run; * Add level number; data &outdataset.; set &outdataset.; length level $3; level = "&denomlevel"; run; %end; /* level is required */ %mend demomlevel; *Overall; %demomlevel(levelvars=, indataset=worktemp._denom&Group., outdataset=_denom_lvl_ALL); *Sex; %demomlevel(levelvars=sex, indataset=worktemp._denom&Group., outdataset=_denom_lvl_S); *Sex Year; %demomlevel(levelvars=sex year, indataset=_denom_lvl_SYM, outdataset=_denom_lvl_SY, where=%str(year ne . and month=.), createsumsby=sex, createsumsdimout=sex, createsumsinfile=worktemp._denom&Group.); *Year; %demomlevel(levelvars=year, indataset=_denom_lvl_SYM, outdataset=_denom_lvl_Y, where=%str(year ne . and month=.), createsumsby=sex, createsumsdimout=sex, createsumsinfile=worktemp._denom&Group.); *Year Month; %demomlevel(levelvars=month year , indataset=_denom_lvl_SYM, outdataset=_denom_lvl_YM, where=%str(year ne . and month ne .), createsumsby=sex, createsumsdimout=sex, createsumsinfile=worktemp._denom&Group.); *Sex Year Month; %demomlevel(levelvars=month sex year, indataset=_denom_lvl_SYM, outdataset=_denom_lvl_SYM, where=%str(year ne . and month ne .), createsumsby=sex, createsumsdimout=sex, createsumsinfile=worktemp._denom&Group.); *Year Quarter; %demomlevel(levelvars=quarter year , indataset=_denom_lvl_SYQ, outdataset=_denom_lvl_YQ, where=%str(year ne . and quarter ne .), createsumsby=sex, createsumsdimout=sex, createsumsinfile=worktemp._denom&Group.); *Sex Year Quarter; %demomlevel(levelvars=quarter sex year, indataset=_denom_lvl_SYQ, outdataset=_denom_lvl_SYQ, where=%str(year ne . and quarter ne .), createsumsby=sex, createsumsdimout=sex, createsumsinfile=worktemp._denom&Group.); *Race; %demomlevel(levelvars=race, indataset=worktemp._denom&Group., outdataset=_denom_lvl_R); *Race Year; %demomlevel(levelvars=race year, indataset=_denom_lvl_RYM, outdataset=_denom_lvl_RY, where=%str(year ne . and month eq .), createsumsby=race, createsumsdimout=race, createsumsinfile=worktemp._denom&Group.); *Race Year Month; %demomlevel(levelvars=month race year, indataset=_denom_lvl_RYM, outdataset=_denom_lvl_RYM, where=%str(year ne . and month ne .), createsumsby=race, createsumsdimout=race, createsumsinfile=worktemp._denom&Group.); *Race Year Quarter; %demomlevel(levelvars=quarter race year, indataset=_denom_lvl_RYQ, outdataset=_denom_lvl_RYQ, where=%str(year ne . and quarter ne .), createsumsby=race, createsumsdimout=race, createsumsinfile=worktemp._denom&Group.); *Race Sex; %demomlevel(levelvars=race sex, indataset=worktemp._denom&Group., outdataset=_denom_lvl_R_S); *Race Sex Year; %demomlevel(levelvars=race sex year, indataset=_denom_lvl_RSYM, outdataset=_denom_lvl_RSY, where=%str(year ne . and month eq .), createsumsby=race sex, createsumsdimout=sex, createsumsinfile=worktemp._denom&Group.); *Race Sex Year Month; %demomlevel(levelvars=month race sex year, indataset=_denom_lvl_RSYM, outdataset=_denom_lvl_RSYM, where=%str(year ne . and month ne .), createsumsby=race sex, createsumsdimout=sex, createsumsinfile=worktemp._denom&Group.); *Race Sex Year Quarter; %demomlevel(levelvars=quarter race sex year, indataset=_denom_lvl_RSYQ, outdataset=_denom_lvl_RSYQ, where=%str(year ne . and quarter ne .), createsumsby=race sex, createsumsdimout=sex, createsumsinfile=worktemp._denom&Group.); *Hispanic; %demomlevel(levelvars=hispanic, indataset=worktemp._denom&Group., outdataset=_denom_lvl_H); *Hispanic Year; %demomlevel(levelvars=hispanic year, indataset=_denom_lvl_HYM, outdataset=_denom_lvl_HY, where=%str(year ne . and month eq .), createsumsby=hispanic, createsumsdimout=hispanic, createsumsinfile=worktemp._denom&Group.); *Hispanic Year Month; %demomlevel(levelvars=hispanic month year, indataset=_denom_lvl_HYM, outdataset=_denom_lvl_HYM, where=%str(year ne . and month ne .), createsumsby=hispanic, createsumsdimout=hispanic, createsumsinfile=worktemp._denom&Group.); *Hispanic Year Quarter; %demomlevel(levelvars=hispanic quarter year, indataset=_denom_lvl_HYQ, outdataset=_denom_lvl_HYQ, where=%str(year ne . and quarter ne .), createsumsby=hispanic, createsumsdimout=hispanic, createsumsinfile=worktemp._denom&Group.); *Hispanic Sex; %demomlevel(levelvars=hispanic sex, indataset=worktemp._denom&Group., outdataset=_denom_lvl_H_S); *Hispanic Sex Year; %demomlevel(levelvars=hispanic sex year, indataset=_denom_lvl_HSYM, outdataset=_denom_lvl_HSY, where=%str(year ne . and month eq .), createsumsby=hispanic sex, createsumsdimout=sex, createsumsinfile=worktemp._denom&Group.); *Hispanic Sex Year Month; %demomlevel(levelvars=hispanic month sex year, indataset=_denom_lvl_HSYM, outdataset=_denom_lvl_HSYM, where=%str(year ne . and month ne .), createsumsby=hispanic sex, createsumsdimout=sex, createsumsinfile=worktemp._denom&Group.); *Hispanic Sex Year Quarter; %demomlevel(levelvars=hispanic quarter sex year, indataset=_denom_lvl_HSYQ, outdataset=_denom_lvl_HSYQ, where=%str(year ne . and quarter ne .), createsumsby=hispanic sex, createsumsdimout=sex, createsumsinfile=worktemp._denom&Group.); *Hispanic Race Year; %demomlevel(levelvars=hispanic race year, indataset=_denom_lvl_HRYM, outdataset=_denom_lvl_HRY, where=%str(year ne . and month eq .), createsumsby=hispanic race, createsumsdimout=race, createsumsinfile=worktemp._denom&Group.); *Hispanic Race Year Month; %demomlevel(levelvars=hispanic month race year, indataset=_denom_lvl_HRYM, outdataset=_denom_lvl_HRYM, where=%str(year ne . and month ne .), createsumsby=hispanic race, createsumsdimout=race, createsumsinfile=worktemp._denom&Group.); *Hispanic Race Year Quarter; %demomlevel(levelvars=hispanic quarter race year, indataset=_denom_lvl_HRYQ, outdataset=_denom_lvl_HRYQ, where=%str(year ne . and quarter ne .), createsumsby=hispanic race, createsumsdimout=race, createsumsinfile=worktemp._denom&Group.); %if "&agegroup_out" = "Y" %then %do; /*-------------------------------------------------*/ /* further breaking down periods by age categories */ /*-------------------------------------------------*/ data worktemp._denom&Group.age(rename=AgeDenomEnrEndDt=DenomEnrEndDt rename=AgeDenomEnrStartDt=DenomEnrStartDt); length agegroupnum 3; set worktemp._denom&Group.; format AgeGroup $9.; format threshdate AgeDenomEnrStartDt AgeDenomEnrEndDt date9.; length threshdate AgeDenomEnrStartDt AgeDenomEnrEndDt 4; AgeDenomEnrStartDt=DenomEnrStartDt; AgeDenomEnrEndDt=DenomEnrEndDt; do i=&NBSTRAT. to 1 by -1; threshdate=intnx(scan("&AGETYP.",i),birth_date,input(scan("&AGETHRESH.",i),best.),'sameday'); if threshdate <= AgeDenomEnrEndDt then do; AgeGroup = scan("&AGESTRAT.",i,' '); agegroupnum = i; AgeDenomEnrStartDt=max(threshdate,DenomEnrStartDt); %if "&outputdenom" = "Y" %then %do; MemberDays=AgeDenomEnrEndDt-AgeDenomEnrStartDt+1; %end; output; AgeDenomEnrEndDt=threshdate-1; if AgeDenomEnrEndDt < DenomEnrStartDt then leave; end; end; keep PatId AgeDenomEnrEndDt AgeDenomEnrStartDt sex race hispanic AgeGroup agegroupnum Patient %if "&outputdenom" = "Y" %then %do; MemberDays %end; threshdate %if "&geog" eq "Y" %then %do; hispanic zip3 state hhs_reg cb_reg %end;; run; *AgeGroup; %demomlevel(levelvars=agegroupnum, indataset=worktemp._denom&Group.age, outdataset=_denom_lvl_AG); *Sex AgeGroup; %demomlevel(levelvars=agegroupnum sex, indataset=worktemp._denom&Group.age, outdataset=_denom_lvl_SAG); *Sex AgeGroup Year; %demomlevel(levelvars=agegroupnum sex year, indataset=_denom_lvl_SAGYM, outdataset=_denom_lvl_SAGY, where=%str(year ne . and month=.), createsumsby=agegroupnum sex, createsumsdimout=sex, createsumsinfile=worktemp._denom&Group.age); *Sex AgeGroup Year Month; %demomlevel(levelvars=agegroupnum month sex year, indataset=_denom_lvl_SAGYM, outdataset=_denom_lvl_SAGYM, where=%str(year ne . and month ne .), createsumsby=agegroupnum sex, createsumsdimout=sex, createsumsinfile=worktemp._denom&Group.age); *Sex AgeGroup Year Quarter; %demomlevel(levelvars=agegroupnum quarter sex year, indataset=_denom_lvl_SAGYQ, outdataset=_denom_lvl_SAGYQ, where=%str(year ne . and quarter ne .), createsumsby=agegroupnum sex, createsumsdimout=sex, createsumsinfile=worktemp._denom&Group.age); *AgeGroup Year; %demomlevel(levelvars=agegroupnum year, indataset=_denom_lvl_AGYM, outdataset=_denom_lvl_AGY, where=%str(year ne . and month=.), createsumsby=agegroupnum, createsumsdimout=agegroupnum, createsumsinfile=worktemp._denom&Group.age); *AgeGroup Year Month; %demomlevel(levelvars=agegroupnum month year, indataset=_denom_lvl_AGYM, outdataset=_denom_lvl_AGYM, where=%str(year ne . and month ne .), createsumsby=agegroupnum, createsumsdimout=agegroupnum, createsumsinfile=worktemp._denom&Group.age); *AgeGroup Year Quarter; %demomlevel(levelvars=agegroupnum quarter year, indataset=_denom_lvl_AGYQ, outdataset=_denom_lvl_AGYQ, where=%str(year ne . and quarter ne .), createsumsby=agegroupnum, createsumsdimout=agegroupnum, createsumsinfile=worktemp._denom&Group.age); *Race AgeGroup; %demomlevel(levelvars=agegroupnum race, indataset=worktemp._denom&Group.age, outdataset=_denom_lvl_RAG); *Race AgeGroup Year; %demomlevel(levelvars=agegroupnum race year, indataset=_denom_lvl_RAGYM, outdataset=_denom_lvl_RAGY, where=%str(year ne . and month=.), createsumsby=agegroupnum race, createsumsdimout=race, createsumsinfile=worktemp._denom&Group.age); *Race AgeGroup Year Month; %demomlevel(levelvars=agegroupnum month race year, indataset=_denom_lvl_RAGYM, outdataset=_denom_lvl_RAGYM, where=%str(year ne . and month ne .), createsumsby=agegroupnum race, createsumsdimout=race, createsumsinfile=worktemp._denom&Group.age); *Race AgeGroup Year Quarter; %demomlevel(levelvars=agegroupnum quarter race year, indataset=_denom_lvl_RAGYQ, outdataset=_denom_lvl_RAGYQ, where=%str(year ne . and quarter ne .), createsumsby=agegroupnum race, createsumsdimout=race, createsumsinfile=worktemp._denom&Group.age); *Hispanic AgeGroup; %demomlevel(levelvars=agegroupnum hispanic, indataset=worktemp._denom&Group.age, outdataset=_denom_lvl_HAG); *Hispanic AgeGroup Year; %demomlevel(levelvars=agegroupnum hispanic year, indataset=_denom_lvl_HAGYM, outdataset=_denom_lvl_HAGY, where=%str(year ne . and month=.), createsumsby=agegroupnum hispanic, createsumsdimout=hispanic, createsumsinfile=worktemp._denom&Group.age); *Hispanic AgeGroup Year Month; %demomlevel(levelvars=agegroupnum hispanic month year, indataset=_denom_lvl_HAGYM, outdataset=_denom_lvl_HAGYM, where=%str(year ne . and month ne .), createsumsby=agegroupnum hispanic, createsumsdimout=hispanic, createsumsinfile=worktemp._denom&Group.age); *Hispanic AgeGroup Year Quarter; %demomlevel(levelvars=agegroupnum hispanic quarter year, indataset=_denom_lvl_HAGYQ, outdataset=_denom_lvl_HAGYQ, where=%str(year ne . and quarter ne .), createsumsby=agegroupnum hispanic, createsumsdimout=hispanic, createsumsinfile=worktemp._denom&Group.age); %end; /* agegroup requested */ %if "&geog." = "Y" %then %do; /*-------------------------------------------------*/ /* Geographic categories */ /*-------------------------------------------------*/ /*Produce Uncertain level stratifications, regardless of Geographic region specified*/ /*Need to adjust denominator for zip_date*/ data worktemp._denom&Group._un(rename=ZipDenomEnrEndDt=DenomEnrEndDt rename=ZipDenomEnrStartDt=DenomEnrStartDt); set worktemp._denom&Group.; format ZipDenomEnrStartDt ZipDenomEnrEndDt date9.; length ZipDenomEnrStartDt ZipDenomEnrEndDt 4; ZipDenomEnrStartDt=DenomEnrStartDt; ZipDenomEnrEndDt=DenomEnrEndDt; /*1. if zip_date < DenomEnrStartDt, full enrollment is certain*/ if . < zip_date < DenomEnrStartDt then do; %if "&outputdenom" = "Y" %then %do; MemberDays=DenomEnrEndDt-DenomEnrStartDt+1; %end; zip_uncertain = 'N'; output; end; /*2. if zip_date is missing, full enrollment is uncertain*/ else if zip_date = . then do; %if "&outputdenom" = "Y" %then %do; MemberDays=DenomEnrEndDt-DenomEnrStartDt+1; %end; zip_uncertain = 'Y'; output; end; /*3. if zip_date > ZipEnrEnd, then no uncertain time*/ else if zip_date >= DenomEnrEndDt then do; %if "&outputdenom" = "Y" %then %do; MemberDays=DenomEnrEndDt-DenomEnrStartDt+1; %end; zip_uncertain = 'Y'; output; end; /*4. if DenomEnrStartDt <= zip_date <= DenomEnrEndDt, then calculate uncertain time*/ else do; zip_uncertain = 'Y'; /*Adjust Denom enrollment*/ ZipDenomEnrEndDt=zip_date; %if "&outputdenom" = "Y" %then %do; MemberDays=zip_date-DenomEnrStartDt+1; %end; output; zip_uncertain = 'N'; ZipDenomEnrStartDt=zip_date+1; ZipDenomEnrEndDt = DenomEnrEndDt; %if "&outputdenom" = "Y" %then %do; MemberDays=ZipDenomEnrEndDt-ZipDenomEnrStartDt+1; %end; /*member is certain on zip_date*/ output; end; keep PatId ZipDenomEnrEndDt ZipDenomEnrStartDt sex Patient %if "&outputdenom" = "Y" %then %do; MemberDays %end; zip_uncertain zip_date birth_date race hispanic zip3 state hhs_reg cb_reg; run; *Zip_Uncertain; %demomlevel(levelvars=zip_uncertain, indataset=worktemp._denom&Group._un, outdataset=_denom_lvl_U); *Zip_Uncertain Sex; %demomlevel(levelvars=sex zip_uncertain, indataset=worktemp._denom&Group._un, outdataset=_denom_lvl_U_S); *Zip_Uncertain Year; %demomlevel(levelvars=year zip_uncertain, indataset=_denom_lvl_U_Y, outdataset=_denom_lvl_U_Y, where=%str(year ne . and month eq .), createsumsby=zip_uncertain, createsumsdimout=zip_uncertain, createsumsinfile=worktemp._denom&Group._un); %if "&agegroup_out" = "Y" %then %do; data worktemp._denom&Group.age_un(rename=AgeDenomEnrEndDt=DenomEnrEndDt rename=AgeDenomEnrStartDt=DenomEnrStartDt); length agegroupnum 3; set worktemp._denom&Group._un; format AgeGroup $9.; format threshdate AgeDenomEnrStartDt AgeDenomEnrEndDt date9.; length threshdate AgeDenomEnrStartDt AgeDenomEnrEndDt 4; AgeDenomEnrStartDt=DenomEnrStartDt; AgeDenomEnrEndDt=DenomEnrEndDt; do i=&NBSTRAT. to 1 by -1; threshdate=intnx(scan("&AGETYP.",i),birth_date,input(scan("&AGETHRESH.",i),best.),'sameday'); if threshdate <= AgeDenomEnrEndDt then do; AgeGroup = scan("&AGESTRAT.",i,' '); agegroupnum = i; AgeDenomEnrStartDt=max(threshdate,DenomEnrStartDt); %if "&outputdenom" = "Y" %then %do; MemberDays=AgeDenomEnrEndDt-AgeDenomEnrStartDt+1; %end; output; AgeDenomEnrEndDt=threshdate-1; if AgeDenomEnrEndDt < DenomEnrStartDt then leave; end; end; keep PatId AgeDenomEnrEndDt AgeDenomEnrStartDt sex AgeGroup agegroupnum Patient %if "&outputdenom" = "Y" %then %do; MemberDays %end; threshdate zip_uncertain zip3 state hhs_reg cb_reg; run; *Zip_Uncertain AgeGroup; %demomlevel(levelvars=agegroupnum zip_uncertain, indataset=worktemp._denom&Group.age_un, outdataset=_denom_lvl_U_AG); %end; %macro geogdenoms(strata=); %let curlevelvars=; %macro getsortedlevelvars(levelvars=); data _denomcurlevelvars(rename=curlevelvars_out=curlevelvars); curlevelvars="&levelvars."; %alphabetizevarutil(array=a, in=curlevelvars, out=curlevelvars_out); run; proc sql noprint; select curlevelvars into :curlevelvars trimmed from _denomcurlevelvars; quit; %mend getsortedlevelvars; *&Strata.(State/Zip/Census/HHS); %demomlevel(levelvars=&strata., indataset=worktemp._denom&Group, outdataset=_denom_lvl_&strata.); *&Strata. Sex; %getsortedlevelvars(levelvars=%str(&strata. sex)); %demomlevel(levelvars=&curlevelvars., indataset=worktemp._denom&Group, outdataset=_denom_lvl_&strata._S); *&Strata. Race; %getsortedlevelvars(levelvars=%str(&strata. race)); %demomlevel(levelvars=&curlevelvars., indataset=worktemp._denom&Group, outdataset=_denom_lvl_&strata._R); *&Strata. Zip_Uncertain Race; %getsortedlevelvars(levelvars=%str(&strata. zip_uncertain race)); %demomlevel(levelvars=&curlevelvars., indataset=worktemp._denom&Group._un, outdataset=_denom_lvl_&strata._U_R); *&Strata. Hispanic; %getsortedlevelvars(levelvars=%str(&strata. hispanic)); %demomlevel(levelvars=&curlevelvars., indataset=worktemp._denom&Group, outdataset=_denom_lvl_&strata._H); *&Strata. Zip_Uncertain Hispanic; %getsortedlevelvars(levelvars=%str(&strata. zip_uncertain hispanic)); %demomlevel(levelvars=&curlevelvars., indataset=worktemp._denom&Group._un, outdataset=_denom_lvl_&strata._U_H); %if "&agegroup_out" = "Y" %then %do; *&Strata. AgeGroup; %getsortedlevelvars(levelvars=%str(&strata. agegroupnum)); %demomlevel(levelvars=&curlevelvars., indataset=worktemp._denom&Group.age, outdataset=_denom_lvl_&strata._AG); *&Strata. Zip_Uncertain AgeGroup; %getsortedlevelvars(levelvars=%str(&strata. agegroupnum zip_uncertain)); %demomlevel(levelvars=&curlevelvars., indataset=worktemp._denom&Group.age_un, outdataset=_denom_lvl_&strata._U_AG); %end; *&Strata. Year; %getsortedlevelvars(levelvars=%str(&strata. year)); %demomlevel(levelvars=&curlevelvars., indataset=_denom_lvl_&strata._Y, outdataset=_denom_lvl_&strata._Y, where=%str(year ne . and month=.), createsumsby=&strata., createsumsdimout=&strata., createsumsinfile=worktemp._denom&Group.); *&Strata. Zip_Uncertain; %getsortedlevelvars(levelvars=%str(&strata. zip_uncertain)); %demomlevel(levelvars=&curlevelvars., indataset=worktemp._denom&Group._un, outdataset=_denom_lvl_&strata._U); *&Strata. Zip_Uncertain Sex; %getsortedlevelvars(levelvars=%str(&strata. zip_uncertain sex)); %demomlevel(levelvars=&curlevelvars., indataset=worktemp._denom&Group._un, outdataset=_denom_lvl_&strata._U_S); *&Strata. Zip_Uncertain Year; %getsortedlevelvars(levelvars=%str(&strata. year zip_uncertain)); %demomlevel(levelvars=&curlevelvars., indataset=_denom_lvl_&strata._U_Y, outdataset=_denom_lvl_&strata._U_Y, where=%str(year ne . and month=.), createsumsby=&strata. zip_uncertain, createsumsdimout=zip_uncertain, createsumsinfile=worktemp._denom&Group._un); %mend; %if %index(%lowcase(&allstrat.), zip3) > 0 %then %do; %geogdenoms(strata=zip3); %end; %if %index(%lowcase(&allstrat.), state) > 0 %then %do; %geogdenoms(strata=state); %end; %if %index(%lowcase(&allstrat.), hhs_reg) > 0 %then %do; %geogdenoms(strata=hhs_reg); %end; %if %index(%lowcase(&allstrat.), cb_reg) > 0 %then %do; %geogdenoms(strata=cb_reg); %end; %end; /* geog requested */ data _denomsquare; format sex zip_uncertain race hispanic $1. zip3 state hhs_reg cb_reg $7.; length agegroupnum month year quarter 3; call missing (of _all_); run; *Verify if at least one stratum was computed; %let denomlvlcount=0; proc sql noprint; select count(*) into :denomlvlcount from userstrata_denom where %if &ds_suffix. eq _prev %then %do; tableid in ("t2cidaprev", "t2itsprev") %end; %else %do; tableid not in ("t2cidaprev", "t2itsprev") %end; ; quit; data _DenomCounts; format group $40. race hispanic $1. zip3 state hhs_reg cb_reg $7.; set _denomsquare(obs=0) %if %eval(&denomlvlcount. > 0) %then %do; _denom_lvl: %end;; group="&itgroup."; * Some datasets where created to allow them to be reused for efficiency, but their strata might not have been requested. Need to delete rows with empty level; if missing(level) then delete; if missing(DenNumPts) then DenNumPts = 0; %if "&outputdenom" = "M" %then %do; DenNumMemDays=.; %end; %else %do; if missing(DenNumMemDays) then DenNumMemDays = 0; %end; run; *Store patient denoms to DPLocal; %IF %EVAL(&group.=1) | (%str(&ds_suffix.) ne %str() and %eval(&group. = &firstprevgroup.)) %then %DO; data DPLocal.&RUNID._DenomCounts&ds_suffix.; retain Level group sex agegroupnum year month quarter race hispanic zip3 state hhs_reg cb_reg zip_uncertain DenNumPts DenNumMemDays; set _DenomCounts; run; %END; %ELSE %DO; proc append base=DPLocal.&RUNID._DenomCounts&ds_suffix. data=_DenomCounts force; run; %END; *delete datasets; proc datasets nowarn noprint lib=work; delete _unelig: _denom_lvl:; quit; %mend cidadenom_prev_inc; /* Create Prevalent and Incident dataset for Type2 when requested */ %if %eval(&type=2) and %eval(&numprevgroups. > 0) %then %do; %cidadenom_prev_inc (l = 1, ds_suffix =, where_clause = %str((where = (PrevInc = "Inc")))); %if %str("&autoprev.") = %str("Y") %then %do; %cidadenom_prev_inc (l = 2, ds_suffix =_prev, where_clause = %str((where = (PrevInc_def in ("Both","Prev"))))); %end; %end; %else %do; %cidadenom_prev_inc(l=0, ds_suffix = , where_clause = ); %end; /* Delete denom datasets from worktemp */ proc datasets nowarn noprint lib=worktemp; delete _denom:; quit; proc datasets nowarn noprint lib=work; delete _denom: _zip:; quit; *Output run time; %ms_stoptimer(timestart=denomruntime); %ms_outputruntimes(timevar=denomruntime, step=%str(CIDA denominators), group=&itgroup., monitoringperiod=); %end; /*outputdenom ne N and userstrata contains relevant tables*/ %else %do; /*Create empty dataset*/ %macro createemptydenom(ds_suffix=); data _denomcounts; format group $40. level $3. race hispanic sex zip_uncertain $1. zip3 state hhs_reg cb_reg $7.; length year month quarter agegroupnum 3; call missing(group, level, race, hispanic, sex, zip_uncertain, zip3, state, hhs_reg, cb_reg, year, month, quarter, agegroupnum, DenNumPts, DenNumMemDays); stop; run; %if %eval(&group.=1) | (%str(&ds_suffix.) ne %str() and %eval(&group. = &firstprevgroup.)) %then %do; data dplocal.&RUNID._DenomCounts&ds_suffix.; set _DenomCounts; run; %end; %else %do; proc append base=DPLocal.&RUNID._DenomCounts&ds_suffix. data=_DenomCounts force; run; %end; %mend; %if %eval(&type=2) and %eval(&numprevgroups. > 0) %then %do; %createemptydenom(ds_suffix =); %if %str("&autoprev.") = %str("Y") %then %do; %createemptydenom(ds_suffix =_prev); %end; %end; %else %do; %createemptydenom(ds_suffix=); %end; %if "&outputdenom" ne "N" %then %do; %put "WARNING: (Sentinel) Denominators are requested (OUTPUTDENOM is not set to N) but USERSTRATA does not contain any related levelid."; %end; %end; /*outputdenom = N or userstrata contains relevant tables*/ %put NOTE: ******** END OF MACRO: ms_cidadenom ********; %mend ms_cidadenom;