**************************************************************************************************** * PROGRAM OVERVIEW **************************************************************************************************** * * PROGRAM: ms_cidacov.sas * * Created (mm/dd/yyyy): 12/19/2014 * Last modified: 03/27/2017 * Version: 2.9 * *-------------------------------------------------------------------------------------------------- * PURPOSE: * This macro will manage covariates. * * Program inputs: * -DPLocal.&RUNID._&data. * -infolder.&COHORTFILE. * -infolder.&UTILFILE. * -infolder.Comorbcodes * -infolder.&Covariatecodes. * -infolder.&DRUGCLASSFILE. * -infolder.&MONITORINGFILE. * * Program outputs: * -DPLocal.&RUNID._ads_&data. * -DPLocal.&RUNID._Claims_icddx09 * -DPLocal.&RUNID._Claims_icddx10 * -DPLocal.&RUNID._Claims_icddxOT * -DPLocal.&RUNID._Claims_icdpx09 * -DPLocal.&RUNID._Claims_icdpx10 * -DPLocal.&RUNID._Claims_icdpxOT * -DPLocal.&RUNID._Claims_cpt * -DPLocal.&RUNID._Claims_hcpcs * -DPLocal.&RUNID._Claims_drugclass * -DPLocal.&RUNID._Claims_rx * -DPLocal.&RUNID._Claims_lab * -MSOC.&RUNID._baseline&outcohort._&i.; * -MSOC.&RUNID._profile._&i.; * -MSOC.&RUNID._baseline_&mfu._&i.; * PARAMETERS: * -data: indicates input the patient-level dataset * -outcohort: indicates the suffix for output baseline table if additional cohorts are created * * Programming Notes: * -This macro includes the optional execution of ms_util and ms_cci_elix macros * * *-------------------------------------------------------------------------------------------------- * CONTACT INFO: * Mini-Sentinel Coordinating Center * info@mini-sentinel.org * *-------------------------------------------------------------------------------------------------- * CHANGE LOG: * * Version Date Initials Comment (reference external documentation when available) * ------- -------- -------- --------------------------------------------------------------- * 1.3 03/31/2015 AC Made changes to programming notes in header section. * * 1.4 03/31/2015 EM Adapt code to Surveilance mode. * * 1.5 06/30/2015 EM Removed Surveillance Analysis related code * * 1.6 06/30/2015 EM Calculation of a baseline table (similar to table 1) for TYPE1 and TYPE2 requests. * * 1.7 12/23/2015 EM Changed age group names to be consitent with table 1. * * 1.8 01/15/2016 VC Allow for greater flexibility specifying the covariate assessment window. * Create combined covariate variables. * * 1.9 04/21/2016 DM Added a w.a.r.n.i.n.g. when no baseline table is produced because no * users were identified in the request * * 1.10 08/10/2016 AP(SOC) Added 2 new HDPS dimension files (DX10 and PX10) for ICD10 (QCI-186) * * 1.11 08/15/2016 DM Added Surveillance Analysis related code removed in 1.5 * * 1.12 10/17/2016 DM Fixed a couple of issues regarding Surveillance Analysis * * 1.13 11/30/2016 AP Removed infolder libname from Monitoring File sort to accomodate * truncation by DPMax Date * * 1.14 12/09/2016 AP Remove KeepAllDum as a parameter in the ComorbFile * * 1.15 12/12/2016 AP Removed code that de-duped RX codes across covariates (QRP-289) * * 2.0 03/27/2017 DM Removed covariates extraction from CDM. Now done earlier in ms_cidanum * * 2.1 05/05/2017 AP Added race, hispanic, and year to baseline table * * 2.2 07/10/2017 AP 1. Added baseline table for Types 3-5 * 2. Added covariate profile table * 3. Added MFU analysis * * 2.3 09/14/2017 AP Bug fix (QRP-429) * * 2.4 09/27/2017 AP Changed Type 3 dataset names, MFU lab extraction (QRP-432, QRP-433) * * 2.5 11/15/2017 AP Added shaving of covariates (QRP-419) * * 2.6 12/07/2017 AP 1. Fixed PX table name in CCI macro call (QRP-469) * 2. Sorting T4 control group by delnum (QRP-471) * * 2.7 12/21/2017 AP 1. Modified comorbidity score window parameters (QRP-435) * 2. Added CODEDAYS to covariate selection (QRP-455) * * 2.8 02/27/2018 RR 1. Ability to add never exposed group if requested (QRP-495) * * 2.9 03/27/2018 AP Removed group variable from ms_util hash table (QRP-534) * ***************************************************************************************************; %macro ms_cidacov(data=, outcohort=); %put =====> MACRO CALLED: ms_cidacov v2.9; %ms_starttimer(START=CIDACOV); %put Macro will further read raw data using the prefix Libname: &DataLib.; /******************/ /* Pre-Processing */ /******************/ *List of patients from CIDANum; proc sort nodupkey data=DPLocal.&RUNID._&data. out=PtsList(keep=Patid); by Patid; run; proc sort nodupkey data=DPLocal.&RUNID._&data. out=&RUNID._&data.; by Group Patid IndexDt; run; *must have at least one patient; %isdata(dataset=&RUNID._&data.); %if %eval(&NOBS. > 0) %then %do; %ISDATA(dataset=infolder.&COVARIATECODES.); %IF %EVAL(&NOBS.>0) %THEN %DO; proc sql noprint; select count (distinct CovarNum) into :NumCovars from infolder.&COVARIATECODES. where codecat not in ("CC"); quit; proc sql noprint; select count (distinct CovarNum) into :NumComb from infolder.&COVARIATECODES. where codecat in ("CC"); quit; %put Number of covars: &NumCovars; %put Number of covarComb: &NumComb; %END; *Assign pointer to prior DPLocal when running surveillance mode; %global DPLOCALPOINTER; %let DPLOCALPOINTER=DPLocal; %if "&SURVEILLANCEMODE."="f" or "&SURVEILLANCEMODE."="p" %then %let DPLocalPointer=DPLPrior; %put NOTE: DPLOCAL for prior run is set to &DPLocalPointer.; *Creating the number of groups to create cohorts; %isdata(dataset=COHORTFILE); data _null_; call symputx("Numgroup","&nobs."); run; *creating agegroupsort to add to master patient file; %macro addagegroupsort; %do group = 1 %to &Numgroup.; data _age&group.; set cohortfile; if _n_ = &group.; if missing(agestrat) then agestrat = "00-01 02-04 05-09 10-14 15-18 19-21 22-44 45-64 65-74 75+"; numgrp = countw(AGESTRAT," ") ; do i=1 to numgrp; AgeGroup=scan(AGESTRAT,i, " "); AgeGroupSort=i; output; end; keep group AgeGroup AgeGroupSort; run; %end; data _age; set %do group = 1 %to &Numgroup.; _age&group. %end;; run; proc sql noprint undo_policy=none; create table dplocal.&runid._&data. as select mstr.*, age.AgeGroupSort from DPLocal.&RUNID._&data. as mstr left join _age as age on age.AgeGroup=mstr.AgeGroup and upcase(age.group) = upcase(mstr.group) order by Group, PatID, IndexDt; quit; %mend addagegroupsort; %addagegroupsort; *Initialize the number of groups; %let Ngrp = 1; /*********************************/ /* Compute Utilization Variables */ /*********************************/ %macro RunUtil; %ISDATA(dataset=UTILFILE); %IF %EVAL(&NOBS.>0) %THEN %DO; *Extracting Encounter Data; data _BaseEnc(keep=PatId ADate EncType); if 0 then set PtsList; declare hash ht (hashexp:16, dataset:"PtsList"); ht.definekey('PatId'); ht.definedone(); do until(eof1); set &datalib.&encTable. end=eof1; if ht.find()=0 then output; end; stop; run; %do Group=1 %to &Numgroup.; *Processing Util parameters; Data _ITUtil; set UTILFILE; if _n_ = &Group.; call symputx('ITGROUP',strip(Group)); if INCLINDEX=. then INCLINDEX=0; *defensive coding - must be populated; *always looking backwards (<0); call symputx("MEDUTILFROM",-1*MEDUTILFROM); *always looking forward (>=0); if MEDUTILTO >=0 then call symputx("MEDUTILTO",MEDUTILTO+1); /*+1 because in ms_util, &medutilto = 0 excludes index*/ else call symputx("MEDUTILTO",0); call symputx("CARESETTINGS",compress(CARESETTINGS,"',")); *defensive coding; if "&Analysis."="ps" or "&Analysis."="ads" or "&Analysis."="ms" then do; call symputx("CARESETTINGS","'AV' 'OA' 'IP' 'IS' 'ED'"); *defensive coding; call symputx("BYENC","Y"); end; else call symputx("BYENC","N"); call symputx("CSSTRAT",CSSTRAT); run; %put &CARESETTINGS.; data _null_; set COHORTFILE; if Group = "&ITGROUP." then do; call symputx('ITGROUP',strip(Group)); end; run; %put &group. &ITGROUP.; *Creating index reference file; proc sort data=&RUNID._&data. out= _indexfile(keep=patid indexdt) %if %eval(&type.=5) %then %do; nodupkey %end; ; by patid group indexdt; where group = "&ITGROUP."; run; *Calculate Utilization; %MS_UTIL(ENCOUNTERFILE=_BaseEnc, INDEXFILE=_IndexFile, INDEXDT=IndexDt, PRIORDAYS=&MEDUTILFROM., INCLINDEX=&MEDUTILTO., CARESETTINGS=&CARESETTINGS., BYENC=&BYENC., CSSTRAT=&CSSTRAT., OUTFILE=_ITUtil ); *Post Process; data _ITUtil; set _ITUtil; format group $40.; Group="&ITGROUP."; length NumVisits $10.; format NumVisits $10.; NumVisits=NumVisit; drop NumVisit; run; *Combine Util for multiple groups; %IF %EVAL(&group.=1) %THEN %DO; data _AllUtil; set _ITUtil; run; %END; %ELSE %DO; proc append base=_AllUtil data=_ITUtil force; run; %END; *Clean-up; proc datasets library=work nolist nowarn; delete _ITUtil _IndexFile; quit; proc sort data=_AllUtil; by Group PatId IndexDt; run; %END; *do loop; %if "&SURVEILLANCEMODE."="f" or "&SURVEILLANCEMODE."="p" %then %do; data _NewPatients; set DPLocal.&RUNID._&data.; where &PERIODIDSTART. <= IndexLook <= &PERIODIDEND.; keep Group PatId IndexDt; run; proc sort nodupkey; by Group PatId IndexDt; run; data _AllUtil; merge _AllUtil(in=a) _NewPatients(in=b); by Group PatId IndexDt; if a and b; run; %end; data DPLocal.&RUNID._&data.; merge DPLocal.&RUNID._&data. _AllUtil; by Group PatId IndexDt; run; %ISDATA(dataset=infolder.&DRUGCLASSFILE.); %IF %EVAL(&NOBS.>0) %THEN %DO; proc sort data=&RUNID._&data. out= _BaseTmp(keep=group patid indexdt) %if %eval(&type.=5) %then %do; nodupkey %end; ; by group patid indexdt; run; *Adding DRUGUTIL window to base file; data _BaseTmp; if 0 then set UTILFILE(Keep=Group DrugUtilFrom DrugUtilTo); declare hash ht (hashexp:16, dataset:"UTILFILE"); ht.definekey('Group'); ht.definedata('DrugUtilFrom','DrugUtilTo'); ht.definedone(); do until(eof1); set _BaseTmp end=eof1; if ht.find()=0 then do; if .<DrugUtilFrom < 0 then DrugUtilFrom=-1*DrugUtilFrom; output; end; end; stop; run; *calculate NumGeneric-NumClass; *extract Rx data in covariatewindow before IndexDt; proc sql noprint; create table _UtilRx as select Pts.Group, Pts.PatId, Pts.IndexDt, disp.NDC from _BaseTmp as pts, &DataLib.&DisTable. as disp where pts.PatId = disp.Patid and %MS_PeriodsOverlap(period1=pts.IndexDt-COALESCE(pts.DrugUtilFrom,99999) COALESCE(pts.indexdt+DrugUtilTo/*-1*/,99999), period2=disp.RxDate); quit; *get Generic ClassName; proc sql noprint; create table _UtilRxClassGen as select Pts.Group, Pts.PatId, Pts.IndexDt, RxCl.Generic, RxCl.ClassName, 1 as one from _UtilRx as pts, infolder.&DRUGCLASSFILE. as RxCl where pts.NDC = RxCl.ndc; quit; *Count number of rows in dispensing table with NDC in drugclass file ; proc sql noprint; create table _NumRx as select Pts.Group, Pts.PatId, Pts.IndexDt, 1 as one from _UtilRx as pts, (select distinct ndc from infolder.&DRUGCLASSFILE.) as RxCl where pts.NDC = RxCl.ndc; quit; proc means data=_NumRx noprint nway; var one; class Group PatId IndexDt; output out=_NumRx(drop=_:) sum=NumRx; run; *Count number of disctinct Generic; proc sort nodupkey data=_UtilRxClassGen out=_Generic; by Group PatId IndexDt Generic; run; proc means data=_Generic noprint; var one; by Group PatId IndexDt; output out=_Generic(drop=_:) sum=NumGeneric; run; *Count number of disctinct ClassName; proc sort nodupkey data=_UtilRxClassGen out=_ClassName; by Group PatId IndexDt ClassName; run; proc means data=_ClassName noprint; var one; by Group PatId IndexDt; output out=_ClassName(drop=_:) sum=NumClass; run; *combine all three metrics; data _combine; merge _Generic _ClassName _NumRx; by Group PatId IndexDt; run; %if "&SURVEILLANCEMODE."="f" or "&SURVEILLANCEMODE."="p" %then %do; data _combine; merge _combine(in=a) _NewPatients(in=b); by Group PatId IndexDt; if a and b; run; %if %eval(&PERIODIDSTART.>1) %then %do; %macro PriorPeriods; *complete covariates with pre-indexdt values from prior periods; data _PriorPeriods; set &DPLOCALPOINTER..&RUNID._ads_&data._%eval(&PERIODIDSTART.-1); by Group PatId IndexDt; keep Group PatId IndexDt NumGeneric NumClass NumRx; run; %mend; %PriorPeriods; data _baseTmp; merge _baseTmp _PriorPeriods; by Group PatId IndexDt; run; proc datasets library=work nolist nowarn; delete _PriorPeriods; run; %end; %end; *put Back in _Base; data _baseTmp; merge _baseTmp(in=a) _combine(keep=Group PatId IndexDt NumRx NumGeneric NumClass); *combine only contains new patients - other vars already updated; by Group PatId IndexDt; if a; run; *Update Master file with utilization data; data DPLocal.&RUNID._&data.; merge DPLocal.&RUNID._&data. _basetmp; by Group PatId IndexDt; if missing(NumRx) then NumRx=0; if missing(NumGeneric) then NumGeneric=0; if missing(NumClass) then NumClass=0; run; proc datasets library=work nolist nowarn; delete _BaseEnc IndexFile _:; quit; %END; %ISDATA(dataset=infolder.&DRUGCLASSFILE.); %IF %EVAL(&NOBS.=0) %THEN %DO; data DPLocal.&RUNID._&data.; set DPLocal.&RUNID._&data.; NumRx=.; NumGeneric=.; NumClass=.; run; %END; %END; %ELSE %DO; data DPLocal.&RUNID._&data.; set DPLocal.&RUNID._&data.; ExactNumVisit=.; NumVisits_AV=.; NumVisits_IP=.; NumVisits_ED=.; NumVisits_OA=.; NumVisits_IS=.; NumVisits=""; NumRx=.; NumGeneric=.; NumClass=.; run; %END; *util calcs; %mend; %RunUtil; /*********************************************/ /* and pre-extract the data for ADS */ /* and Charlson Comorbidity/Elixhauser Index */ /*********************************************/ %macro RunCovExtraction; *Test whether extraction is necessary; %IF %LENGTH(&CovarCodes.) | %LENGTH(&Comorbfile.) %THEN %DO; * Extraction needed: Create extraction lookup files; data _CovRx CovMeds; set &ComborbsCodes. &CovarCodes.; if CodeCat="RX" then output _CovRx; &CovarCodes2.; run; %MS_ProcessWildcards(InFile=CovMeds, CodeVar=code, OutFile=CovMeds); *Break out CaresettingPrincipal into Caresetting and Principal; %ms_caresettingprincipal(InFile=CovMeds, Var=CareSettingPrincipal, OutFile=CovMeds); *Extracting meds using EncType and PDX to meds; %ms_loopmeds(datafile=Meds, lookfile=CovMeds, outfile=_temp_PreMeds); *restricting to pts in cidanum; data _temp_PreMeds1(rename=DummyDate=ADate); if 0 then set PtsList; declare hash pt (hashexp:16, dataset:"PtsList"); pt.definekey('PatId'); pt.definedone(); do until(eof1); set _temp_PreMeds end=eof1; if pt.find()=0 then do; format DummyDate mmddyy10.; length DummyDate 4.; DummyDate=ADate; RxSup=1; RxAmt=1; drop ADate; output; end; end; stop; run; %ms_extractdrugs(datafile=Drugs, datavar=NDC , lookfile=_CovRx(drop=codecat CodeType), lookvar=code, outfile=_temp_PreDrugs); *restricting to pts in cidanum; data _temp_PreDrugs1; if 0 then set PtsList; declare hash pt1 (hashexp:16, dataset:"PtsList"); pt1.definekey('PatId'); pt1.definedone(); do until(eof1); set _temp_PreDrugs end=eof1; if pt1.find()=0 then do; RxSupEndDt=Rxdate+RxSup-1; output; end; end; stop; run; proc sort nodupkey data=_temp_PreDrugs(keep=StudyName StockGroup NDC Comorbcode CovarNum CovFrom CovTo CARESETTINGPRINCIPAL codedays) out=PreDrugParams; by StudyName StockGroup; run; *separate out covariates; data ElixMeds (drop=covfrom covto) _temp_PreMeds2; set _temp_PreMeds1; if Comorbcode eq 1 then output ElixMeds; else output _temp_PreMeds2; run; proc datasets nowarn noprint lib=work; delete _temp_PreMeds1 _temp_PreMeds _temp_PreDrugs; quit; *Loop through groups to shave claims, stockpile, then re-shave; %do Group=1 %to &Ngroup.; data _null_; set infolder.&COHORTFILE.; if _n_ = &Group. then do; call symputx('ITGROUP',strip(Group)); end; run; %IF %eval(&type.) = 2 %THEN %DO; *Creating index reference file; proc sort data=&RUNID._&data. out= _ptsgroup(keep=patid group) nodupkey; by patid group; where group in ("&ITGROUP.", "&ITGROUP._nvrexp"); run; proc sql noprint; select count(distinct group) as group into: Ngrp from _ptsgroup; quit; %END; %ms_shaveoutside(reffile=ENR_&GROUP., refstart=Enr_Start, refend=Enr_End, KeepPartBf=N, ToShaveFile=_temp_PreMeds2, ToShaveStart=ADate, ToShaveEnd=ADate, outfile=PreMeds_&group.); %ms_shaveoutside(reffile=ENR_&GROUP., refstart=Enr_Start, refend=Enr_End, KeepPartBf=N, ToShaveFile=_temp_PreDrugs1, ToShaveStart=RxDate, ToShaveEnd=RxSupEndDt, outfile=_temp_PreDrugs2); *Apply stockpiling; %MS_STOCKPILING(INFILE=_temp_PreDrugs2, CLMDATE=RxDate, CLMSUP=RxSup, CLMAMT=RxAmt, PROCFLAG=, PERCENTDAYS=&PERCENTDAYS., GROUPING=StudyName StockGroup, SAMEDAY=&SAMEDAY., SUPRANGE=&SUPRANGE., AMTRANGE=&AMTRANGE., ID=, OUTFILE=_temp_PreDrugs3, OUTFILEEXCL=PreDrugCovar&group. ); proc datasets lib=work noprint nowarn; delete _temp_PreDrugs2; quit; *Reshave; %ms_shaveoutside(reffile=ENR_&GROUP., refstart=Enr_Start, refend=Enr_End, KeepPartBf=N, ToShaveFile=_temp_PreDrugs3, ToShaveStart=RxDate, ToShaveEnd=ExpireDt, outfile=_temp_PreDrugs3); proc sort data=_temp_PreDrugs3; by StudyName StockGroup; run; %IF %eval(&type.) = 2 & &Ngrp. = 2 %THEN %DO; data PreDrugs_&group.; merge _temp_PreDrugs3 PreDrugParams; by StudyName StockGroup; drop NumDispensing ExpireDt; run; proc sql noprint undo_policy=none; create table PreDrugs_&group. as select a.*, b.group from PreDrugs_&group. a inner join _ptsgroup b on a.patid = b.patid; quit; proc sql noprint undo_policy=none; create table PreMeds_&group. as select a.*, b.group from PreMeds_&group. a inner join _ptsgroup b on a.patid = b.patid; quit; %END; %ELSE %DO; data PreDrugs_&group.; merge _temp_PreDrugs3 PreDrugParams; by StudyName StockGroup; format group $40.; group = "&ITGROUP."; drop NumDispensing ExpireDt; run; data PreMeds_&group.; set PreMeds_&group.; format group $40.; group = "&ITGROUP."; run; %END; %if %eval(&group.) =1 %then %do; data PreDrugs; set PreDrugs_&group.; run; data PreMeds; set PreMeds_&group.; run; %end; %else %do; data PreDrugs; set PreDrugs PreDrugs_&group.; run; data PreMeds; set PreMeds PreMeds_&group.; run; %end; proc datasets library=work nolist nowarn; delete predrugs_: premeds_: ElixMeds_:; quit; %end; proc datasets library=work nolist nowarn; delete _: PreDrugParams; quit; %END; %mend; %RunCovExtraction; /******************************************/ /* Charlson Comorbidity/Elixhauser Index) */ /******************************************/ %macro RunCciElix; %ISDATA(dataset=Comorbfile); %IF %EVAL(&NOBS.>0) %THEN %DO; %do Group=1 %to &Numgroup.; *Process input file; data _null_; set Comorbfile; if _n_ = &Group. then do; call symputx('ITGROUP',Group); call symputx('comorbfrom',coalesce(comorbfrom,-999999)); call symputx('comorbto',coalesce(comorbto,999999)); call symputx('ccigroup',ccigroup); end; run; *Break down Meds in procs and diags; data _cci_elix_dx _cci_elix_px; set ElixMeds; *where Comorbcode eq 1; if Codecat="DX" then output _cci_elix_dx; if Codecat="PX" then output _cci_elix_px; run; %put &ITGROUP. &comorbfrom. &comorbto. &ccigroup.; *The Charlson/Elixhauser combined comorbidity score will be calculated; data _IndexFile; set &RUNID._&data.; where Group="&ITGROUP."; Keep Patid indexdt; run; %ms_cci_elix(COMORBFROM=&comorbfrom., COMORBTO=&comorbto., INFILE=_IndexFile, PATID=PatId, INDEXDT=IndexDt, PREOUTFILE=_PreOutFile, DIAGFILE=_cci_elix_dx, DX_DT_VAR=Adate, DX_CODETYP=Codetype, DX_CODE=Code, PROCFILE=_cci_elix_px, PX_DT_VAR=Adate, PX_CODETYP=Codetype, PX_CODE=Code, CCI_LOOKUP=infolder.Comorbcodes, OUTFILE=_ITcci_elix, CCIGROUP=&ccigroup., KEEPALLDUM=0); /*&keepalldum.*/ *Post Process; data _ITcci_elix; set _ITcci_elix; format group $40.; Group="&ITGROUP."; length ccielixgrp $10.; format ccielixgrp $10.; ccielixgrp=COMBINED_SCORE; run; *Combine Util for multiple groups; %IF %EVAL(&group.=1) %THEN %DO; data _ALLcci_elix; set _ITcci_elix; run; %END; %ELSE %DO; proc append base=_ALLcci_elix data=_ITcci_elix force; run; %END; *Clean-up; proc datasets library=work nolist nowarn; delete _ITcci_elix _IndexFile _PreOutFile; quit; %END; *group loop; proc sort data=_ALLcci_elix; by Group PatId IndexDt; run; %if "&SURVEILLANCEMODE."="f" or "&SURVEILLANCEMODE."="p" %then %do; data _NewPatients; set DPLocal.&RUNID._&data.; where &PERIODIDSTART. <= IndexLook <= &PERIODIDEND.; keep Group PatId IndexDt; run; proc sort nodupkey; by Group PatId IndexDt; run; data _ALLcci_elix; merge _ALLcci_elix(in=a) _NewPatients(in=b); by Group PatId IndexDt; if a and b; run; %end; *Update Master file with utilization data; data DPLocal.&RUNID._&data.; merge DPLocal.&RUNID._&data. _ALLcci_elix; by Group PatId IndexDt; run; proc datasets library=work nolist nowarn; delete _BaseEnc IndexFile _: Elix_infile_sort Dsout Cci_diag_temp Cci_diag_lookup; quit; %end; %else %do; data DPLocal.&RUNID._&data.; set DPLocal.&RUNID._&data.; COMBINED_SCORE=""; COMBINED_SCORE_NUM=.; ccielixgrp=""; run; %end; %mend; %RunCciElix; /****************/ /* Prepare ADS */ /****************/ %macro ADS; %put &analysis.; %if %str(%UPCASE("&ANALYSIS."))=%str("PS") or %str(%UPCASE("&ANALYSIS."))=%str("ADS") or %str(%UPCASE("&ANALYSIS."))=%str("MS") %then %do; %let t1_table1vars = ; %let t2_table1vars = ; %let t3_table1vars = ; %let t4_table1vars = ; %let t5_table1vars = ; %let analysiscohort = ; %if %eval(&type.=2) %then %do; %let t2_table1vars =NumEvents tte blackoutper EpisodeType LastLookFollowed: EpisodeEndDt; %end; %if %eval(&type.=3) %then %do; %let t3_table1vars = DAYS_FROM: analysiscohort censor:; %let analysiscohort = analysiscohort censor:; %end; %if %eval(&type.=4) %then %do; %let t4_table1vars = delnum EpisodeEndDt; %end; %if %eval(&type.=5) %then %do; %let t5_table1vars = episodenum; %end; *Creating the base file to extract data and then divide into different PeriodId; data _Base; set DPLocal.&RUNID._&data.; rename AgeGroup=Age_Cat FEventDt=EventDt NumVisits_IP=NumIP NumVisits_ED=NumED NumVisits_AV=NumAV NumVisits_OA=NumOA NumVisits_IS=NumIS COMBINED_SCORE_NUM=COMORBIDSCORE; keep PatID IndexDt Year Group Age AgeGroup AgeGroupSort Sex Race hispanic FEventDt COMBINED_SCORE_NUM NumVisits_IP NumVisits_ED NumVisits_AV NumVisits_OA NumVisits_IS NumGeneric NumClass NumRx &t2_table1vars. &t3_table1vars. &t4_table1vars. &t5_table1vars.; run; proc datasets lib=work nolist; modify _Base; attrib _all_ label=''; *Remove labels; quit; proc sort data=_base; by Group Patid IndexDt %if %eval(&type.=5) %then %do; episodenum %end;; run; %if %eval(&type.=5) %then %do; data _base; set _base; by group patid indexdt episodenum; if first.patid; run; %end; /**************************/ /* Creating Covar1-CovarN */ /**************************/ *Combine records; Data _CombineRecords; length Adate ExpireDt 4.; * to avoid w a r n i n g s; set PreDrugs(rename=RxDate=ADate) PreMeds; format Adate ExpireDt date9.; ExpireDt=Adate+max(1,RxSup)-1; where studyname ne ''; Keep Group PatId Adate ExpireDt studyname CovarNum covfrom covto codedays; run; proc datasets library=work nowarn nolist; delete _Drugs CovMeds PreMeds; quit; /*Finding those claims in covariatewindow*/ proc sql noprint; create table _Covar as select distinct pts.Patid, pts.Group, pts.IndexDt, Rec.studyname, Rec.Adate, Rec.covfrom, Rec.covto, Rec.CovarNum, Rec.codedays from _base as pts, _CombineRecords as Rec where pts.Patid = rec.Patid and pts.group = rec.group and %MS_PeriodsOverlap(period1=coalesce(pts.IndexDt+covFrom,-99999) COALESCE(pts.indexdt+CovTo/*-1*/,99999), period2=Rec.ADate Rec.ExpireDt) order by pts.Group, pts.Patid, pts.IndexDt; quit; /*Count number of ADate per covariate and only keep covariate when freq >=codedays*/ proc means data=_Covar noprint nway missing; class group patid indexdt studyname covfrom covto covarnum codedays / missing; output out=_Covar(drop=_: where=(freq>=codedays)) n=freq; run; *Squaring; data _Covar; set studynames _Covar(drop=freq codedays); Rec=1; run; *One record per Patid Group IndexDt; proc transpose data=_Covar out=_Covar(drop=_NAME_) prefix=COVAR; var Rec; by Group Patid IndexDt; id Covarnum; idlabel studyname; run; /******************************/ /*Verify if any combcovariates*/ /******************************/ %ISDATA(dataset=infolder.&COVARIATECODES.); %IF %EVAL(&NOBS.>0) %THEN %DO; data _COMBO; set infolder.&COVARIATECODES.; where codecat in ("CC"); run; %if "&SURVEILLANCEMODE."="f" or "&SURVEILLANCEMODE."="p" %then %do; data _NewPatients; set DPLocal.&RUNID._&data.; where &PERIODIDSTART. <= IndexLook <= &PERIODIDEND.; keep Group PatId IndexDt; run; proc sort nodupkey; by Group PatId IndexDt; run; %end; %ISDATA(dataset=_COMBO); %IF %EVAL(&NOBS.>=1) %THEN %DO; data _COMBO; set _COMBO; format RuleLong $1000.; RuleLong=code; %do j=1 %to &numcovars.; RuleLong=left(TRANWRD(cat(' ',rulelong,' '),(" &j. ")," COVAR&j. ")); RuleLong=left(TRANWRD(cat(' ',rulelong,' '),("(&j. "),"(COVAR&j. ")); RuleLong=left(TRANWRD(cat(' ',rulelong,' '),(" &j.)")," COVAR&j.)")); %end; run; *Create CombCovar variables; %do i=(&numcovars.+1) %to (&numcovars.+&numcomb.); data _null_; set _COMBO (where=(Covarnum=&i.)); call symput ('Rule',RuleLong); call symput ('Label',Studyname); run; %put &Rule.; data _covar; set _covar; COVAR&i.=0; if &rule. then do; COVAR&i.=1; end; label COVAR&i.="&Label."; run; %end;*do loop numcomb; %if "&SURVEILLANCEMODE."="f" or "&SURVEILLANCEMODE."="p" %then %do; proc sort data=_Covar; by Group PatId IndexDt; run; data _Covar; merge _Covar(in=a) _NewPatients(in=b); by Group PatId IndexDt; if a and b; run; %end; *Add dummies to master file (and will also order the vars by covarN); %macro PutBack; data _base; merge _base(in=a) _Covar(keep=Group PatId IndexDt %do j=1 %to &numcovars.;%str(covar&j. )%end; %do k=(&numcovars.+1) %to (&numcovars.+&numcomb.);%str(covar&k. )%end;); by Group PatId IndexDt; if a; run; %mend; %PutBack; %END; %ELSE %DO; %if "&SURVEILLANCEMODE."="f" or "&SURVEILLANCEMODE."="p" %then %do; data _Covar; merge _Covar(in=a) _NewPatients(in=b); by Group PatId IndexDt; if a and b; run; %end; *Add dummies to master file (and will also order the vars by covarN); %macro PutBack; data _base; merge _base(in=a) _Covar(keep=Group PatId IndexDt %do j=1 %to &numcovars.;%str(covar&j. )%end;); by Group PatId IndexDt; if a; run; %mend; %PutBack; %END; %END; *Creating individual PeriodId files; %isdata(dataset=&Monitoringfile.); %if %eval(&nobs.>0) %then %do; proc sort data=&Monitoringfile. out=_Looks; by PeriodId; run; data _Looks; set _looks end=eof; lastEndDt=lag(enddate); format incrstartfollowup date9.; incrstartfollowup=startfollowup; if _N_>1 then incrstartfollowup=lastEndDt+1; drop lastEndDt; run; proc sql noprint undo_policy=none;; create table _base as select distinct base.*, look.PERIODID as time from _Base as base, _Looks as look where incrstartfollowup <= IndexDt <= enddate; quit; %end; %if %eval(&type.=3) %then %do; data _looks; set msoc.&runid._Metadata_for_time_period_&PERIODIDSTART.; incrstartfollowup=ExpPeriodStartDt; enddate = ExpPeriodEndDt; periodid = TimePeriod; run; proc sql noprint undo_policy=none;; create table _base as select distinct base.*, look.PERIODID as time from _Base as base, _Looks as look where incrstartfollowup <= IndexDt <= enddate and base.group=look.group; quit; %end; %let delnum = ; /*Need to include DelNum for Type 4 control grp because ctrl group may not be unique on group/patid/indexdt*/ %if "&data" = "ctrl" %then %do; %let delnum = delnum; %end; %macro forAdsloop; %do i=&PERIODIDSTART. %to &PERIODIDEND.; proc sort data =_base; by Group PatId IndexDt &delnum.; run; data DPLocal.&RUNID._ads_&data._&i.; set _Base; if _N_=1 then set _Looks(keep=PERIODID enddate where=(PERIODID=&i.)); if missing(NumGeneric) then NumGeneric=0; if missing(NumClass) then NumClass=0; if missing(NumRx) then NumRx=0; *if Type = 2 then: 1. Adjust tte for episodes going beyond the PERIODID 2. Add followuptime_ and event_ vars ; %if %eval(&type.=2) %then %do; if IndexDt <= enddate and EpisodeEndDt > min(LastLookFollowedDt,enddate) then do; if EventDt > min(LastLookFollowedDt,enddate) then EventDt = .; *tte = min(tte,enddate - IndexDt +1 - BlackOutPer); tte = min(LastLookFollowedDt,EventDt,enddate) - IndexDt +1 - BlackOutPer; end; *Variables needded for the ADS; Followuptime_ITT=.; Event_ITT=0; if EpisodeType="ITT" then do; Followuptime_ITT=tte; Event_ITT=EventDt>0; end; Followuptime_astreated=.; Event_astreated=0; if EpisodeType="EPI" then do; Followuptime_astreated=tte; Event_astreated=EventDt>0; end; drop BlackOutPer EpisodeEndDt; %end; *fill covars with 0s; %do j=1 %to &numcovars.;%str(covar&j.=covar&j.>0;)%end; %do k=(&numcovars.+1) %to (&numcovars.+&numcomb.);%str(covar&k.=covar&k.>0; )%end; *Output incremental datasets; if IndexDt <= enddate then output DPLocal.&RUNID._ads_&data._&i.; *Cleanup to keep only required in specs; drop enddate PERIODID; run; *Carry forward information from previous look in ads_mstr; %IF %EVAL(&i.>1) & %eval(&type.=2) %THEN %DO; %let previous = %eval(&i-1); data DPLocal.&RUNID._ads_&data._&i.; merge DPLocal.&RUNID._ads_&data._&i. &DPLOCALPOINTER..&RUNID._ads_&data._&previous. (where=(Time < &PERIODIDSTART. and LastLookFollowed > 0) keep=Time LastLookFollowed Group PatId IndexDt Followuptime_: Event_: %do j=1 %to &numcovars.;%str(covar&j. )%end; %do k=(&numcovars.+1) %to (&numcovars.+&numcomb.);%str(covar&k. )%end;); by Group PatId IndexDt; run; %END; %end; %mend forAdsloop; %forAdsloop; %macro baselineloop(where=, t3out=); %do i=&PERIODIDSTART. %to &PERIODIDEND.; proc sql noprint; select count(*) into: nusers from DPLocal.&RUNID._ads_&data._&i. where &where.; quit; %if %eval(&nusers.>0) %then %do; ************************* *Create baseline profile* *************************; %if "&profile." = "y" %then %do; data _tempcovar; set DPLocal.&RUNID._ads_&data._&i.; patient = 1; where &where.; run; proc means data=_tempcovar noprint nway; var patient; class group patid covar1-covar%eval(&numcovars.+&numcomb.); id patient; output out=_covarprofile(drop=_:) max(patient) = npts sum(patient) = n_episodes; run; proc means data=_covarprofile nway noprint missing; var Npts n_episodes; class group covar1-covar%eval(&numcovars.+&numcomb.); output out=msoc.&runid._profile&outcohort.&t3out._&i.(drop=_:) sum=; run; %end; *********************** *Create Baseline table* ***********************; *Strip age_cat of special characters; data _RawData; set DPLocal.&RUNID._ads_&data._&i. (drop = agegroupsort); by group patid indexdt &delnum.; Age_cat=TRANSLATE(Age_cat,"_","-"); Age_cat=upcase(compress(Age_cat,' <>+-')); patient=1; where &where.; run; *Create age group dummies - can be multiple index per patient; proc transpose data=_RawData out=_AgeGroups(keep=group patid indexdt Age: &delnum.) prefix=AGE; var patient; by group patid indexdt &delnum.; id Age_cat; run; *Create sex dummies - can be multiple index per patient; proc transpose data=_RawData out=_Genders(keep=group patid indexdt Sex_: &delnum.) prefix=Sex_; var patient; by group patid indexdt &delnum.; id Sex; run; *Create race dummies - can be multiple index per patient; proc transpose data=_RawData out=_races(keep=group patid indexdt Race_: &delnum.) prefix=Race_; var patient; by group patid indexdt &delnum.; id race; run; *Create hispanic dummies - can be multiple index per patient; proc transpose data=_RawData out=_hispanic(keep=group patid indexdt Hispanic_: &delnum.) prefix=Hispanic_; var patient; by group patid indexdt &delnum.; id hispanic; run; *Create year dummies - can be multiple index per patient; proc transpose data=_RawData out=_years(keep=group patid indexdt year_: &delnum.) prefix=Year_; var patient; by group patid indexdt &delnum.; id year; run; *Merge back agegroup and sex dummies; data _RawData; merge _RawData(drop=patient) _AgeGroups _Genders _years _races _hispanic; by group patid indexdt &delnum.; patient=0; *create a new patient indicator to count distinct patients; if first.patid then patient=1; if not first.patid then do; array Sexes Sex_:; do over Sexes; Sexes=.; end; array races race_:; do over races; races=.; end; array hispanics hispanic_:; do over hispanics; hispanics=.; end; end; run; *Process discrete vars; proc means data=_RawData(drop=age age_cat) nway noprint; var patient Age: Sex_: year_: race_: hispanic_: %if %eval(&numcovars. ge 1) %then %do; covar: %end; %if %eval(&numcomb. ge 1) %then %do; covar: %end;; class group; output out=_Discrete(drop=_:) sum=; run; *Process continuous vars; proc means data=_RawData nway noprint; var /*Followuptime_ITT Followuptime_astreated */ Age COMORBIDSCORE NumAV NumOA NumIP NumIS NumED NumGeneric NumClass NumRx; class group; output out=_Continuous(rename=_freq_=N_episodes drop=_type_) mean= mean_Age mean_COMORBIDSCORE mean_NumAV mean_NumOA mean_NumIP mean_NumIS mean_NumED mean_NumGeneric mean_NumClass mean_NumRx std= std_Age std_COMORBIDSCORE std_NumAV std_NumOA std_NumIP std_NumIS std_NumED std_NumGeneric std_NumClass std_NumRx; run; *merge the two; data msoc.&RUNID._baseline&outcohort.&t3out._&i.; merge _discrete _continuous; by group; /*Set to missing if &race_out =N/&hispanic_ou=N for each group*/ if upcase(group) not in (&race_groups2.) then do; array races race_:; do over races; races=.; end; end; if upcase(group) not in (&hispanic_groups2.) then do; array hispanic hispanic_:; do over hispanic; hispanic=.; end; end; run; *add missing groups if any; proc sql noprint; create table _MissingGroups as select distinct (Group), 0 as patient, 0 as N_Episodes from COHORTFILE where group not in (select distinct (Group) from msoc.&RUNID._baseline&outcohort.&t3out._&i. ) ; quit; data msoc.&RUNID._baseline&outcohort.&t3out._&i.; set msoc.&RUNID._baseline&outcohort.&t3out._&i. _MissingGroups; run; %end; %else %do; %put WARNING: No users. Baseline table &RUNID._baseline&outcohort.&t3out._&i. will not be produced.; %end; %end; %mend baselineloop; %baselineloop(where=1, t3out=); %if %eval(&type.=3) %then %do; %baselineloop(where=analysiscohort=1 and censorenrol=0 and censordeath=0, t3out=_an); %baselineloop(where=AnalysisCohort=1, t3out=_an_censor); %end; /*****************************/ /* Claims_icddx09.sas7bdat */ /* Claims_icddx10.sas7bdat */ /* Claims_dxOT.sas7bdat */ /* Claims_icdpx09.sas7bdat */ /* Claims_icdpx10.sas7bdat */ /* Claims_pxOT.sas7bdat */ /* Claims_cpt.sas7bdat */ /* Claims_hcpcs.sas7bdat */ /* Claims_drugclass.sas7bdat */ /* Claims_rx.sas7bdat */ /* Claims_lab.sas7bdat */ /*****************************/ %macro ClaimsFiles; %let HDPS=N; %let MFU=N; %ISDATA(dataset=HDPSSettings); *Note: HDPS settings contains groups where HDPS=Y; %IF %EVAL(&NOBS.>0) %THEN %DO; data _ToSelect; set HDPSSettings; where upcase(HDPS)="Y"; if upcase(HDPS)="Y" then call symputx("HDPS",upcase(HDPS)); keep Group; run; %put &HDPS.; %END; *Note: MFU is performed on all groups, so _ToSelect contains all groups, even if HDPS is not performed on all groups; %isdata(dataset=infolder.&mfufile.); %if %eval(&nobs.>0) %then %do; data _ToSelect; set cohortfile; keep group; run; %let MFU=Y; %put &MFU; %end; %if %str(&HDPS.)=%str(Y) | %str(&MFU.)=%str(Y) %then %do; *keep only patients in groups where HDPS is required (All groups for MFU); data _lookup(keep=Patid Group Indexdt &analysiscohort.); if 0 then set _ToSelect(Keep=Group); declare hash ht (hashexp:16, dataset:"_ToSelect"); ht.definekey('Group'); ht.definedone(); do until(eof1); set &RUNID._&data. end=eof1; if ht.find()=0 then output; end; stop; run; *keep only new patients; %if "&SURVEILLANCEMODE."="f" or "&SURVEILLANCEMODE."="p" %then %do; proc sort nodupkey data=_NewPatients(keep=Group PatId); by Group PatId; run; data _lookup; merge _lookup(in=a) _NewPatients(in=b); by Group PatId; if a and b; run; %end; /*Determine Min and Max Windows. Cannot use coalesce() because HDPS or MFU may use entire history whereas the other is a defined window */ %let HDPS_MFU_FROM=.; %let HDPS_MFU_TO=.; /*Enrollment considered absolute value of window, need to obtain true max window*/ %if %str(&MFU.)=%str(Y) %then %do; proc means data=infolder.&mfufile. nway noprint; var MFUFROM MFUTO; output out=MFU_WIN min(MFUFROM)= max(MFUTO)=; run; data _NULL_; set MFU_WIN; call symputx("MinMFUWinFrom",put(MFUFROM,best.)); call symputx("MaxMFUWinTo",put(MFUTO,best.)); run; %put &MinMFUWinFrom. &MaxMFUWinTo.; %end; %put &MinHDPSWinfrom. &MaxHDPSWinTo.; %if %str(&HDPS.)=%str(Y) & %str(&MFU.)=%str(N) %then %do; %let HDPS_MFU_FROM=&MinHDPSWinfrom.; %let HDPS_MFU_TO=&MaxHDPSWinTo.; %end; %else %if %str(&HDPS.)=%str(N) & %str(&MFU.)=%str(Y) %then %do; %let HDPS_MFU_FROM=&MinMFUWinFrom.; %let HDPS_MFU_TO=&MaxMFUWinTo.; %end; %else %do; /*both HDPS and MFU*/ %if &MinHDPSWinfrom. ne . & &MinMFUWinFrom. ne . %then %let HDPS_MFU_FROM = %sysfunc(min(&MinHDPSWinfrom.,&MinMFUWinFrom.)); %else %let HDPS_MFU_FROM = .; %if &MaxHDPSWinTo. ne . & &MaxMFUWinTo. ne . %then %let HDPS_MFU_TO = %sysfunc(max(&MaxHDPSWinTo.,&MaxMFUWinTo.)); %else %let HDPS_MFU_TO = .; %end; %let t3vars = ; %if %eval(&type.=3) %then %do; %let t3vars = , pts.analysiscohort, pts.censordeath, pts.censorenrol; %end; *Claims_icddx; proc sql noprint; create table &RUNID._Claims_icddx as select /*distinct*/ claims.Patid, compress(claims.DX) as Code, claims.DX_Codetype, claims.Adate, claims.enctype, claims.pdx, pts.group, pts.indexdt &t3vars. from _lookup as pts, &DataLib.&Diatable. as claims where pts.Patid = claims.Patid and %MS_PeriodsOverlap(period1=pts.IndexDt+coalesce(&HDPS_MFU_FROM.,-99999) pts.IndexDt+coalesce(&HDPS_MFU_TO.,99999), period2=claims.ADate) order by claims.Patid, pts.group; quit; data DPLocal.&RUNID._Claims_icddx09 DPLocal.&RUNID._Claims_icddx10 DPLocal.&RUNID._Claims_dxOT; set &RUNID._Claims_icddx; if DX_Codetype in("09") then output DPLocal.&RUNID._Claims_icddx09; if DX_Codetype in("10","11") then output DPLocal.&RUNID._Claims_icddx10; if DX_Codetype in("OT") then output DPLocal.&RUNID._Claims_dxOT; /*For MFU*/ run; *Claims_icdpx; proc sql noprint; create table &RUNID._Claims_icdpx as select /*distinct*/ claims.Patid, compress(claims.PX) as Code, pts.group, claims.PX_Codetype, claims.Adate, claims.Enctype, pts.indexdt &t3vars. from _lookup as pts, &DataLib.&Proctable. as claims where pts.Patid = claims.Patid and %MS_PeriodsOverlap(period1=pts.IndexDt+coalesce(&HDPS_MFU_FROM.,-99999) pts.IndexDt+coalesce(&HDPS_MFU_TO.,99999), period2=claims.ADate) order by claims.Patid, pts.group; quit; data DPLocal.&RUNID._Claims_icdpx09 DPLocal.&RUNID._Claims_icdpx10 DPLocal.&RUNID._Claims_cpt DPLocal.&RUNID._Claims_hcpcs DPLocal.&RUNID._Claims_pxOT; set &RUNID._Claims_icdpx; if PX_Codetype in("09") then output DPLocal.&RUNID._Claims_icdpx09; if PX_Codetype in("10","11") then output DPLocal.&RUNID._Claims_icdpx10; if PX_Codetype in("C2","C3","C4") then output DPLocal.&RUNID._Claims_cpt; if PX_Codetype in("HC","H3") then output DPLocal.&RUNID._Claims_hcpcs; if PX_Codetype in("RE","ND","LO","OT") then output DPLocal.&RUNID._Claims_pxOT; /*For MFU*/ run; *Claims_drugclass; proc sql noprint; create table _Claims_drugclass as select /*distinct*/ claims.Patid, claims.NDC as Code, claims.Rxdate as Adate, pts.group, pts.indexdt, claims.rxsup, claims.rxamt &t3vars. from _lookup as pts, &DataLib.&distable. as claims where pts.Patid = claims.Patid and %MS_PeriodsOverlap(period1=pts.IndexDt+coalesce(&HDPS_MFU_FROM.,-99999) pts.IndexDt+coalesce(&HDPS_MFU_TO.,99999), period2=claims.RxDate) /*claims.ADate+RxSup-1*/; quit; /*For MFU*/ data DPLocal.&RUNID._Claims_rx; set _Claims_drugclass; where rxsup >0 and rxamt > 0; run; *add Drugclass information for HDPS; proc sql noprint; create table DPLocal.&RUNID._Claims_drugclass as select /*distinct*/ claims.Patid, claims.indexdt, claims.group, claims.adate, ndc.classname as Code from infolder.&DRUGCLASSFILE. as ndc inner join _Claims_drugclass as claims on ndc.ndc = claims.Code order by claims.Patid, claims.group; quit; /*Lab table - for MFU only*/ %ISDATA(dataset=indata.&labtable.); %IF %EVAL(&NOBS.>0) %THEN %DO; proc sql noprint; create table DPLocal.&RUNID._Claims_lab as select claims.patid, pts.group, pts.indexdt, coalesce(claims.lab_dt,claims.result_dt,claims.order_dt,0) as adate, upcase(claims.result_type) as result_type, claims.loinc, claims.px, claims.px_codetype, claims.ms_test_name, claims.specimen_source, claims.ms_test_sub_category, claims.ms_result_unit, claims.fast_ind, claims.pt_loc &t3vars. from _lookup as pts, &DataLib.&labtable. as claims where pts.Patid = claims.Patid and %MS_PeriodsOverlap(period1=pts.IndexDt+coalesce(&HDPS_MFU_FROM.,-99999) pts.IndexDt+coalesce(&HDPS_MFU_TO.,99999), period2=coalesce(claims.lab_dt,claims.result_dt,claims.order_dt,0)) order by claims.Patid, pts.group; quit; %end; *Lab MFU codes; %if ("&SURVEILLANCEMODE."="f" or "&SURVEILLANCEMODE."="p") & %eval(&PERIODIDSTART.>=2) %then %do; data DPLocal.&RUNID._Claims_icdpx09; set DPLocal.&RUNID._Claims_icdpx09 &DPLOCALPOINTER..&RUNID._Claims_icdpx09; by Patid group; run; data DPLocal.&RUNID._Claims_icdpx10; set DPLocal.&RUNID._Claims_icdpx10 &DPLOCALPOINTER..&RUNID._Claims_icdpx10; by Patid group; run; data DPLocal.&RUNID._Claims_cpt; set DPLocal.&RUNID._Claims_cpt &DPLOCALPOINTER..&RUNID._Claims_cpt; by Patid group; run; data DPLocal.&RUNID._Claims_hcpcs; set DPLocal.&RUNID._Claims_hcpcs &DPLOCALPOINTER..&RUNID._Claims_hcpcs; by Patid group; run; data DPLocal.&RUNID._Claims_pxOT; set DPLocal.&RUNID._Claims_pxOT &DPLOCALPOINTER..&RUNID._Claims_pxOT; by Patid group; run; data DPLocal.&RUNID._Claims_icddx09; set DPLocal.&RUNID._Claims_icddx09 &DPLOCALPOINTER..&RUNID._Claims_icddx09; by Patid group; run; data DPLocal.&RUNID._Claims_icddx10; set DPLocal.&RUNID._Claims_icddx10 &DPLOCALPOINTER..&RUNID._Claims_icddx10; by Patid group; run; data DPLocal.&RUNID._Claims_dxOT; set DPLocal.&RUNID._Claims_dxOT &DPLOCALPOINTER..&RUNID._Claims_dxOT; by Patid group; run; data DPLocal.&RUNID._Claims_drugclass; set DPLocal.&RUNID._Claims_drugclass &DPLOCALPOINTER..&RUNID._Claims_drugclass; by Patid group; run; data DPLocal.&RUNID._Claims_rx; set DPLocal.&RUNID._Claims_rx &DPLOCALPOINTER..&RUNID._Claims_rx; by Patid group; run; %ISDATA(dataset=indata.&labtable.); %IF %EVAL(&NOBS.>0) %THEN %DO; data DPLocal.&RUNID._Claims_lab; set DPLocal.&RUNID._Claims_lab &DPLOCALPOINTER..&RUNID._Claims_lab; by Patid group; run; %end; %end; %END; *HDPS/MFU extraction; %mend; %if "&data." = "mstr" %then %do; %ClaimsFiles; %end; /**Conduct MFU analysis*/ %macro MFU(where=, t3out=); /*Determine number of analyses*/ proc sql noprint; select max(ANALYSISNUM) into: mfucnt from infolder.&mfufile; quit; /*loop through analyses*/ %do a = 1 %to &mfucnt.; /*number of CodeCat/CodeType within analysis*/ data _currentMFU; set infolder.&mfufile.(where=(ANALYSISNUM=&a.)); if _n_ = 1 then do; /*These parameters are set for the analysis and not unique to CODECAT/CODETYPE*/ call symputx('TOPXX',TOPXX); call symputx('MFUFROM',MFUFROM); call symputx('MFUTO',MFUTO); call symputx('COUNTMETHOD',upcase(COUNTMETHOD)); end; run; %put &TOPXX. &MFUFROM. &MFUTO.; /*CODECAT list*/ proc sql noprint; select distinct codecat into: codecatlist separated by ' ' from _currentMFU; quit; %put &codecatlist.; *DX/PX codes; %if %index(&codecatlist., DX)>0 | %index(&codecatlist., PX)>0 %then %do; data _mfudxpx; set _currentMFU; where codecat in('DX', 'PX'); run; *Break out CaresettingPrincipal into Caresetting and Principal; %ms_caresettingprincipal(InFile=_mfudxpx, Var=CareSettingPrincipal, OutFile=_mfudxpx); *Select all codetypes; %let dx_codetypelist = 'XX'; /*Dummy code*/ %let px_codetypelist = 'XX'; proc sql noprint; select distinct "'"||(compress(codetype))||"'" into: dx_codetypelist separated by "," from _mfudxpx where codecat = 'DX'; select distinct "'"||(compress(codetype))||"'" into: px_codetypelist separated by "," from _mfudxpx where codecat = 'PX'; quit; %put &dx_codetypelist &px_codetypelist.; *Stack Claims datasets; data claims_dxpx(where=(&where.)); set DPLocal.&RUNID._Claims_icddx09(rename=dx_codetype = codetype where=(codetype in (&dx_codetypelist.)) in=a) DPLocal.&RUNID._Claims_icddx10(rename=dx_codetype = codetype where=(codetype in (&dx_codetypelist.)) in=b) DPLocal.&RUNID._Claims_dxOT(rename=dx_codetype = codetype where=(codetype in (&dx_codetypelist.)) in=c) DPLocal.&RUNID._Claims_icdpx09(rename=px_codetype = codetype where=(codetype in (&px_codetypelist.)) in=d) DPLocal.&RUNID._Claims_icdpx10(rename=px_codetype = codetype where=(codetype in (&px_codetypelist.)) in=e) DPLocal.&RUNID._Claims_pxOT(rename=px_codetype = codetype where=(codetype in (&px_codetypelist.)) in=f) DPLocal.&RUNID._Claims_cpt(rename=px_codetype = codetype where=(codetype in (&px_codetypelist.)) in=g) DPLocal.&RUNID._Claims_hcpcs(rename=px_codetype = codetype where=(codetype in (&px_codetypelist.)) in=h); if a or b or c then codecat = 'DX'; if c or d or e or f or g or h then codecat = 'PX'; run; *Envelope will not be run for MFU analysis; *Extract records; proc sql noprint; create table _dxpxcodes as select claim.patid, compress(claim.code,' .') as code format=$18. length=18, claim.codetype format=$3. length=3, claim.codecat, claim.group from claims_dxpx as claim, _mfudxpx as mfu where claim.codetype = mfu.codetype and ((mfu.EncType = claim.EncType and mfu.Pdx = claim.Pdx) or /*No Wilcards*/ (mfu.EncType = "**" and mfu.Pdx = claim.Pdx) or /*Any EncType*/ (mfu.EncType = claim.EncType and mfu.Pdx = "*") or /*Any Pdx*/ (mfu.EncType = "**" and mfu.Pdx = "*")) and %MS_PeriodsOverlap(period1=IndexDt+coalesce(&MFUFROM.,-99999) IndexDt+coalesce(&MFUTO.,99999), period2=ADate); quit; proc append data=_dxpxcodes base=_allmfucodes force; run; %end; *DX/PX codes; *RX codes; %if %index(&codecatlist., RX)>0 %then %do; data _mfurx; set _currentMFU(where=(codecat='RX')); run; *Determine whether to extract 09, 11, or both; proc sql noprint; select distinct codetype into: rx_codetypelist separated by ' ' from _mfurx; quit; %put &rx_codetypelist.; *Extract 9-digit NDC codes; %if %index(&rx_codetypelist, 09) > 0 %then %do; proc sql noprint; create table _rxcodes09 as select claim.patid, compress(substr(claim.code, 1,9)) as code format=$18. length=18, '09' as codetype format=$3. length=3, 'RX' as codecat, claim.group from DPLocal.&RUNID._Claims_rx(where=(&where.)) as claim, _mfurx as mfu where %MS_PeriodsOverlap(period1=IndexDt+coalesce(&MFUFROM.,-99999) IndexDt+coalesce(&MFUTO.,99999), period2=ADate); quit; proc append data=_rxcodes09 base=_allmfucodes force; run; %end; *Extract 11-digit NDC codes; %if %index(&rx_codetypelist, 11) > 0 %then %do; proc sql noprint; create table _rxcodes11 as select claim.patid, compress(claim.code) as code format=$18. length=18, '11' as codetype format=$3. length=3, 'RX' as codecat, claim.group from DPLocal.&RUNID._Claims_rx(where=(&where.)) as claim, _mfurx as mfu where %MS_PeriodsOverlap(period1=IndexDt+coalesce(&MFUFROM.,-99999) IndexDt+coalesce(&MFUTO.,99999), period2=ADate); quit; proc append data=_rxcodes11 base=_allmfucodes force; run; %end; %end; *RX codes; *Lab codes; %if %index(&codecatlist., LB)>0 %then %do; data _mfulb_01_02 _mfulb; set _currentMFU(where=(codecat='LB')); if substr(codetype,1,2) in ('01','02') then output _mfulb_01_02; else output _mfulb; run; %isdata(dataset=_mfulb_01_02); %if %eval(&nobs.>0) %then %do; /*Select codetypes*/ proc sql noprint; select distinct "'"||(compress(codetype))||"'" into: lb_codetypelist separated by ' ' from _mfulb_01_02; quit; %put &lb_codetypelist; %let result_type_n = 'XXX'; %let result_type_c = 'XXX'; %macro assign_lab_resulttype(cat=); *Determine whether to restrict to N, C, or both; %if %index(&lb_codetypelist., &cat.N) > 0 %then %do; %let result_type_n = 'N'; %end; %if %index(&lb_codetypelist., &cat.C) > 0 %then %do; %let result_type_c = 'C'; %end; %mend; /*Count SOC-defined lab codes (codetype = 01N, 01C)*/ %if %index(&lb_codetypelist., 01) > 0 %then %do; %assign_lab_resulttype(cat=01); *Code in infolder.&LABSCODEMAP. should be unique; proc sort nodupkey data=infolder.&LABSCODEMAP. out=_Map; by Code; run; *Extract Lab Records; proc sql noprint; create table _mfulab01 as select claim.patid, claim.group, compress(_map.Code,' .') as code format=$18. length=18, cat('01',claim.result_type) as codetype format=$3. length=3, 'LB' as codecat from _Map as look, DPLocal.&RUNID._Claims_lab(where=(&where.)) as claim where upcase(strip(look.ms_test_name)) = upcase(strip(claim.ms_test_name)) and upcase(strip(look.ms_test_sub_category)) = upcase(strip(claim.ms_test_sub_category)) and upcase(strip(look.specimen_source)) = upcase(strip(claim.specimen_source)) and upcase(strip(look.ms_result_unit)) = upcase(strip(claim.ms_result_unit)) and upcase(strip(look.result_type)) = upcase(strip(claim.result_type)) and upcase(strip(look.fast_ind)) = upcase(strip(claim.fast_ind))and upcase(strip(look.pt_loc)) = upcase(strip(claim.pt_loc)) and upcase(strip(claim.result_type)) in (&result_type_n, &result_type_c) and %MS_PeriodsOverlap(period1=claim.IndexDt+coalesce(&MFUFROM.,-99999) claim.IndexDt+coalesce(&MFUTO.,99999), period2=claim.ADate); quit; proc append data=_mfulab01 base=_allmfucodes force; run; %end; /*Count LOINC lab codes (codetype = 02N, 02 C)*/ %if %index(&lb_codetypelist., 02) > 0 %then %do; %assign_lab_resulttype(cat=02); *Extract Lab Records; proc sql noprint; create table _mfulab02 as select claim.patid, claim.group, compress(LOINC) as code format=$18. length=18, cat('02',claim.result_type) as codetype format=$3. length=3, 'LB' as codecat from DPLocal.&RUNID._Claims_lab(where=(&where.)) as claim where upcase(strip(claim.result_type)) in (&result_type_n, &result_type_c) and LOINC is not missing and %MS_PeriodsOverlap(period1=claim.IndexDt+coalesce(&MFUFROM.,-99999) claim.IndexDt+coalesce(&MFUTO.,99999), period2=claim.ADate); quit; proc append data=_mfulab02 base=_allmfucodes force; run; %end; %end; %isdata(dataset=_mfulb); %if %eval(&nobs.>0) %then %do; /*Count PX lab codes)*/ data _lkup03; set _mfulb(rename=codetype=codetype1); codetype = substr(codetype1,1,2); result_nc = substr(codetype1,3,1); run; *Extract Lab Records; proc sql noprint; create table _mfulab03 as select claim.patid, claim.group, compress(px) as code format=$18. length=18, lkup.codetype format=$3. length=3, 'LB' as codecat from DPLocal.&RUNID._Claims_lab(where=(&where.)) as claim, _lkup03 as lkup where upcase(strip(lkup.codetype)) = upcase(strip(claim.px_codetype)) and PX is not missing and upcase(strip(lkup.result_nc)) = upcase(strip(claim.result_type)) and %MS_PeriodsOverlap(period1=claim.IndexDt+coalesce(&MFUFROM.,-99999) claim.IndexDt+coalesce(&MFUTO.,99999), period2=claim.ADate); quit; proc append data=_mfulab03 base=_allmfucodes force; run; %end; %end; *Calculate Top XX and output aggregate dataset; %let countmethodvar = codecount; %if "&countmethod" = "P" %then %do; %let countmethodvar = patcount; %end; proc sql noprint; create table _aggregate_counts as select group, code, codecat, codetype, count(*) as codecount, count(distinct patid) as patcount from _allmfucodes group by group, code, codecat, codetype order by group, &countmethodvar. desc; quit; data _codecounts; set _aggregate_counts; by group descending &countmethodvar.; analysisnum =&a.; if first.group then rank = 0; rank = rank +1; retain rank; if rank <= &topxx. then output; run; %if %eval(&a.=1) %then %do; data msoc.&runid._mfu&t3out.; set _codecounts; run; %end; %else %do; proc append data=_codecounts base=msoc.&runid._mfu&t3out. force; run; %end; proc datasets lib=work nowarn noprint; delete _aggregate_counts _codecounts _allmfucodes _rxxcodes11 _rxxcodes09 _dxpxcodes _mfudxpx _mfurx _mfulab _currentMFU; quit; %end; *Analysisnum loop; %mend; %isdata(dataset=infolder.&mfufile.); %if %eval(&nobs.>0) %then %do; %if "&data." = "mstr" %then %do; %MFU(where=1, t3out=) %if %eval(&type.=3) %then %do; %MFU(where=analysiscohort=1 and censorenrol=0 and censordeath=0, t3out=_an); %MFU(where=analysiscohort=1, t3out=_an_censor); %end; %end; %end; %END; %mend; %ADS; %end; %else %do; %put WARNING: No users were identified in this request. If a baseline table was specified it will not be produced.; %end; %ms_stoptimer(START=&CIDACOV.); %put NOTE: ******** END OF MACRO: ms_cidacov v2.9 ********; %mend ms_cidacov;