*************************************************************************************************** * PROGRAM OVERVIEW **************************************************************************************************** * * PROGRAM: ms_cidanum.sas * Created (mm/dd/yyyy): 12/19/2014 * *-------------------------------------------------------------------------------------------------- * PURPOSE: * This macro will compute the numerators for each cohort and call many other macros: * - creating the denominators * - creating output tables * - performing multiple cohort analyses (PSA/Covariate stratification, Multiple Events, Concomitant Use, Overlap, Tree Extraction) * * Program inputs: * -infolder.&MONITORINGFILE. * -infolder.&USERSTRATA. * -infolder.&COMBOFILE. * -infolder.&COHORTFILE. * -infolder.&COHORTCODES. * -infolder.&INCLUSIONCODES. * -infolder.&STOCKPILINGFILE. * -infolder.&ZIPFILE. * -infolder.&TYPE1FILE. * -infolder.&TYPE2FILE. * -infolder.&TYPE3FILE. * -infolder.&TYPE4FILE. * -infolder.&MODPREGDUR. * -infolder.&TYPE5FILE. * -infolder.&TYPE6FILE. * -infolder.&METADATAFILE. * -infolder.&COVARIATECODES. * -infolder.&UTILFILE. * -infolder.&COMORBFILE. * -infolder.&DRUGCLASSFILE. * -infolder.&MFUFILE. * -infolder.&MULTEVENTFILE. * -infolder.&MULTEVENTFILE_ADHERE. * -infolder.&CONCFILE. * -infolder.&OVERLAPFILE. * -infolder.&OVERLAPFILE_ADHERE. * -infolder.&ITSFILE. * -infolder.&TREATMENTPATHWAYS. * -infolder.&MICOHORTFILE. * -infolder.&TREEFILE. * -infolder.&TREELOOKUP. * -infolder.&ICD10ICD9MAP. * -infolder.&PSESTIMATIONFILE. * -infolder.&PSMATCHFILE. * -infolder.&STRATIFICATIONFILE. * -infolder.&COVSTRATFILE. * -infolder.&IPTWFILE. * -infolder.&PSCSSUBGROUPFILE. * * * Program outputs: * -Numerous dplocal and msoc datasets * * PARAMETERS: * * -RUNID = Run identifier to denote each execution of the program * -PROJID = SOC-defined value * -WPTYPE = SOC-defined value * -WPID = SOC-defined value * -DPID = SOC-defined value * -VERID = SOC-defined value * -PERIODIDSTART = Starting PERIODID from the MONITORINGFILE * -PERIODIDEND = Ending PERIODID from the MONITORINGFILE * -ANALYSIS = Indicates whether to perform tree extraction * -MONITORNGFILE = Name of the SAS dataset that defines the relevant query periods for execution * -USERSTRATA = Name of the SAS dataset that defines the stratifications to return in the MSOC folder * -COMBOFILE = Name of the SAS dataset that will be used to create combination items. * When this parameter is specified, "CODES" input files is required, and "STOCK" is optional * -COHORTFILE = Name of the SAS dataset that defines how the cohort should be created (gaps, coverage,...) * -COHORTCODES = Name of the SAS dataset that includes the codes defining the cohort * -INCLUSIONCODES = Name of the SAS dataset that includes the codes defining inclusions/exclusions * -STOCKPILINGFILE = Name of the SAS dataset that defines how the stockpiling algorithm should be performed * -RUN_ENVELOPE = Indicates if the envelope macro should include Adate or be turned off entirely * -FREEZEDATA = Indicates if SDD patient data should be copied to DPLocal * -ZIPFILE = Name of the SAS dataset that contains list of valid zip to geographical area mappings * -LABSCODEMAP = Name of the SAS dataset that contains laboratory matching information * -DISTINDEX = Indicates if distribution of index defining codes should be output to MSOC folder * -TYPE1FILE = Name of the SAS dataset that defines type 1 cohort parameters (washouts, cohortdef, ...) * -TYPE2FILE = Name of the SAS dataset that defines type 2 cohort parameters (washouts, cohortdef, ...) * -TYPE3FILE = Name of the SAS dataset that defines type 3 cohort parameters (washouts, cohortdef, ...) * -TYPE4FILE = Name of the SAS dataset that defines type 4 cohort parameters (washouts, cohortdef, ...) * -MODPREGDUR = Name of the SAS dataset that contains pregnacy duration delivery codes for type 4 analysis * -TYPE5FILE = Name of the SAS dataset that defines type 5 cohort parameters (washouts, cohortdef, ...) * -TYPE6FILE = Name of the SAS dataset that defines type 6 cohort parameters (washouts, cohortdef, ...) * -METADATAFILE = Name of the SAS dataset that defines the metadata generated for each time period request for sequential analysis * -SURVEILLANCEMODE = Indicates if the module should be executed in suveilance mode and which type * -COVARIATECODES = Name of the SAS dataset that includes the codes associated with covariate exctraction * -UTILFILE = Name of the SAS dataset that defines how medical and drug utilization metrics should be calculated * -COMORBFILE = Name of the SAS dataset that defines how CCI/Elixhauser Combined Comorbdity Score should be calculated * -DRUGCLASSFILE = Name of the SAS dataset that lists NDCs by generic and class names and allows * the program to count the number of distinct generic names and class names * -PROFILE = Indicates if a covariate profile file should be produced * -MFUFILE = Name of the SAS dataset that defines how MFU analysis should be performed * -MULTEVENTFILE = Name of the SAS dataset that defines how a multiple events analysis should be performed * -MULTEVENTFILE_ADHERE = Name of the SAS dataset that defines how adherence is calculated for a multiple events analysis * -CONCFILE = Name of the SAS dataset that defines how concomitant episodes should be created and evaluated * -OVERLAPFILE = Name of the SAS dataset that defines how secondary episode overlap of primary episodes should be evaluated * -OVERLAPFILE_ADHERE = Name of the SAS dataset that defines how adherence is calculated for a overlapping episodes analysis * -ITSFILE = Name of the SAS dataset that defines parameters for an Interupted Time Series (ITS) analysis * -TREATMENTPATHWAYS = Name of the SAS dataset that defines how the switching module should be performed * -MICOHORTFILE = Name of the SAS dataset that defines how Type 4 PSA/Mother-Infant cohorts will be created * -TREEFILE = Name of the SAS dataset that defines parameters for tree extraction * -TREELOOKUP = Name of the SAS dataset that defines the parent-child nodes for tree extraction * -ICD10ICD9MAP = Name of the SAS dataset that maps ICD 9 to ICD 10 codes * -HDVARSEL_INPUT = For requests calculating a HDPS, lists each data dimension dataset * -PSESTIMATIONFILE = Name of the SAS dataset describing parameters for estimating a PS model * -PSMATCHFILE = Name of the SAS dataset describing parameters for a PS Matching analysis * -STRATIFICATIONFILE = Name of the SAS dataset describing parameters for a PS stratification analyses * -COVSTRATFILE = Name of the SAS dataset describing parameters for a covariate stratification analyses * -IPTWFILE = Name of the SAS dataset describing parameters for Inverse Probability Treatment Weight(IPTW) analyses * -PSCSSUBGROUPFILE = Name of the SAS dataset describing parameters for subgroups within the PS/CS submodule * -INDLEVEL = Indicates whether to return an individual level file after PS or Covariate Stratification analysis in the MSOC folder * -DIAGNOSTICS = Indicates if proc logistic diagnostic output files should be generated * * * Programming Notes: * * *-------------------------------------------------------------------------------------------------- * CONTACT INFO: * Sentinel Coordinating Center * info@sentinelsystem.org * **********************************************************************************************************************************************; %macro ms_cidanum(RUNID=, PROJID=, WPTYPE=, WPID=, DPID=, VERID=, PERIODIDSTART=, PERIODIDEND=, ANALYSIS=, MONITORINGFILE=, USERSTRATA=, COMBOFILE=, COHORTFILE=, COHORTCODES=, INCLUSIONCODES=, STOCKPILINGFILE=, RUN_ENVELOPE=, FREEZEDATA=, ZIPFILE=, LABSCODEMAP=, DISTINDEX=, TYPE1FILE=, TYPE2FILE=, TYPE3FILE=, TYPE4FILE=, MODPREGDUR=, TYPE5FILE=, TYPE6FILE=, METADATAFILE=, SURVEILLANCEMODE=, COVARIATECODES=, UTILFILE=, COMORBFILE=, DRUGCLASSFILE=, PROFILE=, MFUFILE=, MULTEVENTFILE=, MULTEVENTFILE_ADHERE=, CONCFILE=, OVERLAPFILE=, OVERLAPFILE_ADHERE=, ITSFILE=, TREATMENTPATHWAYS=, MICOHORTFILE=, TREEFILE=, TREELOOKUP=, ICD10ICD9MAP=, HDVARSEL_INPUT=, PSESTIMATIONFILE= , PSMATCHFILE=, STRATIFICATIONFILE=, COVSTRATFILE=, IPTWFILE=, PSCSSUBGROUPFILE=, INDLEVEL=, DIAGNOSTICS=); %put =====> MACRO CALLED: ms_cidanum ; %ms_starttimer(timestart=qrpruntime); /*---------------------------------------------------*/ /* 01 -- Set up variables needed for the run */ /*---------------------------------------------------*/ %LET PROJID=%LOWCASE(&PROJID.); %LET WPTYPE=%LOWCASE(&WPTYPE.); %LET WPID=%LOWCASE(&WPID.); %LET DPID=%LOWCASE(&DPID.); %LET VERID=%LOWCASE(&VERID.); %LET PERIODIDSTART=%LOWCASE(&PERIODIDSTART.); %LET PERIODIDEND=%LOWCASE(&PERIODIDEND.); %LET ANALYSIS=%LOWCASE(&ANALYSIS.); %LET SURVEILLANCEMODE=%LOWCASE(&SURVEILLANCEMODE.); %let PROFILE=%LOWCASE(&PROFILE.); %let DISTINDEX=%LOWCASE(&DISTINDEX.); %let FREEZEDATA=%LOWCASE(&FREEZEDATA.); %LET MONITORINGFILE=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&MONITORINGFILE.), .sas7bdat, %STR()))); %LET USERSTRATA=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&USERSTRATA.), .sas7bdat, %STR()))); %LET COHORTFILE=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&COHORTFILE.), .sas7bdat, %STR()))); %LET TYPE1FILE=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&TYPE1FILE.), .sas7bdat, %STR()))); %LET TYPE2FILE=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&TYPE2FILE.), .sas7bdat, %STR()))); %LET TYPE3FILE=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&TYPE3FILE.), .sas7bdat, %STR()))); %LET TYPE4FILE=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&TYPE4FILE.), .sas7bdat, %STR()))); %LET TYPE5FILE=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&TYPE5FILE.), .sas7bdat, %STR()))); %LET TYPE6FILE=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&TYPE6FILE.), .sas7bdat, %STR()))); %LET METADATAFILE=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&METADATAFILE.), .sas7bdat, %STR()))); %LET COHORTCODES=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&COHORTCODES.), .sas7bdat, %STR()))); %LET INCLUSIONCODES=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&INCLUSIONCODES.), .sas7bdat, %STR()))); %LET COVARIATECODES=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&COVARIATECODES.), .sas7bdat, %STR()))); %LET MFUFILE=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&MFUFILE.), .sas7bdat, %STR()))); %LET STOCKPILINGFILE=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&STOCKPILINGFILE.), .sas7bdat, %STR()))); %LET UTILFILE=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&UTILFILE.), .sas7bdat, %STR()))); %LET COMORBFILE=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&COMORBFILE.), .sas7bdat, %STR()))); %LET DRUGCLASSFILE=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&DRUGCLASSFILE.), .sas7bdat, %STR()))); %LET COMBOFILE=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&COMBOFILE.), .sas7bdat, %STR()))); %LET MODPREGDUR=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&MODPREGDUR.), .sas7bdat, %STR()))); %LET ZIPFILE=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&ZIPFILE.), .sas7bdat, %STR()))); %LET MULTEVENTFILE=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&MULTEVENTFILE.), .sas7bdat, %STR()))); %LET MULTEVENTFILE_ADHERE=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&MULTEVENTFILE_ADHERE.), .sas7bdat, %STR()))); %LET CONCFILE=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&CONCFILE.), .sas7bdat, %STR()))); %LET OVERLAPFILE=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&OVERLAPFILE.), .sas7bdat, %STR()))); %LET OVERLAPFILE_ADHERE=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&OVERLAPFILE_ADHERE.), .sas7bdat, %STR()))); %LET ITSFILE=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&ITSFILE.), .sas7bdat, %STR()))); %LET TREATMENTPATHWAYS=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&TREATMENTPATHWAYS.), .sas7bdat, %STR()))); %LET MICOHORTFILE=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&MICOHORTFILE.), .sas7bdat, %STR()))); %LET TREEFILE=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&TREEFILE.), .sas7bdat, %STR()))); %LET TREELOOKUP=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&TREELOOKUP.), .sas7bdat, %STR()))); %LET ICD10ICD9MAP=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&ICD10ICD9MAP.), .sas7bdat, %STR()))); %let INDLEVEL=%LOWCASE(&INDLEVEL.); %let PSESTIMATIONFILE=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&PSESTIMATIONFILE.), .sas7bdat, %STR()))); %let PSMATCHFLE=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&PSMATCHFILE.), .sas7bdat, %STR()))); %let STRATIFICATIONFILE=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&STRATIFICATIONFILE.), .sas7bdat, %STR()))); %let IPTWFILE=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&IPTWFILE.), .sas7bdat, %STR()))); %let PSCSSUBGROUPFILE=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&PSCSSUBGROUPFILE.), .sas7bdat, %STR()))); %let COVSTRATFILE=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&COVSTRATFILE.), .sas7bdat, %STR()))); %let DIAGNOSTICS=%lowcase(&DIAGNOSTICS.); /*---------------------------------------------------*/ /* 02 -- Import input files in SAS format */ /*---------------------------------------------------*/ %IMPORTFILES(var=&MONITORINGFILE.); %IMPORTFILES(var=&USERSTRATA.); %IMPORTFILES(var=&COHORTFILE.); %IMPORTFILES(var=&TYPE1FILE.); %IMPORTFILES(var=&TYPE2FILE.); %IMPORTFILES(var=&TYPE3FILE.); %IMPORTFILES(var=&TYPE4FILE.); %IMPORTFILES(var=&TYPE5FILE.); %IMPORTFILES(var=&TYPE6FILE.); %IMPORTFILES(var=&METADATAFILE.); %IMPORTFILES(var=&COHORTCODES.); %IMPORTFILES(var=&INCLUSIONCODES.); %IMPORTFILES(var=&COVARIATECODES.); %IMPORTFILES(var=&MFUFILE.); %IMPORTFILES(var=&STOCKPILINGFILE.); %IMPORTFILES(var=&UTILFILE.); %IMPORTFILES(var=&COMORBFILE.); %IMPORTFILES(var=&DRUGCLASSFILE.); %IMPORTFILES(var=&COMBOFILE.); %IMPORTFILES(var=&DRUGCLASSFILE.); %IMPORTFILES(var=&LABSCODEMAP.); %IMPORTFILES(var=&PTSTOEXCLUDE.); %IMPORTFILES(var=&MODPREGDUR.); %IMPORTFILES(var=&ZIPFILE.); %IMPORTFILES(var=&MULTEVENTFILE.); %IMPORTFILES(var=&MULTEVENTFILE_ADHERE.); %IMPORTFILES(var=&CONCFILE.); %IMPORTFILES(var=&OVERLAPFILE.); %IMPORTFILES(var=&OVERLAPFILE_ADHERE.); %IMPORTFILES(var=&ITSFILE.); %IMPORTFILES(var=&TREATMENTPATHWAYS.); %IMPORTFILES(var=&MICOHORTFILE.); %IMPORTFILES(var=&TREEFILE.); %IMPORTFILES(var=&TREELOOKUP.); %IMPORTFILES(var=&ICD10ICD9MAP.); %IMPORTFILES(var=&PSESTIMATIONFILE.); %IMPORTFILES(var=&PSMATCHFILE.); %IMPORTFILES(var=&STRATIFICATIONFILE.); %IMPORTFILES(var=&IPTWFILE.); %IMPORTFILES(var=&PSCSSUBGROUPFILE.); %IMPORTFILES(var=&COVSTRATFILE.); /*---------------------------------------------------*/ /* 03 - Jump to checkpoint if restarting QRP */ /*---------------------------------------------------*/ %if &restartrun = Y %then %do; %goto checkpoint; %end; /*---------------------------------------------------*/ /* 04 -- Initialize macro variables and */ /* Process input file parameters */ /*---------------------------------------------------*/ *Initialize macro variables; %ms_initmacrovariables(); *Process input files; %ms_processinputfiles(); /*---------------------------------------------------*/ /* 05 -- Process Ranges "-" and Wilcards "*" */ /* in lookup codes */ /*---------------------------------------------------*/ %ISDATA(dataset=_diag); %IF %EVAL(&NOBS.>=1) %THEN %DO; %ms_processwildcards(InFile=_diag, CodeVar=code, OutFile=_diag); %END; /*---------------------------------------------------*/ /* 06 -- Extract Raw Data and run envelope or */ /* Create combo records (if applicable) */ /*---------------------------------------------------*/ %if %str(&COMBOFILE.) = %str() or %length(&COMBOFILE.) = 0. %then %do; *Programming note: We are not using caresettingprincipal in the pre-extraction phase because typical sensitivity analysis around caresettingprincipal could lead to massive claim duplication; /*Procedure extraction*/ %ms_extractmeds(datafile=indata.&proctable., datacode=PX , datacodetype=PX_codetype , lookfile=_proc, mindate = &studystartdate., outfile=worktemp._procextract(keep=PatID ADate EncType PX PX_CodeType)); proc sort data=worktemp._procextract nodupkey; by _all_; run; *Delete data from patients in DPs &PTSTOEXCLUDE. files; %ms_delpatients(datafile=worktemp._procextract, ptsfile=&PTSTOEXCLUDE., Outfile=worktemp._procextract); /*Diagnosis extraction*/ %ms_extractmeds(datafile=indata.&diatable., datacode=DX, datacodetype=DX_codetype, lookfile=_diag, mindate = &studystartdate., outfile=worktemp._diagextract(keep = PatID ADate EncType DX DX_CodeType PDX)); proc sort data=worktemp._diagextract nodupkey; by _all_; run; *Delete data from patients in DPs &PTSTOEXCLUDE. files; %ms_delpatients(datafile=worktemp._diagextract, ptsfile=&PTSTOEXCLUDE., Outfile=worktemp._diagextract); /*Dispensing extraction*/ *Codes must be unique to avoid claim duplication.; proc sort nodupkey data=_ndc; by code; run; %ms_extractdrugs(datafile=indata.&distable., lookfile=_ndc, lookvar=code , mindate = &studystartdate., outfile=drugs); proc sort data=drugs out=worktemp.drugs(where=(RxSup>0 and RxAMt>0)) nodupkey; by _all_; run; proc datasets nowarn noprint lib=work; delete drugs; quit; *Delete data from patients in DPs &PTSTOEXCLUDE. files; %ms_delpatients(datafile=worktemp.drugs, ptsfile=&PTSTOEXCLUDE., Outfile=worktemp.drugs); /*Lab extraction*/ %ms_extractlabs(datafile=indata.&labtable., lookfile=_lab, mindate = &studystartdate., outfile=worktemp.labextract); proc sort data=worktemp.labextract nodupkey; by _all_; run; *Delete data for patients in DPs &PTSTOEXCLUDE. files; %ms_delpatients(datafile=worktemp.labextract, ptsfile=&PTSTOEXCLUDE., Outfile=worktemp.labextract); %end; %else %do; *Combo is called using a macro wrapper to preserve the scoping of macro call combo variables (specifically STOCKPILINGFILE); %MACRO RUNCOMBO; %let COMBORUN=1; %let DXENVEL = 1; %let PXENVEL = 1; %if %EVAL(&RUN_ENVELOPE. = 2) %then %do; %let DXENVEL = 0; %let PXENVEL = 0; %end; %combo(COMBFILE=&COMBOFILE., CODESFILE=&COMBOFILE.Codes, DXENVEL=&DXENVEL., PXENVEL=&PXENVEL., OUTNAME=&RUNID._Combo, STOCKPILING=1, STOCKPILINGFILE=&COMBOFILE.Stock, ENROLGAP=0, LABSCODEMAP=&LABSCODEMAP., SAVETODPLOCAL=N, PTSTOEXCLUDE=&PTSTOEXCLUDE.); %MEND RUNCOMBO; %RUNCOMBO; %end; *Deaths, MI Linkage are not processed by combo tool. Therefore they must be extracted no matter if combo is run; *Encounters can optionally be extracted by ms_cidanum outside of combo tool whether or not combo is run; /*MI Linkage table extraction*/ %ms_extractmilinkage(datafile=indata.&miltable., lookfile=_mil, mindate = &studystartdate., outfile=worktemp.milextract); *Delete data for patients in DPs &PTSTOEXCLUDE. files; %ms_delpatients(datafile=worktemp.milextract, ptsfile=&PTSTOEXCLUDE., Outfile=worktemp.milextract); /*Encounter table extraction*/ %ms_extractencounters(datafile=indata.&enctable., lookfile=_enc, mindate = &studystartdate., outfileprefix=worktemp.encextract); *Delete data for patients in DPs &PTSTOEXCLUDE. files; %if %str("&enctypeextractlist.") ne %str("") %then %do; %macro wrapper(); %local e enc; %do e = 1 %to %sysfunc(countw(&enctypeextractlist.)); %let enc = %scan(&enctypeextractlist., &e.); %ms_delpatients(datafile=worktemp.encextract&enc., ptsfile=&PTSTOEXCLUDE., Outfile=worktemp.encextract&enc.); %end; %mend; %wrapper(); %end; * Deaths are not processed by combo tool. Therefore they must be extracted no matter if combo is run; %ms_extractdeaths(deathfile=indata.&DEATHTABLE., encounterfile=indata.&enctable., codfile=indata.&CODTABLE., codlookupfile=_cod, deathoutfile=worktemp.deathextract, codoutfile=worktemp.codextract); * Delete data for patients in DPs &PTSTOEXCLUDE. files; %ms_delpatients(datafile=worktemp.deathextract, ptsfile=&PTSTOEXCLUDE., Outfile=worktemp.deathextract); %ms_delpatients(datafile=worktemp.codextract, ptsfile=&PTSTOEXCLUDE., Outfile=worktemp.codextract); *Combine _diags and _procs for envelope later; data worktemp.meds(keep=Patid Adate Code Pdx EncType /*RxSup RxAmt*/ CodeType CodeCat); length adate 4 code $&codelength.; set worktemp._procextract (in = procex) worktemp._diagextract (in = diagex); if procex then do; code = compress(PX,' .'); PDX = " "; Codetype = PX_codetype; CodeCat = "PX"; end; else if diagex then do; code = compress(DX,' .'); Codetype = DX_codetype; CodeCat = "DX"; end; *RxSup = 1; *RxAmt = 1; run; * Delete _procextract and _diagextract from worktemp; proc datasets nowarn noprint lib=worktemp; delete _procextract _diagextract; quit; *If meds records not out of combo, run envelope; %ISDATA(dataset=worktemp.meds); %if (%str(&COMBOFILE.) = %str() or %length(&COMBOFILE.) = 0.) & %EVAL(&NOBS.>=1) & %EVAL(&RUN_ENVELOPE. ne 2) %then %do; %MS_ENVELOPE(INFILE=worktemp.meds, /*Name of SAS dataset with diagnosis and/or procedure claims data*/ ENCOUNTERINFILE=indata.&ENCTABLE., /*Name of SAS dataset with encounter data*/ OUTFILE=worktemp.meds); /*Name of output file with reclassified claims*/ %end; proc datasets library=work nowarn nolist; delete _:; quit; /*---------------------------------------------------*/ /* 07 -- Reconcile all enrollment spans */ /*---------------------------------------------------*/ %ms_create_enrollment_spans(); /*---------------------------------------------------*/ /* 08 -- Create worktemp.meds partition */ /*---------------------------------------------------*/ *Partitition worktemp.meds if diagnosis or procedure claims are requested in %scenarioloop; %isdata(dataset=worktemp.meds); %if %eval(&nobs.>0) %then %do; %let partition=N; data _null_; set &COHORTCODES.(where=(codecat in ('DX','PX') and group in (&cohortgrplist.))); if _n_ =1 then call symputx('partition', 'Y'); run; %if &partition.= Y %then %do; %ms_partition_patients(datalib =WORKTEMP, datafile =MEDS, split_vars =patid, outfile =medspartition); /*Number of partitions*/ proc sql noprint; select max(partition) into: nummeds_partitions from medspartition; quit; /*Split data if nummeds_partitions>1*/ %if %eval(&nummeds_partitions.)>1 %then %do; %ms_partition_splitdata(partitiondata =medspartition, datafile =worktemp.meds(keep=patid adate codecat codetype code enctype pdx), outfile =medstemp.meds, num_partitions=&nummeds_partitions.); /*delete worktemp.meds to save disk space*/ proc datasets nowarn noprint lib=worktemp; delete meds; quit; %end; %end; %end; /*---------------------------------------------------*/ /* 09 -- Loop through Group(s) */ /*---------------------------------------------------*/ /*Output preproccessing runtime*/ %ms_stoptimer(timestart=qrpruntime); %ms_outputruntimes(timevar=qrpruntime, step=%str(Preprocessing/code extraction), group=, monitoringperiod=); /*---------------------------------------------------*/ /* If restarting QRP, restore prior session */ /*---------------------------------------------------*/ %checkpoint: %let startgroup = 1; %if &restartrun = Y %then %do; /*Replace dplocal and msoc folder contents*/ proc datasets nowarn noprint lib=dplocal kill; quit; proc copy in=dptemp out=dplocal memtype=data; run; proc datasets nowarn noprint lib=msoc kill; quit; proc copy in=msoctemp out=msoc memtype=data; run; proc datasets nowarn noprint lib=worktemp kill; quit; proc copy in=wrktemp2 out=worktemp memtype=data; run; data _null_; set dplocal.&runid._checkpoints nobs=nobs; if _n_ = nobs then do; startgroup = groupnum+1; call symput("startgroup", put(startgroup, best.)); end; run; %if %eval(&startgroup.>&ngroup.) %then %goto postgrouploop; %end; %macro ms_scenarioloop; %do Group=&startgroup. %to &Ngroup.; /*---------------------------------------------------*/ /* 09.a -- Loop pre-processing */ /*---------------------------------------------------*/ /*loop timing*/ %ms_starttimer(timestart=loopruntime); *Set current Group macro parameters; %ms_setnumloopmacrovars(); %PUT INFO: NOW LOOPING ON &ITGROUP.; %PUT &ITGROUP. processing began on %sysfunc(date(),date9.) %sysfunc(time(),tod8.); *Set query period for data driven queries; %if "&datadrivenqueryperiod" = "Y" %then %do; %ms_setdatadrivenqueryperiod(); %end; *Get specific codes for this loop, separate diags from others to process wildcards, and set flags to carry through variables needed to compute dose; %let computedose = N ; %let computepov3cumdose = N; %let computepov3afdd = N; %let computepov3cfdd = N; data _diag _others; set &COHORTCODES.(where=(group="&ITGROUP.")); /*only keep strength if specified in codes file*/ if missing(strength)=0 and missing(unit)=0 then call symputx('computedose', 'Y'); %if &excl_incl. = Y %then %do; if indexcriteria in ('INC', 'EXC') and mincumdose >0 then call symputx('computepov3cumdose', 'Y'); if indexcriteria in ('INC', 'EXC') and (minafdd >0 | maxafdd>0) then call symputx('computepov3afdd', 'Y'); if indexcriteria in ('INC', 'EXC') and (mincfdd >0 | maxcfdd>0) then call symputx('computepov3cfdd', 'Y'); %end; if CodeCat in("DX") then output _diag ; else output _others; run; %ISDATA(dataset=_diag); %IF %EVAL(&NOBS.>=1) %THEN %DO; %MS_ProcessWildcards(InFile=_diag, CodeVar=code, OutFile=_diag); %END; *Create Loop-specific parameter files; data _ITGroupParamNDC (keep = obsnum codecat codetype code dateonly stockgroup codesupply indexcriteria CareSettingprincipal %if &computedose. = Y %then %do; strength %end; %if %eval(&type. = 2) %then %do; fupcriteria %end; %else %if %eval(&type. = 3) %then %do; fupcriteria %end; %else %if %eval(&type. = 4) %then %do; fupcriteria PriorityGroup1 PriorityGroup2 duration priority %end; %else %if %eval(&type. = 6) %then %do; productapprovaldate productmarketingdate otherproductdate %end; %if &excl_incl = Y %then %do; &InclExclVars. %if &computepov3cumdose. = Y %then %do; mincumdose %end; %if &computepov3cfdd. = Y %then %do; mincfdd maxcfdd %end; %end;) _ITGroupParamNDCForExtract (keep = obsnum code codetype codesupply) /* NDC extract for processing loopmeds*/ _ITGroupParamMeds (keep = obsnum codecat codetype code dateonly codesupply indexcriteria CareSettingprincipal %if %eval(&type. = 2) %then %do; fupcriteria %end; %else %if %eval(&type. = 3) %then %do; fupcriteria %end; %else %if %eval(&type. = 4) %then %do; fupcriteria PriorityGroup1 PriorityGroup2 duration priority %end; %else %if %eval(&type. = 6) %then %do; productapprovaldate productmarketingdate otherproductdate %end; %if &excl_incl = Y %then %do; &InclExclVars. %end;) _ITGroupParamLabs (keep = codecat codetype code dateonly codesupply indexcriteria CareSettingprincipal RawLabResult RawLabDateType Group %if %eval(&type. = 2) %then %do; fupcriteria %end; %else %if %eval(&type. = 3) %then %do; fupcriteria %end; %else %if %eval(&type. = 4) %then %do; fupcriteria PriorityGroup1 PriorityGroup2 duration priority %end; %else %if %eval(&type. = 6) %then %do; productapprovaldate productmarketingdate otherproductdate %end; %if &excl_incl = Y %then %do; &InclExclVars. %end; rename=(CareSettingprincipal=RawCaresetting Group=RawGroup)) _ITGroupParamDate (keep = codecat codetype code dateonly codesupply indexcriteria %if %eval(&type. = 2) %then %do; fupcriteria %end; %else %if %eval(&type. = 3) %then %do; fupcriteria %end; %else %if %eval(&type. = 4) %then %do; fupcriteria PriorityGroup1 PriorityGroup2 duration priority %end; %else %if %eval(&type. = 6) %then %do; productapprovaldate productmarketingdate otherproductdate %end; %if &excl_incl = Y %then %do; &InclExclVars. %end;) _ITGroupParamMIL (keep = codecat codetype code dateonly codesupply indexcriteria %if %eval(&type. = 2) %then %do; fupcriteria %end; %else %if %eval(&type. = 3) %then %do; fupcriteria %end; %else %if %eval(&type. = 4) %then %do; fupcriteria PriorityGroup1 PriorityGroup2 duration priority %end; %else %if %eval(&type. = 6) %then %do; productapprovaldate productmarketingdate otherproductdate %end; %if &excl_incl = Y %then %do;&InclExclVars. %end;) _ITGroupParamEnc (keep = codecat codetype code dateonly codesupply indexcriteria CareSettingprincipal %if %eval(&type. = 2) %then %do; fupcriteria %end; %else %if %eval(&type. = 3) %then %do; fupcriteria %end; %else %if %eval(&type. = 4) %then %do; fupcriteria %end; %else %if %eval(&type. = 6) %then %do; productapprovaldate productmarketingdate otherproductdate %end; %if &excl_incl = Y %then %do; &InclExclVars. %end;) _ITGroupParamDth (keep = codecat codetype code dateonly codesupply indexcriteria CareSettingprincipal %if %eval(&type. = 2) %then %do; fupcriteria %end; %else %if %eval(&type. = 3) %then %do; fupcriteria %end; %else %if %eval(&type. = 4) %then %do; fupcriteria %end; %else %if %eval(&type. = 6) %then %do; productapprovaldate productmarketingdate otherproductdate %end; %if &excl_incl = Y %then %do; &InclExclVars. %end;) ; set _diag _others; obsnum = _N_; *Defensive coding; *Do not create Incl/Excl variables if they are not required; %if &excl_incl = Y %then %do; if Condinclusion=. then Condinclusion=1; if SubCondinclusion=. then SubCondinclusion=1; if Cond=. then Cond=-1; if SubCond=. then SubCond=-1; if codedays = . then codedays = 1; %end; if missing(dateonly) then dateonly = 'N'; else dateonly=upcase(dateonly); *Output; if CodeCat="RX" then do; output _ITGroupParamNDC; output _ITGroupParamNDCForExtract; end; else if CodeCat in("DX","PX") then output _ITGroupParamMeds; else if CodeCat in("LB") then output _ITGroupParamLabs; else if CodeCat in("AN","DT") then output _ITGroupParamDate; else if CodeCat in("MI") then output _ITGroupParamMIL; else if CodeCat in("EN") then output _ITGroupParamEnc; else if CodeCat in("DH","CD") then output _ITGroupParamDth; run; *Indicator if group index determined by Age Anniversary or Calendar Date; %let agedatecohort = N; %isdata(dataset=_ITGroupParamDate); %if %eval(&nobs.) > 0 %then %do; %let agedatecohort = Y; %end; *Break out CaresettingPrincipal into Caresetting and Principal; %ms_caresettingprincipal(InFile=_ITGroupParamMeds, Var=CareSettingPrincipal, OutFile=_ITGroupParamMeds); %ms_caresettingprincipal(InFile=_ITGroupParamEnc, Var=CareSettingPrincipal, OutFile=_ITGroupParamEnc); %ms_caresettingprincipal(InFile=_ITGroupParamDth, Var=CareSettingPrincipal, OutFile=_ITGroupParamDth); * Meds dataset with reduced variables for processing loopmeds; data _ITGroupParamMedsForExtract; set _ITGroupParamMeds(keep = obsnum code codetype codecat pdx enctype); run; /*---------------------------------------------------*/ /* 09.b -- Extract loop-specific records */ /*---------------------------------------------------*/ *Partitition worktemp.enr_&enrollmentnum. and execute ms_loopmeds/ms_shaveoutside for each partition; %isdata(dataset=_ITGroupParamMeds); %if %eval(&nobs.>0) %then %do; /*Split data if nummeds_partitions>1*/ %if %eval(&nummeds_partitions.)>1 %then %do; %ms_partition_splitdata(partitiondata =medspartition, datafile =worktemp.enr_&enrollmentnum.(keep=patid enr_start enr_end), outfile =worktemp.enr_&enrollmentnum., num_partitions=&nummeds_partitions.); %end; /*loop through partitions*/ %do p = 1 %to %eval(&nummeds_partitions.); %if %eval(&nummeds_partitions.) = 1 %then %do; %let datafile = worktemp.meds; %let pnum = ; %end; %else %do; %let datafile = medstemp.meds_&p.; %let pnum = _&p.; %end; *Extract Records necessary for creating this group only (record duplic OK + add loop parameters back to records); %ms_loopmeds(datafile=&datafile., lookfile=_ITGroupParamMedsForExtract, multiplecodecat=Y, outfile=_ITMeds&pnum.); /*----------------------------------------------*/ /* Shave claims - Meds only in partition loop */ /*----------------------------------------------*/ *Make sure all claims overlap enrollment span and only keep eligible exposures (overlaping Enr_Start Enr_End); %ms_shaveoutside(reffile=worktemp.enr_&enrollmentnum.&pnum.(keep=enr_start enr_end patid), refstart=Enr_Start, refend=Enr_End, KeepPartBf=N, ToShaveFile=_ITMeds&pnum.(keep=patid adate obsnum enctype pdx), ToShaveStart=ADate, ToShaveEnd=ADate, shaverx=N, outfile=_ITMeds&pnum.); /* Get meds required parameters using obsnum as the key */ proc sql noprint undo_policy=none; create table _ITMeds&pnum.(drop=obsnum) as select a.PatId, a.ADate, a.enr_start, a.enr_end, a.enctype, a.pdx, b.* from _ITMeds&pnum. as a inner join _ITGroupParamMeds (keep = obsnum codecat codetype code codesupply dateonly indexcriteria %if %eval(&type. = 2) %then %do; fupcriteria %end; %else %if %eval(&type. = 3) %then %do; fupcriteria %end; %else %if %eval(&type. = 4) %then %do; fupcriteria PriorityGroup1 PriorityGroup2 duration priority %end; %else %if %eval(&type. = 6) %then %do; productapprovaldate productmarketingdate otherproductdate %end; %if &excl_incl = Y %then %do; &InclExclVars. %end;) as b on a.obsnum=b.obsnum; quit; %end; %if %eval(&nummeds_partitions.)>1 %then %do; /*Stack partitioned data and delete partitions*/ data _itmeds; set _itmeds_:; run; proc datasets nowarn noprint lib=worktemp; delete enr_&enrollmentnum._:; quit; proc datasets nowarn noprint lib=work; delete _itmeds_:; quit; %end; %end; %else %do; data _ITMeds; length codetype $3.; set %if %eval(&nummeds_partitions.) > 1 %then %do; medstemp.meds_1(obs=0) %end; %else %do; worktemp.meds(obs=0) %end; _ITGroupParamMeds(obs=0 drop=code); run; %end; /*Encounters*/ options minoperator; %ms_loopenc(datafilesuffix=worktemp.encextract, lookfile=_ITGroupParamEnc, keepvars = codetype codecat codesupply dateonly code %if &excl_incl = Y %then %do; &InclExclVars. %end; enctype indexcriteria %if &type. in (2 3 4) %then %do; fupcriteria %end; %if %eval(&type.=6) %then %do; productapprovaldate productmarketingdate otherproductdate %end;, outfile=_ITEnc); options nominoperator; /*Death*/ %ms_loopdth(deathdatafile=worktemp.deathextract, coddatafile=worktemp.codextract, lookfile=_ITGroupParamDth, keepvars = indexcriteria codesupply dateonly CodeType EncType %if %eval(&type=2 | &type=3 | &type=4) %then %do; fupcriteria %end;, outfile=_ITDth); %macro mergedrugvars(outfile= , allvarsfile=); /* Get drugs required parameters using obsnum as the key. Select only variables that will be relevant for the ms_stockpiling macro as the others will be dropped after the macro execution anyway */ proc sql noprint undopolicy=none; create table &outfile. as select a.Patid, a.RxDate, a.RxAmt, a.Codetype, case when not missing(a.codesupply) then a.CodeSupply else a.RxSup end as RxSup, case when not missing(a.codesupply) then (a.Rxdate + a.codesupply-1) else (a.Rxdate + a.RxSup-1) end as RxSupEndDt format date9., b.CodeCat, b.StockGroup, b.indexcriteria, %if &computedose. = Y %then %do; b.strength, %end; %if %eval(&type. = 2) %then %do; b.fupcriteria, %end; %else %if %eval(&type. = 3) %then %do; b.fupcriteria, %end; %else %if %eval(&type. = 4) %then %do; b.fupcriteria, %end; %if &excl_incl = Y %then %do; b.condinclusion, b.subcondinclusion, b.cond, b.subcond, b.condfrom, b.condto, b.codedays, %if &computepov3cumdose. = Y %then %do; b.mincumdose, %end; %if &computepov3cfdd. = Y %then %do; b.mincfdd, b.maxcfdd, %end; %end; %if %eval(&type.=6) %then %do; a.rx, b.productapprovaldate, b.productmarketingdate, b.otherproductdate, %end; b.dateonly from &outfile. as a join &allvarsfile. as b on a.obsnum=b.obsnum; quit; %mend mergedrugvars; %ms_extractdrugs(datafile=worktemp.drugs, lookfile=_ITGroupParamNDCForExtract, lookvar=code , mindate=, outfile=_ITDrugs); %mergedrugvars(outfile=_ITDrugs, allvarsfile =_ITGroupParamNDC); %if &CHKCOMBREC = 1 %then %do; %ms_extractdrugs(datafile=worktemp.drugscomb, lookfile=_ITGroupParamNDCForExtract, lookvar=code , mindate=, outfile=_ITDrugsComb); %mergedrugvars(outfile=_ITDrugsComb, allvarsfile =_ITGroupParamNDC); %end; %ms_extractlabs(datafile=worktemp.labextract, lookfile=_ITGroupParamLabs, mindate=, outfile=_ITlabs); %ms_extractmilinkage(datafile=worktemp.milextract, lookfile=_ITGroupParamMIL, mindate=, outfile=_ITMIL); /*---------------------------------------*/ /* 09.c -- Shave enrollment spans */ /*---------------------------------------*/ *Make sure all claims overlap enrollment span and only keep eligible exposures (overlaping Enr_Start Enr_End); %ms_shaveoutside(reffile=worktemp.enr_&enrollmentnum., refstart=Enr_Start, refend=Enr_End, KeepPartBf=N, ToShaveFile=_ITDrugs, ToShaveStart=RxDate, ToShaveEnd=RxSupEndDt, shaverx=Y, outfile=_ITDrugs); %ISDATA(dataset=_ITDrugsComb); %IF %EVAL(&NOBS.>=1) %THEN %DO; %ms_shaveoutside(reffile=worktemp.enr_&enrollmentnum., refstart=Enr_Start, refend=Enr_End, KeepPartBf=N, ToShaveFile=_ITDrugsComb, ToShaveStart=RxDate, ToShaveEnd=RxSupEndDt, shaverx=Y, outfile=_ITDrugsComb(drop=Enr_Start Enr_end)); %END; %isdata(dataset=_ITLabs); %if %eval(&NOBS.>=1) %then %do; %ms_shaveoutside(reffile=worktemp.enr_&enrollmentnum., refstart=Enr_Start, refend=Enr_End, KeepPartBf=N, ToShaveFile=_ITLabs (keep=PatID Adate codecat codetype code CodeSupply dateonly indexcriteria %if %eval(&type. = 2 | &type. = 3 ) %then %do; fupcriteria %end; %else %if %eval(&type. = 4) %then %do; fupcriteria PriorityGroup1 PriorityGroup2 duration priority %end; %else %if %eval(&type. = 6) %then %do; productapprovaldate productmarketingdate otherproductdate %end; %if &excl_incl = Y %then %do; &InclExclVars. %end; ), ToShaveStart=ADate, ToShaveEnd=ADate, shaverx=N, outfile=_ITLabs); %end; %isdata(dataset=_ITEnc); %if %eval(&NOBS.>=1) %then %do; %ms_shaveoutside(reffile=worktemp.enr_&enrollmentnum., refstart=Enr_Start, refend=Enr_End, KeepPartBf=N, ToShaveFile=_ITEnc, ToShaveStart=adate, ToShaveEnd=expiredt, shaverx=Y, outfile=_ITEnc); %end; %isdata(dataset=_ITDth); %if %eval(&NOBS.>=1) %then %do; %ms_shaveoutside(reffile=worktemp.enr_&enrollmentnum., refstart=Enr_Start, refend=Enr_End, KeepPartBf=N, ToShaveFile=_ITDth, ToShaveStart=DeathDt, ToShaveEnd=DeathDt, shaverx=N, outfile=_ITDth); %end; *For MIL analysis, Mother must be enrolled on ADate. Infant claim not shaved; %ms_shaveoutside(reffile=worktemp.enr_&enrollmentnum., refstart=Enr_Start, refend=Enr_End, KeepPartBf=N, ToShaveFile=_ITMil, ToShaveStart=ADate, ToShaveEnd=ADate, shaverx=N, outfile=_ITMIL); /*For Type 6 analysis, need to select earliest date for same-day dispensings before getting resolved in %ms_stockpiling. if uptakedate = COMPUTEDSTARTMARKETINGDATE, can ignore, because specific COMPUTEDSTARTMARKETINGDATE is GROUP and not NDC specific*/ %if %eval(&type.=6) & %upcase("&UPTAKEDATE.") ne "COMPUTEDSTARTMARKETINGDATE" %then %do; %isdata(dataset=_itdrugs); %if %eval(&nobs.>0) %then %do; proc means data=_itdrugs noprint nway; var &uptakedate.; class patid rxdate indexcriteria; output out=_mindates(drop=_:) min=; run; proc sql noprint undo_policy=none; create table _itdrugs as select x.*, y.&uptakedate. from _itdrugs(drop=&uptakedate.) as x, _mindates as y where x.patid = y.patid and x.rxdate = y.rxdate and x.indexcriteria=y.indexcriteria; quit; %end; %end; /*Type 3*/ %if %str(&ExclOnSameDay.)=%str(Y) %then %do; *Identify SameDayDispensings for different NDCs but from the same group; proc sort nodupkey data=_ITDrugs(keep=Patid rxdate ndc indexcriteria) out=_SameDayNDCs(keep=Patid rxdate ndc); by Patid rxdate ndc; WHERE indexcriteria="DEF"; run; proc means data=_SameDayNDCs nway noprint; class Patid rxdate; output out=_SameDayNDCs(where=(_freq_>1)); run; %end; /*--------------------------------------------------------------*/ /* 09.d -- Create claims dataset based on age or calendar date */ /*--------------------------------------------------------------*/ %ms_extractanniversarydate(datafile = worktemp.enr_&enrollmentnum., lookfile = _ITGroupParamDate, lookvar = code, outfile = _itdates); /*---------------------------------------------------*/ /* 09.e -- Apply StockPiling */ /*---------------------------------------------------*/ %let unique_stock_params=0; %ISDATA(dataset=STOCKPILE_NONCOVAR); %if %eval(&NOBS>0) %then %do; /* store maximum number of combination of stockpiling parameters */ proc sql noprint; select max(stocknumber) into :unique_stock_params from STOCKPILE_NONCOVAR where group="&ITGROUP."; quit; %end; %if &unique_stock_params <= 1 %then %do; %if &unique_stock_params <= 0 %then %do; /* set defaults */ %let SAMEDAY=aa; %let SUPRANGE=0<-HIGH; %let AMTRANGE=0<-HIGH; %let PERCENTDAYS=; %end; %else %do; data _null_; set STOCKPILE_NONCOVAR; where group="&ITGROUP"; call symputx("SAMEDAY",strip(SameDay)); call symputx("SUPRANGE",strip(SupRange)); call symputx("AMTRANGE",strip(AmtRange)); call symputx("PERCENTDAYS",put(PercentDays,best.)); run; %end; /* =1 */ %MS_STOCKPILING(INFILE=_ITDrugs, CLMDATE=RxDate, CLMSUP=RxSup, CLMAMT=RxAmt, PROCFLAG=, PERCENTDAYS=&PERCENTDAYS., %if &computedose. = Y %then %do; strength = strength, %end; GROUPING=StockGroup indexcriteria dateonly %if %eval(&type. = 2) %then %do; fupcriteria %end; %else %if %eval(&type. = 3) %then %do; fupcriteria %end; %else %if %eval(&type. = 4) %then %do; fupcriteria %end; %if &excl_incl = Y %then %do; &InclExclVars. %if &computepov3cumdose. = Y %then %do; mincumdose %end; %if &computepov3cfdd. = Y %then %do; mincfdd maxcfdd %end; %end;, SAMEDAY=&SAMEDAY., SUPRANGE=&SUPRANGE., AMTRANGE=&AMTRANGE., ID=CODECAT &t6vars., OUTFILE=_ITDrugs, OUTFILEEXCL=_ITDrugsExcl ); %end; /* <=1 */ %if &unique_stock_params > 1 %then %do; %do z = 1 %to &unique_stock_params; data STOCKPILE_NONCOVAR_&z; set STOCKPILE_NONCOVAR; where group="&ITGROUP." and stocknumber=&z; call symputx("SAMEDAY",strip(SameDay)); call symputx("SUPRANGE",strip(SupRange)); call symputx("AMTRANGE",strip(AmtRange)); call symputx("PERCENTDAYS",put(PercentDays,best.)); run; /* Only process dataset if there are subsetted observations */ %ISDATA(dataset=STOCKPILE_NONCOVAR_&z); %if %eval(&NOBS>0) %then %do; %let stock_list=; proc sql noprint; select distinct quote(strip(stockgroup)) into :stock_list separated by ' ' from STOCKPILE_NONCOVAR_&z; quit; %MS_STOCKPILING(INFILE=_ITDrugs(where=(stockgroup in (&stock_list))), CLMDATE=RxDate, CLMSUP=RxSup, CLMAMT=RxAmt, PROCFLAG=, PERCENTDAYS=&PERCENTDAYS., %if &computedose. = Y %then %do; strength = strength, %end; GROUPING=StockGroup indexcriteria dateonly %if %eval(&type. = 2) %then %do; fupcriteria %end; %else %if %eval(&type. = 3) %then %do; fupcriteria %end; %else %if %eval(&type. = 4) %then %do; fupcriteria %end; %if &excl_incl = Y %then %do; &InclExclVars. %if &computepov3cumdose. = Y %then %do; mincumdose %end; %if &computepov3cfdd. = Y %then %do; mincfdd maxcfdd %end; %end;, SAMEDAY=&SAMEDAY., SUPRANGE=&SUPRANGE., AMTRANGE=&AMTRANGE., ID=CODECAT &t6vars., OUTFILE=_ITDrugs_&z, OUTFILEEXCL=_ITDrugsExcl_&z ); %end; /* %isdata(&STOCKPILE_NONCOVAR._&z) */ %end; /* z */ /* Stack all datasets together */ data _ITDrugs; set _ITDrugs_:; run; data _ITDrugsExcl; set _ITDrugsExcl_:; run; /* Delete temporary datasets */ proc datasets nowarn noprint lib=work; delete _ITDrugs_: _ITDrugsExcl_: stockpile_noncovar_:; quit; %end; /* unique_stock_params > 1 */ %if &CHKCOMBREC = 1 %then %do; data _ITDrugs; set _ITDrugs _ITDrugsComb(in=a); *ExpireDt does not exist in _ITDrugsComb; length ExpireDt 4; if a then ExpireDt=Rxdate+RxSup-1; run; %end; *Need to reshave because Stockpiling may have pushed claims outside enrollment period; %ISDATA(dataset=_ITDrugs); %IF %EVAL(&NOBS.>=1) %THEN %DO; %ms_shaveoutside(reffile=worktemp.enr_&enrollmentnum., refstart=Enr_Start, refend=Enr_End, KeepPartBf=N, ToShaveFile=_ITDrugs, ToShaveStart=RxDate, ToShaveEnd=ExpireDt, shaverx=Y, outfile=_ITDrugs); %END; proc datasets library=work nowarn nolist; delete _diag _others; quit; /*---------------------------------------------------*/ /* 09.f -- Create raw POVs datasets */ /*---------------------------------------------------*/ data _GroupIndex(keep=PatId Adate ExpireDt RXsup RXAmt NumDispensing Enr_Start Enr_end /* POV1: Primary cohort Group Index Date (GroupIndex) */ %if %eval(&type = 6) %then %do; productapprovaldate productmarketingdate otherproductdate %end; codecat codetype code stockgroup enctype pdx %if %eval(&type = 4) %then %do; csex linkedid cbirth_date cenr_start birth_type matchmethod %end; %if &computedose. = Y & %eval(&type.=2) %then %do; strength cumdose &rxsupvar. &rxamtvar. %end; %if &computedose. = Y & %eval(&type.=5) %then %do; strength %end;) _GroupWashForTrunk(keep=PatId Adate) /* POV4: Primary Cohort Truncation (GroupTrunk) */ _InclExcl(keep=PatId ADate ExpireDt %if &excl_incl = Y %then %do; &InclExclVars. %end; %if &computepov3cumdose. = Y %then %do; cumdose rxsup mincumdose stockgroup %end; %if &computepov3afdd. = Y %then %do; cfdd NumDispensing stockgroup %end; %if &computepov3cfdd. = Y %then %do; cfdd mincfdd maxcfdd %end; ) /* POV3: Inclusion/Exclusion (InclExcl) */ _FUPEvent(keep=PatId Adate ExpireDt codecat codetype code dateonly stockgroup enctype pdx) /* POV5: Risk Follow-Up Event (FUPEvent) */ _FUPWash(keep=PatId Adate ExpireDt dateonly) /* POV6: Risk Follow-Up Washout (FUPWash) */ /*Type 4 files*/ %if %eval(&type.=4) %then %do; %do n=1 %to &NUM_MPN.; _GroupIndex&n.(keep=PatId Adate ExpireDt Enr_Start Enr_End NumDispensing RXsup RXAmt CodeSupply) /* POV1: Primary cohort Group Index Date (GroupIndex) */ _GroupWash&n.(keep=PatId Adate ExpireDt dateonly) /* POV2: Primary Cohort Group Washout (GroupWash) */ %end; _GroupPreg(keep=PatId Adate Code PriorityGroup1 PriorityGroup2 /* Pregnancy cohort Group duration def (GroupPreg) */ Priority Duration rename=code=pregdurcode) %end; /*Type 6 files*/ %if %eval(&type.=6) %then %do; _GroupIndex2(keep=PatId Adate ExpireDt RXsup RXAmt NumDispensing Enr_Start Enr_end /* POV1: Secondary Cohort Group Index Date (GroupIndex2) */ productapprovaldate productmarketingdate otherproductdate code) %end; ; length code $&codelength. expiredt 4; set _ITDrugs(in=a rename=RxDate=ADate %if %eval(&type.=6) %then %do; rename=rx=code %end;) _ITMeds(in=b) _ITLabs(in=c) _itdates(in=d) _itmil(in=e) _itenc(in=f) _itDth(in=g rename=DeathDt=ADate); /*Dose*/ %if (&computedose. = Y & %eval(&type.=2)) | &computepov3cumdose.=Y %then %do; cumdose = strength*RxAmt; %end; %if &computepov3afdd. = Y | &computepov3cfdd. = Y %then %do; cfdd = (strength*rxamt)/rxsup; %end; if b or c or d or e or g then do; if not missing(codesupply) then RxSup = CodeSupply; else RxSup = 1; Expiredt=Adate+RxSup-1; RXAmt=1; NumDispensing = 1; end; if f then do; NumDispensing = 1; end; %if %eval(&type.=1) %then %do; /*POV1*/ if indexcriteria in('DEF') then output _GroupIndex; /*POV3*/ if indexcriteria in('INC','EXC') then output _InclExcl; %end; %if %eval(&type.=2) %then %do; /*POV1*/ if indexcriteria in('DEF') then do; %if &POINT = Y %then %do; %if &mincumdose ne . | (&maxcumdose. ne . and &cumdoseper. ne .) | &mincfdd. ne . | &maxcfdd. ne . %then %do; origrxsup = rxsup; origrxamt = rxamt; %end; rxsup=0; rxamt=0; %end; output _GroupIndex; end; /*POV4*/ if indexcriteria in('FUT') then output _GroupWashForTrunk; /*POV3*/ if indexcriteria in('INC','EXC') then output _InclExcl; /*POV5*/ if fupcriteria in('DEF') then output _FUPEvent; /*POV6*/ if fupcriteria in('IOC') then output _FUPWash; %end; %if %eval(&type.=3) %then %do; /*POV1*/ if indexcriteria in('DEF') then output _GroupIndex; /*POV3*/ if indexcriteria in('INC','EXC') then output _InclExcl; /*POV5*/ if fupcriteria in('DEF') then output _FUPEvent; /*POV6*/ if fupcriteria in('IOC') then output _FUPWash; %end; %if %eval(&type.=4) %then %do; /*POV1*/ if indexcriteria in('DEF') then output _GroupIndex; %do n=1 %to &NUM_MPN.; /*POV1*/ if indexcriteria in("MP&n.") then do; %if &POINT. = Y %then %do; rxsup=0; rxamt=0; %end; output _GroupIndex&n.; end; %end; %do n=1 %to &NUM_MPN.; /*POV2*/ if indexcriteria in("IC&n.") then output _GroupWash&n.; %end; /*POV3*/ if indexcriteria in('INC','EXC') then output _InclExcl; /*Preg*/ if indexcriteria in('PCY') then output _GroupPreg; /*POV5*/ if fupcriteria in('DEF') then output _FUPEvent; /*POV6*/ if fupcriteria in('IOC') then output _FUPWash; %end; %if %eval(&type.=5) %then %do; /*POV1*/ if indexcriteria in('DEF') then output _GroupIndex; /*POV4*/ if indexcriteria in('FUT') then output _GroupWashForTrunk; /*POV3*/ if indexcriteria in('INC','EXC') then output _InclExcl; %end; %if %eval(&type. eq 6) %then %do; /*POV1*/ if indexcriteria in('DEF') then output _GroupIndex _GroupIndex2; /*POV3*/ if indexcriteria in('INC','EXC') then output _InclExcl; %end; run; proc datasets library= work nowarn nolist; delete _ITDrugs _ITMeds _ITLabs _ITDates _ITEnc _ITDth; quit; /*---------------------------------------------------*/ /* 09.g -- POV1: Find All potential index dates */ /*---------------------------------------------------*/ *Leave CohortId blank for primary cohort; %ms_createpov1(CohortId=); %IF %EVAL(&type.=4) %THEN %DO; %ms_createpov1t4(CohortId=); %do n=1 %to &NUM_MPN.; %ms_createpov1(CohortId=&n.); %end; %END; /*---------------------------------------------------*/ /* 09.h -- POV2: identify all Type 4 MOI index */ /* dates that are free of POV2 records */ /* in washper. For all other types, this */ /* is assesed with POV3 */ /*---------------------------------------------------*/ %IF %EVAL(&type.=4) %THEN %DO; %do n=1 %to &NUM_MPN.; %ms_createpov2(CohortId=&n.); %end; %END; /*---------------------------------------------------*/ /* 09.i -- POV3: identify all index dates meeting */ /* inclusion Exclusion */ /*---------------------------------------------------*/ *POV3 will be evaluated for prevalent Type 6 episodes in %ms_createt6episodes; %if %eval(&type. ne 6) %then %do; %ms_createpov3(CohortId=); %end; /*---------------------------------------------------*/ /* 09.j -- POV4: Create At-Risk Episodes */ /*---------------------------------------------------*/ *Leave CohortId blank for primary cohort; %IF %EVAL(&type. ne 4) %THEN %DO; %ms_createpov4(CohortId=); %END; %ELSE %DO; %do n=1 %to &NUM_MPN.; %ms_createpov4(CohortId=&n.); %end; %END; /******************************************/ /* For Type 6 - select prevalent episodes */ /******************************************/ %if %eval(&type=6) %then %do; /*POV1*/ %ms_createpov1(CohortId=2); proc datasets nowarn noprint lib=work; delete _agegroups; change _AgeGroups2 = _AgeGroups; quit; /*POV3*/ %ms_createpov3(cohortID=2); /*POV4*/ %ms_createpov4(CohortId=2); %end; /*---------------------------------------------------*/ /* 09.k -- Create Final Record wrt index date */ /*---------------------------------------------------*/ %ms_createptsmasterlist(); /*******************************************************************/ /* For Type 2 when autoprev = Y - select incident episodes */ /*******************************************************************/ %if %eval(&type=2) and %str("&autoprev.") = %str("Y") %then %do; %ms_findgap(InFile=_groupindex, OutFile=_pov12, gap=&Washper2.); *Add looking period related variables to POV1 for attrition; proc sql noprint undo_policy=none; create table _POV12 as select dat.*, look.lookstartdt as IndexLookStartDt, look.LookEnddt as IndexLookEndDt, Look.Look as IndexLook from _POV12 as dat, looks as look where look.LookStartdt<=dat.Adate<=look.LookEnddt order by Patid,Adate; quit; data _POV12(drop=AgeGroup); merge _POV12(in=a) _agegroups(keep=PatId indexdt AgeGroup rename=indexdt=adate); by patid adate; if a and strip(AgeGroup) ne ""; run; /* Apply previnc variable to ptsmasterlist */ data _PtsMasterList; merge _PtsMasterList (in = mstr) _pov12 (in = pov12 keep = patid adate rename = (adate=indexdt)); by patid indexdt; length previnc $4.; if pov12 then previnc = "Inc"; else previnc = "Prev"; if mstr then output; run; %end; /**********/ /* EVENTS */ /**********/ %ms_createpov56(); /********************************************************************/ /* For Type 5 - select index episode and create subsequent episodes */ /********************************************************************/ %if %eval(&type=5) %then %do; %ms_createt5episodes(); %end; /*---------------------------------------------------*/ /* 09.l -- Finalize Episode List */ /*---------------------------------------------------*/ %ms_finalizeptsmasterlist(); %if %eval(&type=4) %then %do; * Create the control group (match treated patients); %ms_createnopreggroup(); * Retain MOI episodes/codes during pregnancy/control episode; %ms_finalizemoiepisodes(); %end; /*---------------------------------------------------*/ /* 09.m -- Calculate additional metrics */ /*---------------------------------------------------*/ %if %eval(&type < 3) %then %do; *Compute Denominators; /* %ms_cidadenom();*/ /*PLUS: not requested*/ %end; %if %eval(&type = 2) %then %do; *Compute never exposed Cohort; %ms_nvrexposed(); %end; %if %eval(&type = 4) %then %do; *Compute MOI stats; %ms_moimetrics(cohortfile=_PtsMasterList, outfile=mstr_preg); %if "&t4_nopreggroup." = "Y" %then %do; %ms_moimetrics(cohortfile=_ControlGroup, outfile=mstr_nopreg); %end; %end; *Run surveillance if required and applicable; %if ("&SURVEILLANCEMODE."="f" or "&SURVEILLANCEMODE."="p") and %eval(&type. = 2) %then %do; %if ("&SURVEILLANCEMODE."="f") %then %do; data _PtsMasterList; set _PtsMasterList; format EndFollowUpType $20.; length LastLookFollowedDt 4; if LastLookFollowed=0 then do; *apply only to eligible patients; if min(Feventdt,EpisodeEndDt) < &enddate. then do; LastLookFollowedDt = &enddate.; LastLookFollowed = &PERIODIDSTART.; EndFollowUpType="EpisodeEndBFEnddate"; end; else if Feventdt = &enddate. then do; LastLookFollowedDt = &enddate.; LastLookFollowed = &PERIODIDSTART.; EndFollowUpType="EventOnEnddate"; end; end; run; %end; * Prior data existence for Surveillance; %ISDATA(dataset=DPLPRIOR.&RUNID._mstr); %IF %EVAL(&NOBS.>0) and %EVAL(&PERIODIDSTART. > 1) %THEN %DO; %ms_surveillance(); %END; %end; *Type 6; %if %eval(&type=6) %then %do; /*Calculate dates for [runid]_T6_ProductDates*/ /*1. ProductApprovalDate, ProductMarketingDate, Otherproductdate*/ data _ITGROUPPARAM_Combined; set _itgroupparammeds(keep=productmarketingdate productapprovaldate Otherproductdate) _itgroupparamndc(keep=productmarketingdate productapprovaldate Otherproductdate) _itgroupparamlabs(keep=productmarketingdate productapprovaldate Otherproductdate); run; proc sql noprint; create table _productdates1 as select min(productmarketingdate) as productmarketingdate format=date9. , min(productapprovaldate) as productapprovaldate format=date9. , min(Otherproductdate) as Otherproductdate format=date9., "&ITGROUP." as group format=$40. from _ITGROUPPARAM_Combined; quit; /*2. ComputedStartMarketingDate*/ %isdata(dataset=_PtsMasterList); %if %eval(&NOBS.>=1) %then %do; proc sql noprint; create table _productdates2 as select min(indexdt) as computedstartmarketingdate format=date9., "&ITGROUP." as group format=$40. from _PtsMasterList; quit; %end; %else %do; data _productdates2; format group $40. computedstartmarketingdate date9.; computedstartmarketingdate = .; group = "&ITGROUP."; run; %end; data _productdates_group; format group $40.; merge _productdates1 _productdates2; by group; run; /*Store to MSOC*/ %IF %EVAL(&group.=1) %THEN %DO; data MSOC.&RUNID._T6_productsdates; set _productdates_group; run; %end; %else %do; data MSOC.&RUNID._T6_productsdates; set MSOC.&RUNID._T6_productsdates _productdates_group; run; %end; proc sort data=_PtsMasterList; by group; run; /*Add computedstartmarketingdate to _PtsMasterList*/ data _PtsMasterList; merge _PtsMasterList (in=a) _productdates_group (keep=group computedstartmarketingdate); by group; if a; run; /*Calculate total time on treatment*/ proc sort data=_PtsMasterList; by patid; run; proc means data=_PtsMasterList noprint nway; var episodelength; class patid; output out=_totalepisodelength(drop=_:) sum=CumEpisodeLength; where incexl = 1; run; /*Update [runid]_mstr with total time on treatment*/ data _PtsMasterList; merge _PtsMasterList _totalepisodelength; by patid; run; %end; *Codes that define exposure and hoi; %if "&DISTINDEX." = "y" %then %do; %ms_codedistribution(); %end; /*PLUS: merge in urbanicity and SES variables*/ proc sql noprint; create table _zip as select pts.*, lkup.statecode, lkup.cb_region, lkup.med_house_inc, lkup.med_prop_val, lkup.perc_unempl, lkup.house_inc_known, lkup.prop_val_known, lkup.perc_unempl_known, lkup.all_ses_known, lkup.urban_cat from _PtsMasterList as pts left join infolder.&zipfile. as lkup on pts.zip = lkup.zip; quit; data _PtsMasterList(drop=statecode cb_region); length cb_reg $7 urban_cat $30; set _zip; if missing(zip) then do; cb_reg = 'Missing'; urban_cat = 'Unknown'; house_inc_known = 0; prop_val_known = 0; perc_unempl_known = 0; all_ses_known = 0; med_house_inc = .; med_prop_val = .; perc_unempl = .; end; else if missing(statecode) then do; cb_reg = 'Invalid'; urban_cat = 'Unknown'; house_inc_known = 0; prop_val_known = 0; perc_unempl_known = 0; all_ses_known = 0; med_house_inc = .; med_prop_val = .; perc_unempl = .; end; else do; cb_reg = cb_region; if urban_cat not in ('Rural', 'Urban', 'Suburban') then urban_cat = 'Unknown'; if statecode ne '' and missing(cb_reg) then do; cb_reg = 'Other'; end; end; /*PLUS: add known race*/ if race in ('1','2','3','4','5') then known_race='1'; else known_race = '0'; run; /***************************************************/ /** ALL Types - Store patient episodes to DPLocal **/ /***************************************************/ %IF %EVAL(&group.=1) %THEN %DO; %if %eval(&type ne 4) %then %do; data DPLocal.&RUNID._mstr; set _PtsMasterList; run; %end; %if %eval(&type eq 4) %then %do; data DPLocal.&RUNID._mstr_preg; set _PtsMasterList; run; data DPLocal.&RUNID._sec; set _PtsMasterList2; run; %if "&t4_nopreggroup." = "Y" %then %do; data DPLocal.&RUNID._mstr_nopreg; set _ControlGroup; run; %end; data DPLocal.&RUNID._prePostCodes; set _prePostCodes; run; data DPLocal.&RUNID._allDeliveries; set _Deliveries; run; %end; %if %eval(&type.=5 | &type.=6) %then %do; data DPLocal.&RUNID._dispensings; set _dispensings; run; %end; %END; %ELSE %DO; /*Because of surveillance mode and the carried forward variables from look <&PERIODIDSTART. that have not been calculated yet for the (&PERIODIDSTART.<=look<=&PERIODIDEND.)) - we will use a set method rather than append*/ %if %eval(&type ne 4) %then %do; data DPLocal.&RUNID._mstr; set DPLocal.&RUNID._mstr _PtsMasterList; run; %end; %if %eval(&type eq 4) %then %do; proc append base=DPLocal.&RUNID._mstr_preg data=_PtsMasterList force; run; proc append base=DPLocal.&RUNID._sec data=_PtsMasterList2 force; run; %if "&t4_nopreggroup." = "Y" %then %do; proc append base=DPLocal.&RUNID._mstr_nopreg data=_ControlGroup force; %end; run; proc append base=DPLocal.&RUNID._prePostCodes data=_prePostCodes force; run; proc append base=DPLocal.&RUNID._allDeliveries data=_Deliveries force; run; %end; %if %eval(&type.=5 | &type.=6) %then %do; proc append base=DPLocal.&RUNID._dispensings data=_dispensings force; run; %end; %END; %if &censor_dth.=1 %then %do; *If censoring is used, truncate enrollment at death date (for denominators/attrition); data worktemp.enr_group&GROUP.; set worktemp.enr_&enrollmentnum.; if enrend_death in ('B', 'C') and DeathDt <= Enr_End then do; Enr_End=DeathDt; end; if Enr_end < Enr_Start then delete; run; data _groupindex; set _groupindex; if enrend_death in ('B', 'C') and . < DeathDt < adate then delete; run; %end; *Compute Attrition for this group; %if %eval(&type=2) and %str("&autoprev.") = %str("Y") %then %do; %ms_attrition (ds_suffix =, where_clause =%str((where=(PrevInc = "Inc"))), cohortid=2); %ms_attrition (ds_suffix =_prev, where_clause =%str((where=(group in ("&prevgroups.") and previnc_def in ("Both","Prev")))), cohortid=); %end; %else %do; %ms_attrition; %end; proc datasets nowarn noprint lib=worktemp; delete enr_group&group. %if &group. = &ngroup. %then %do; _keep %end;; quit; * Reset loop macro variables; %let EXCL=; %let INCL=; %let CHARTRES=; * Save _GroupIndex for later processing; %if %eval(&concomitant.=1) %then %do; data gi&itgroup.; set _groupindex; run; %end; proc datasets nowarn noprint lib=work; delete _pov: _uniquepts: _age: _control: _deliveries _demo: _groupindex: _it: _next: _ptsmasterlist: _groupwash: _t&type.priorlooks _EventsInBlackout _InclExcl _FUPEvent _FUPWash _GroupPreg _fut: _temp _tmp _zip; quit; /*Output loop runtime*/ %ms_stoptimer(timestart=loopruntime); %ms_outputruntimes(timevar=loopruntime, step=%str(CIDA Loop), group=&itgroup., monitoringperiod=); %put LAST GROUP RAN WAS &ITGROUP. &group.; %PUT &ITGROUP. processing ended on %sysfunc(date(),date9.) %sysfunc(time(),tod8.); /*Checkpoint*/ %ms_checkpoint(macrocalled=ms_scenarioloop); %end; /*group loop*/ %mend ms_scenarioloop; %ms_scenarioloop; /*recreate worktemp.meds and clear medstemp folder*/ %if %eval(&nummeds_partitions.>1) %then %do; data wrktemp2.meds; set medstemp.meds:; run; proc copy in=wrktemp2 out=worktemp memtype=data; select meds; run; proc datasets nowarn noprint lib=medstemp kill; quit; %end; %postgrouploop: /* Assign patid length if it does not already exist */ %if %symexist(patid_len) = 0 %then %do; %varlength (var = patid, indata = DPLocal.&RUNID._mstr&preg.); %end; proc datasets nowarn noprint lib=work; delete demogs: MultiDemogs:; quit; /* Code distribution pts vars - Determine max length of values of distindexexp/distindexhoi and apply as the length of the variable */ %if "&DISTINDEX." = "y" %then %do; %macro codedistlength(data=, hoi=); proc sql noprint; select max(length(distindexexp)) %if &hoi.=Y %then %do; , max(length(distindexhoi)) %end; into :distexplength %if &hoi.=Y %then %do; , :disthoilength %end; from dplocal.&runid._mstr&data.(keep=distindex:); quit; data dplocal.&runid._mstr&data.; set dplocal.&runid._mstr&data.(rename=(distindexexp=var1 %if &hoi.=Y %then %do; distindexhoi=var2 %end; )); length distindexexp $%sysfunc(max(1,&distexplength.)) %if &hoi.=Y %then %do; distindexhoi $%sysfunc(max(1,&disthoilength.)) %end; ; distindexexp = var1; drop var1; %if &hoi.=Y %then %do; distindexhoi = var2; drop var2; %end; run; %mend; %if %eval(&type = 4) %then %do; %codedistlength(data=_preg, hoi=N); %end; %else %if (%eval(&type.=2) | %eval(&type.=3)) & "&analysis" ne "tree" %then %do; %codedistlength(data=, hoi=Y); %end; %else %do; %codedistlength(data=, hoi=N); %end; %end; *all patients in master list; proc sort nodupkey data = DPLocal.&RUNID._mstr&preg. (keep = patid) out = _unique_&runid._mstr&preg.; by patid; run; %if %eval(&milinkage. =1) %then %do; proc sort nodupkey data = DPLocal.&RUNID._mstr&preg. (keep = linkedid) out = _unique_link_&runid._mstr&preg. (rename = (linkedid = patid)); by linkedid; run; %end; %if %eval(&type.=4) & "&t4_nopreggroup." = "Y" %then %do; proc sort nodupkey data = DPLocal.&RUNID._mstr_nopreg (keep = patid) out = _unique_&RUNID._mstr_nopreg; by patid; run; %end; data worktemp.ptsmstrall; merge _unique_&runid._mstr&preg. %if %eval(&milinkage. =1) %then %do; _unique_link_&runid._mstr&preg. %end; %if %eval(&type.=4) & "&t4_nopreggroup." = "Y" %then %do; _unique_&RUNID._mstr_nopreg %end;; by patid; run; proc datasets library=work nowarn nolist; delete _unique_&runid._mstr:; quit; %do e = 1 %to &numenrollgroup.; *Extracting enrollment data for patients in master list; %restrictclms(indata=worktemp.enr_&e., lookupdata=worktemp.ptsmstrall, outdata=worktemp.enr_&e.); *Adjust enrollment for death for later processing; %if %sysfunc(exist(infolder.&type4file.)) ne 1 %then %do; data worktemp.enr_&e.; set worktemp.enr_&e.; if enrend_death in ('B', 'C') and DeathDt <= Enr_End then do; Enr_End=DeathDt; end; if Enr_end < Enr_Start then delete; run; %end; %end; *subset medical/Rx claims to only patients in master list if they are used for following analyses; %if %eval(&milinkage. =1)| %eval(&switchincl.)=1 | &CovarCodes.=Y | %length(&Comorbfile.) | %length(&CONCFILE.) %then %do; %ISDATA(dataset=worktemp.meds); %if %eval(&NOBS.>0) %then %do; %restrictclms(indata=worktemp.meds, lookupdata=worktemp.ptsmstrall, outdata=worktemp.meds); %end; %ISDATA(dataset=worktemp.drugs); %if %eval(&NOBS.>0) %then %do; %restrictclms(indata=worktemp.drugs, lookupdata=worktemp.ptsmstrall, outdata=worktemp.drugs); %end; %ISDATA(dataset=worktemp.drugscomb); %if %eval(&NOBS.>0) %then %do; %restrictclms(indata=worktemp.drugscomb, lookupdata=worktemp.ptsmstrall, outdata=worktemp.drugscomb); %end; *For encounter claims; %if %str("&enctypeextractlist.") ne %str("") %then %do; %local e enc; %do e = 1 %to %sysfunc(countw(&enctypeextractlist.)); %let enc = %scan(&enctypeextractlist., &e.); %restrictclms(indata=worktemp.encextract&enc., lookupdata=worktemp.ptsmstrall, outdata=worktemp.encextract&enc.); %end; %end; %end; proc datasets library=worktemp nowarn nolist; delete PtsMstrall enr_m: enr_d:; quit; *if data-driven query period, assign calendar based macro variables for reporting; %if "&datadrivenqueryperiod" = "Y" %then %do; %ms_assigncalmacrovars(date1=&MinExpPeriodStartDt., date2=&MaxExpPeriodEndDt.); %end; /********************/ /* Switching module */ /********************/ %if %eval(&type. eq 6) %then %do; %ms_switching(); %end; /******************************/ /* Secondary Episode Analysis */ /* -Multiple Events */ /* -Overlap */ /* -Concomitant Use Episodes */ /******************************/ %if %eval(&multievent.=1 | &overlap.=1) %then %do; %ms_evalsecondaryepi(); %if %eval(&type.=2) %then %do; %ms_evalsecondarytables (ds_suffix =, where_clause = %str(and PrevInc = "Inc")); %if %index(&tables.,t2multeventprev) >0 or %index(&tables.,t2overlapprev)> 0 or %index(&tables.,t2epigapprev)> 0 %then %do; %ms_evalsecondarytables (ds_suffix =_prev, where_clause =%str(and previnc_def in ("Both","Prev"))); %end; %end; %else %do; %ms_evalsecondarytables; %end; %end; %if %eval(&concomitant.=1) %then %do; %ms_concomitantuse(); %end; /************************/ /* Mother-Infant module */ /************************/ %if %eval(&milinkage. =1) %then %do; %ms_createmicohorts(); %end; /********************************************************************************************************/ /* Freeze Patients Data - Will save A/Y patients now. Matched patients saved after covariate_adjustment */ /********************************************************************************************************/ %macro saveptstofreezedata(data=, wherekeep=); %ms_starttimer(timestart=freezeruntime); %if "&t4_nopreggroup." = "N" %then %do; data _ptslist(keep=patid); set DPLocal.&RUNID.&data.&preg.(&wherekeep.); run; %end; %else %do; data _PtsList; set DPLocal.&RUNID._allDeliveries (keep=Patid) DPLocal.&RUNID._mstr_nopreg (keep=Patid); run; %end; %isdata(dataset=_PtsList); %if %eval(&nobs.>0) %then %do; %IF %STR(&ENRTABLE.) ne %STR() or %LENGTH(&ENRTABLE.) > 0. %THEN %DO;%MS_FREEZEDATA(INFILE=indata.&ENRTABLE, PATLISTINFILE=_PtsList,OUTFILE=freedir.&RUNID._enrtable);%END; %IF %STR(&DEMTABLE.) ne %STR() or %LENGTH(&DEMTABLE.) > 0. %THEN %DO;%MS_FREEZEDATA(INFILE=indata.&DEMTABLE, PATLISTINFILE=_PtsList,OUTFILE=freedir.&RUNID._demtable);%END; %IF %STR(&DISTABLE.) ne %STR() or %LENGTH(&DISTABLE.) > 0. %THEN %DO;%MS_FREEZEDATA(INFILE=indata.&DISTABLE, PATLISTINFILE=_PtsList,OUTFILE=freedir.&RUNID._distable);%END; %IF %STR(&DIATABLE.) ne %STR() or %LENGTH(&DIATABLE.) > 0. %THEN %DO;%MS_FREEZEDATA(INFILE=indata.&DIATABLE, PATLISTINFILE=_PtsList,OUTFILE=freedir.&RUNID._diatable);%END; %IF %STR(&PROCTABLE.) ne %STR() or %LENGTH(&PROCTABLE.) > 0. %THEN %DO;%MS_FREEZEDATA(INFILE=indata.&PROCTABLE,PATLISTINFILE=_PtsList,OUTFILE=freedir.&RUNID._proctable);%END; %IF %STR(&ENCTABLE.) ne %STR() or %LENGTH(&ENCTABLE.) > 0. %THEN %DO;%MS_FREEZEDATA(INFILE=indata.&ENCTABLE, PATLISTINFILE=_PtsList,OUTFILE=freedir.&RUNID._enctable);%END; %IF %STR(&LABTABLE.) ne %STR() or %LENGTH(&LABTABLE.) > 0. %THEN %DO;%MS_FREEZEDATA(INFILE=indata.&LABTABLE, PATLISTINFILE=_PtsList,OUTFILE=freedir.&RUNID._labtable);%END; %IF %STR(&VITTABLE.) ne %STR() or %LENGTH(&VITTABLE.) > 0. %THEN %DO;%MS_FREEZEDATA(INFILE=indata.&VITTABLE, PATLISTINFILE=_PtsList,OUTFILE=freedir.&RUNID._vittable);%END; %IF %STR(&DEATHTABLE.) ne %STR() or %LENGTH(&DEATHTABLE.) > 0. %THEN %DO;%MS_FREEZEDATA(INFILE=indata.&DEATHTABLE, PATLISTINFILE=_PtsList,OUTFILE=freedir.&RUNID._deathtable);%END; %IF %STR(&MILTABLE.) ne %STR() or %LENGTH(&MILTABLE.) > 0. %THEN %DO;%MS_FREEZEDATA(INFILE=indata.&MILTABLE, PATLISTINFILE=_PtsList,OUTFILE=freedir.&RUNID._miltable);%END; %IF %STR(&pretable.) ne %STR() or %LENGTH(&pretable.) > 0. %THEN %DO;%MS_FREEZEDATA(INFILE=indata.&pretable, PATLISTINFILE=_PtsList,OUTFILE=freedir.&RUNID._pretable);%END; /*Facility and provider table are lookup tables without patID - will freeze entire table*/ %IF %STR(&factable.) ne %STR() or %LENGTH(&factable.) > 0. %THEN %DO; data freedir.&RUNID._factable; set indata.&factable.; run; %end; %IF %STR(&pvdtable.) ne %STR() or %LENGTH(&pvdtable.) > 0. %THEN %DO; data freedir.&RUNID._pvdtable; set indata.&pvdtable.; run; %end; *This datalib will point to the subset of PatId data generated by Freeze data; %let datalib_enr=freedir.&runid._enrtable; %let datalib_dem=freedir.&runid._demtable; %let datalib_dis=freedir.&runid._distable; %let datalib_dia=freedir.&runid._diatable; %let datalib_proc=freedir.&runid._proctable; %let datalib_enc=freedir.&runid._enctable; %let datalib_lab=freedir.&runid._labtable; %let datalib_vit=freedir.&runid._vittable; %let datalib_death=freedir.&runid._deathtable; %let datalib_mil=freedir.&runid._miltable; %let datalib_pre=freedir.&runid._pretable; %end; /*Output freezedata runtime*/ %ms_stoptimer(timestart=freezeruntime); %ms_outputruntimes(timevar=freezeruntime, step=%str(Freeze Data), group=, monitoringperiod=); %mend saveptstofreezedata; %if %str("&FREEZEDATA.")=%str("y") | %str("&FREEZEDATA.")=%str("a") %then %do; %if %str("&FREEZEDATA.")=%str("a") %then %do; %saveptstofreezedata(data=_mstr, wherekeep=%str(keep=patid)); %end; /*if y - excluded never-exposed cohorts and any patID not identified in a secondary episode cohort */ %else %if %str("&FREEZEDATA.")=%str("y") %then %do; %if %eval(&multievent.=1) %then %do; %saveptstofreezedata(data=_mstr_multevent, wherekeep=%str(keep=patid)); %end; %else %if %eval(&overlap.=1) %then %do; %saveptstofreezedata(data=_mstr_overlap, wherekeep=%str(keep=patid)); %end; %else %if %eval(&concomitant.=1) %then %do; %saveptstofreezedata(data=_mstr_concomitance, wherekeep=%str(keep=patid)); %end; %else %do; %saveptstofreezedata(data=_mstr, wherekeep=%str(keep=patid group where=(index(lowcase(group), "_nvrexp") = 0))); %end; %end; %end; /*** Extract Covariates and Produce Baseline table ***/ *CIDA Groups: Types 1-5; %if %eval(&type. ne 6) & %eval(&multievent.=0) & %eval(&overlap.)=0 & %eval(&concomitant.=0) %then %do; %ms_CIDAcov(data=mstr&preg., outcohort=&preg., groupvar=group, groupdefdata=cohortfile, groupdefvar=cohortgrp %if %eval(&type.=4) %then %do; ,lookdt=EpisodeEndDt %end;); %end; *CIDA Groups: Type 4 control group; %if %eval(&type.=4) & "&t4_nopreggroup" = "Y" %then %do; %ms_CIDAcov(data=mstr_nopreg, outcohort=_nopreg, groupvar=group, groupdefdata=cohortfile, groupdefvar=cohortgrp, lookdt=EpisodeEndDt); %end; *Concomitant episodes; %if %eval(&concomitant.=1) %then %do; %ms_CIDAcov(data=mstr_concomitance, outcohort=_concomitance, groupvar=analysisgrp, groupdefdata=infolder.&concfile., groupdefvar=analysisgrp, cohortgrpvar=primary); %end; *Multiple event analysis; %if %eval(&multievent.=1) %then %do; %ms_CIDAcov(data=mstr_multevent, outcohort=_multevent, groupvar=analysisgrp, groupdefdata=secondaryinputfile, groupdefvar=analysisgrp, cohortgrpvar=primary); %end; *Overlap event analysis; %if %eval(&overlap.=1) %then %do; %ms_CIDAcov(data=mstr_overlap, outcohort=_overlap, groupvar=analysisgrp, groupdefdata=secondaryinputfile, groupdefvar=analysisgrp, cohortgrpvar=primary); %end; *Mother-infant analysis; %if %eval(&milinkage. =1) %then %do; %ms_CIDAcov(data=mstr_mi, outcohort=_mi, groupvar=group, groupdefdata=migroupnames, groupdefvar=cohortgrp, cohortgrpvar=groupname); %end; *Switch episode analysis; %if %eval(&type.=6) %then %do; /* loop through all potential switches */ %do switchnum = 0 %to 2; %ms_CIDAcov(data=t6_switchepisodes, outcohort=_switch_&switchnum, groupvar=analysisgrp, groupdefdata=type6groups_forbaseline, groupdefvar=analysisgrp, cohortgrpvar=primary, suffixvarnum=&switchnum); %end; /* Stack switch datasets */ %do i = &PERIODIDSTART. %to &PERIODIDEND.; /* Only stack when at least one table is requested */ %let checkbaseline=; proc sql noprint; select upcase(createbaseline) into :checkbaseline from infolder.&TREATMENTPATHWAYS where upcase(createbaseline) = 'Y'; quit; %if &checkbaseline = Y %then %do; /*Check that switcheval step 0 ADS file exists*/ %isdata(dataset=dplocal.&RUNID._ads_t6_switchepisodes_0_&i.); %if %eval(&nobs.>0) %then %do; data dplocal.&RUNID._ads_t6_switchepisodes_&i.; set %do j = 0 %to 2; %if %sysfunc(exist(dplocal.&RUNID._ads_t6_switchepisodes_&j._&i.)) %then %do; dplocal.&RUNID._ads_t6_switchepisodes_&j._&i. %end; %end; ; run; %end; data msoc.&RUNID._baseline_switch_&i; set %do j = 0 %to 2; %if %sysfunc(exist(msoc.&RUNID._baseline_switch_&j._&i.)) %then %do; msoc.&RUNID._baseline_switch_&j._&i. %end; %end; ; run; %end; proc datasets nowarn noprint lib=msoc; delete &RUNID._baseline_switch_0_&i. &RUNID._baseline_switch_1_&i. &RUNID._baseline_switch_2_&i.; quit; proc datasets nowarn noprint lib=dplocal; delete &RUNID._ads_t6_switchepisodes_0_&i. &RUNID._ads_t6_switchepisodes_1_&i. &RUNID._ads_t6_switchepisodes_2_&i.; quit; %end; %end; proc datasets library=worktemp nolist nowarn; delete encextract: type6groups_forbaseline; quit; /*****************************************/ /** Extract Claims Files (for MFU/HDPS) **/ /*****************************************/ %if %eval(&type. ne 6) & %eval(&multievent.=0 & &overlap.=0 & &concomitant.=0) %then %do; %ms_createclaimsfiles; %end; /**Conduct MFU analysis*/ %isdata(dataset=infolder.&mfufile.); %if %eval(&nobs.>0) %then %do; %ms_starttimer(timestart=mfuruntime); %ms_mfu(%if %eval(&type. = 2) %then %do; where=previnc="Inc" %end; %else %do; where=1 %end; ,t3out=); %if %eval(&type.=3) %then %do; %ms_mfu(where=analysiscohort=1, t3out=_an); %end; %ms_stoptimer(timestart=mfuruntime); %ms_outputruntimes(timevar=mfuruntime, step=%str(MFU Module), group=, monitoringperiod=); %end; /*****************************/ /* Produce Aggregate Outputs */ /*****************************/ %if %eval(&type. = 1) %then %do; %ms_cidatables; %end; %if %eval(&type.=2) %then %do; %ms_cidatables (ds_suffix =, where_clause = %str(PrevInc = "Inc"), followuptimevar=followuptime); %if %index(&tables.,t2cidaprev) >0 %then %do; %ms_cidatables (ds_suffix =_prev, where_clause =%str(previnc_def in ("Both","Prev")), followuptimevar=followuptime); %end; %end; %if %eval(&type. eq 3) %then %do; %ms_cidatablest3(); %end; %if %eval(&type. eq 4) %then %do; %ms_cidatablest4(); %end; %if %eval(&type. eq 5) %then %do; %ms_cidatablest5(); %end; %if %eval(&type. eq 6) %then %do; %ms_cidatablest6(); %end; %if %eval(&concomitant.=1) %then %do; %ms_concomitantusetables(); %end; *output censoring table; %if "&censor_output." = "Y" %then %do; %if %eval(&type.=2) %then %do; %if %sysfunc(findw(&tables., t2censor)) >0 %then %do; %ms_createcensortable(table = censor, ds_suffix =, where_clause = %str(PrevInc = "Inc"), convar = timetocensor, catvar = censdays_value_cat, dplocalflaglist = cens_elig cens_dth cens_dpend cens_qryend, msocflaglist = cens_elig cens_dth cens_dpend cens_qryend); %end; %if %sysfunc(findw(&tables., t2followuptime)) > 0 %then %do; %ms_createcensortable(table = followuptime, ds_suffix =, where_clause = %str(PrevInc = "Inc"), convar = followuptime, catvar = fupdays_value_cat, dplocalflaglist = fup_elig fup_dth fup_dpend fup_qryend fup_episend fup_spec fup_event, msocflaglist = cens_elig cens_dth cens_dpend cens_qryend cens_episend cens_spec cens_event); %end; %if %sysfunc(findw(&tables., t2censorprev)) >0 %then %do; %ms_createcensortable(table = censor, ds_suffix =_prev, where_clause = %str(previnc_def in ("Both","Prev")), convar = timetocensor, catvar = censdays_value_cat, dplocalflaglist = cens_elig cens_dth cens_dpend cens_qryend, msocflaglist = cens_elig cens_dth cens_dpend cens_qryend); %end; %if %sysfunc(findw(&tables., t2followuptimeprev)) >0 %then %do; %ms_createcensortable(table = followuptime, ds_suffix =_prev, where_clause = %str(previnc_def in ("Both","Prev")), convar = followuptime, catvar = fupdays_value_cat, dplocalflaglist = fup_elig fup_dth fup_dpend fup_qryend fup_episend fup_spec fup_event, msocflaglist = cens_elig cens_dth cens_dpend cens_qryend cens_episend cens_spec cens_event); %end; %end; %else %do; %ms_createcensortable(table = censor, convar = timetocensor, catvar = censdays_value_cat, dplocalflaglist = cens_elig cens_dth cens_dpend cens_qryend, msocflaglist = cens_elig cens_dth cens_dpend cens_qryend); %end; %end; *ITS analysis; %if %eval(&ITSANALYSIS.=1) %then %do; %if %eval(&type=2) %then %do; %ms_its (ds_suffix =, where_clause = %str(and PrevInc = "Inc") ,data = %if %eval(&overlap.=1) %then %do;_mstr_overlap %end; %else %do; _mstr_multevent %end;); %if %index(&tables.,t2itsprev) >0 %then %do; %ms_its (ds_suffix =_prev, where_clause = %str(and previnc_def in ("Both","Prev")) ,data = %if %eval(&overlap.=1) %then %do;_mstr_overlap %end; %else %do; _mstr_multevent %end;); %end; %end; %end; *delete undocumented vars from MSTR; data dplocal.&RUNID._mstr&preg.(drop=EndFollowUpType blackoutper); set dplocal.&RUNID._mstr&preg.; if _n_ = 1 then do; dsid = open("dplocal.&RUNID._mstr&preg."); if varnum(dsid,"EndFollowUpType") = 0 then EndFollowUpType =''; if varnum(dsid,"blackoutper") = 0 then blackoutper =.; rc= close(dsid); end; drop rc dsid; %if %eval(&type.=5) %then %do; drop FEventDt; %end; run; proc datasets library=work nowarn nolist; delete &cohortcodes. drugs drugscomb ENR_MD30 LABEXTRACT DeathExtract meds &MONITORINGFILE. &inclusioncodes. Enr_: PreMeds ElixMeds covmeds PreDrugs Monitoringfileflm Premeds Ptslist Studynames _: STOCKPILE_NONCOVAR; quit; /*plus: logistic regressions*/ %isdata(dataset=infolder.&ormodelfile.); %if %eval(&nobs.>0) %then %do; %let orcompnumber = &nobs.; ods listing close; *Initialize output table; data msoc.&runid._oddsratios; format group $40. modelnum 8. race $1. byvarvalue $30. npts numevents 8. var 8.4 or lowerci upperci oddsr8.3 pvalue pvalue6.4; call missing(group, modelnum, race, byvarvalue, npts, numevents, or, var, lowerci, upperci, pvalue); stop; run; /*Create squared race and urban_cat dataset - will square all race values, regardless of reference vaue*/ data _square_race_urban; format variable $9. ClassVal0 $1. urban_cat $30.; variable = "race"; %do v =0 %to 5; ClassVal0 = "&v."; urban_cat = 'Urban'; output; urban_cat = 'Rural'; output; urban_cat = 'Suburban'; output; urban_cat = 'Unknown'; output; %end; run; /*sort by urban_cat for by statement*/; proc sort data=dplocal.&runid._ads_mstr_1 out=&runid._ads_mstr_1; by urban_cat; run; /*Add dummy vars (for diagnostics)*/ data &runid._ads_mstr_1; set &runid._ads_mstr_1; length sex_f sex_m race_0 race_1 race_2 race_3 race_4 race_5 3; if sex="F" then sex_F=1;else sex_F=0; if sex="M" then sex_M=1;else sex_M=0; if race="0" then race_0=1; else race_0 = 0; if race="1" then race_1=1; else race_1 = 0; if race="2" then race_2=1; else race_2 = 0; if race="3" then race_3=1; else race_3 = 0; if race="4" then race_4=1; else race_4 = 0; if race="5" then race_5=1; else race_5 = 0; length pat 3; pat = 1; run; /*Number of patients and number of events*/ proc means data=&runid._ads_mstr_1 noprint; var pat event; class group race urban_cat all_ses_known; output out=totalcounts(drop=_:) sum=npts numevents; run; *loop through each model; %do comp = 1 %to %eval(&orcompnumber.); data _null_; set infolder.&ormodelfile.; if _n_ = &comp. then do; call symputx('orgroup', lowcase(strip(group))); call symputx('modelnum', modelnum); call symputx('orclass', lowcase(class)); call symputx('ornoclass', lowcase(noclass)); call symputx('racelevel', racelevel); call symputx('byvar', lowcase(byvar)); call symputx('whereclause', where); end; run; /*check at least 1 event in model*/ %let eventexists = N; data _null_; set &runid._ads_mstr_1(where=(group="&orgroup." %if %length(&whereclause.)>0 %then %do; and &whereclause. %end;)); if event = 1 then do; call symputx('eventexists', 'Y'); stop; end; run; %if &eventexists = N %then %do; %put WARNING: (Sentinel) Group &orgroup. and model &modelnum. does not have any events. Model will be skipped; %goto skiplogistic; %end; /*if byvar is specified - remove any categories that do not have events*/ %let byvarmissinglist =; %if %length(&byvar.)>0 %then %do; proc means data=&runid._ads_mstr_1(where=(group="&orgroup." %if %length(&whereclause.)>0 %then %do; and &whereclause. %end;)) nway noprint; var event; class &byvar.; output out=_tmpeventcount(drop=_:) sum=sumevent; run; proc sql noprint; select quote(strip(&byvar.),"'") into: byvarmissinglist separated by ', ' from _tmpeventcount where sumevent <=0; quit; %end; /*select dummy vars*/ %let racevars = %sysfunc(tranwrd(race_0 race_1 race_2 race_3 race_4 race_5, race_&racelevel.,%str() )); /*sex only variable needing dummy coding*/ %let orclass = %sysfunc(tranwrd(&orclass., sex, sex_f )); %if %length(&byvar.)>0 %then %do; %if &byvar. ne urban_cat %then %do; %put WARNING: (Sentinel) BYVAR can only be populated with URBAN_CAT; %end; %end; /*Must have at least 1 patient with race reference level /*if no patients with racelevel - skip logistic. if patients exist in certain BY groups, then run logistic using only those BY groups */ proc means data=&runid._ads_mstr_1(where=(group="&orgroup." %if %length(&whereclause.)>0 %then %do; and &whereclause. %end; %if %length(&byvarmissinglist.)>0 %then %do; and &byvar. not in (&byvarmissinglist.) %end; )) nway noprint; var pat; class race &byvar.; output out=_tmpracecount(drop=_:) sum=; run; %if %length(&byvar.)>0 %then %do; %let racelevelmissing = Y; proc sql noprint; select quote(strip(&byvar.),"'") into: racelevelmissing separated by ', ' from _tmpracecount where race = "&racelevel" and pat >0; quit; %put &racelevelmissing; %end; %else %do; %let racelevelmissing = Y; /*skip model*/ data _null_; set _tmpracecount; if race = "&racelevel" and pat >0 then call symputx('racelevelmissing', 'N'); run; %end; %if &racelevelmissing = Y %then %do; %goto skiplogistic; %end; title modeling group = &orgroup. and model = &modelnum.; *Run model; ods rtf file="&MSOC.&RUNID._runmodel_&orgroup._&modelnum..rtf"; ods output Association = fit; ods output ConvergenceStatus = converge; ods output Nobs = Nobs; ods output SimpleStatistics = simple; ods output IterHistory = itprint; ods output ParameterEstimates = param; ods output CLOddsWald = clodds; proc logistic data = &runid._ads_mstr_1(where=(group="&orgroup." %if %length(&whereclause.)>0 %then %do; and &whereclause. %end; %if %length(&byvarmissinglist.)>0 %then %do; and &byvar. not in (&byvarmissinglist.) %end; %if %length(&racelevelmissing.)>0 and &racelevelmissing. ne N %then %do; and &byvar. in (&racelevelmissing.) %end; )) descending simple; model event = &racevars &orclass &ornoclass / clodds=wald firth itprint; %if %length(&byvar.)>0 %then %do; by &byvar.; %end; run; ods rtf close; title; /*diagnostics*/ *remove sex b/c need to dummy code; %if %index(&orclass, sex_f)>0 %then %let orclass = &orclass sex_m; /*correlations*/ ods output PearsonCorr=corrs; proc corr data=&runid._ads_mstr_1(where=(group="&orgroup." %if %length(&whereclause.)>0 %then %do; and &whereclause. %end;)); var race_0 race_1 race_2 race_3 race_4 race_5 &orclass. &ornoclass.; run; ods output close; data corrs; set corrs; keep variable race_0 race_1 race_2 race_3 race_4 race_5 &orclass. &ornoclass.; run; proc sort data=corrs; by Variable; run; proc transpose data=corrs out=corrst; by Variable; run; data finalcorrst; length Variable _NAME_ $32 modelnum 3; format group $40.; set corrst; rename Variable=Var1 _NAME_=Var2 col1=Corr; group="&orgroup."; modelnum=1; run; proc append base=msoc.&RUNID._corr data=finalcorrst force; run; /*runreg*/ ods rtf file="&MSOC.&RUNID._runreg_&orgroup._&modelnum..rtf"; ODS GRAPHICS OFF; TITLE "OLS Regression with Group of Interest=&orgroup. and model &modelnum."; proc reg data=&runid._ads_mstr_1(where=(group="&orgroup." %if %length(&whereclause.)>0 %then %do; and &whereclause. %end;)); model event = &racevars. &orclass. &ornoclass. /COLLINOINT VIF; %if %length(&byvar.)>0 %then %do; by &byvar.; %end; quit; TITLE; ODS GRAPHICS ON; ods rtf close; /*skipped model if no events or no patients with reference race level*/ %skiplogistic: *Defensive incase output datasets are not produced / model skipped *Write Sentinel Note if model run and datasets not created; %isdata(dataset=param); %if %eval(&nobs.<1) %then %do; %if &eventexists = Y | &racelevelmissing = Y %then %do; %put NOTE: (Sentinel) ParameterEstimates not produced for group &orgroup. and model &modelnum.; %end; data param; format variable $9. ClassVal0 $1. StdErr 8.4 ProbChiSq PVALUE6.4 urban_cat $30.; call missing(variable,ClassVal0, StdErr, ProbChiSq, urban_cat); stop; run; %end; %if %sysfunc(exist(clodds))=0 %then %do; %if &eventexists = Y %then %do; %put NOTE: (Sentinel) CLOddsWald not produced for group &orgroup. and model &modelnum.; %end; data clodds; format variable $9. ClassVal0 effect $1. OddsRatioEst lowercl uppercl oddsr8.3 urban_cat $30.; call missing(variable,ClassVal0, effect, OddsRatioEst, lowercl, uppercl, urban_cat); stop; run; %end; %else %do; /*extract effect value*/ data clodds; set clodds; length ClassVal0 $1; ClassVal0 = substr(effect,6,1); variable = substr(effect,1,4); run; %end; *Merge to create output dataset; proc sql; create table _or as select distinct "&orgroup." as group format=$40. length=40, &modelnum. as modelnum, a.ClassVal0 as race, %if %length(&byvar.)>0 %then %do; a.&byvar. as byvarvalue format=$30. length=30, %end; %else %do; '' as byvarvalue format=$30. length=30, %end; x.OddsRatioEst as or, y.StdErr**2 as var format=8.4, x.lowercl as lowerci, x.uppercl as upperci, y.ProbChiSq as pvalue, case when z.npts = . then 0 else z.npts end as npts, case when z.numevents = . then 0 else z.numevents end as numevents from _square_race_urban as a left join param(where=(lowcase(substr(variable,1,4)) = 'race')) as y on a.ClassVal0 = substr(y.variable,6,1) %if %length(&byvar.)>0 %then %do; and a.&byvar. = y.&byvar. %end; left join clodds(where=(lowcase(variable) = 'race')) as x on substr(y.variable,6,1) = x.ClassVal0 %if %length(&byvar.)>0 %then %do; and x.&byvar. = y.&byvar. %end; left join totalcounts(where=(group="&orgroup." %if %length(&whereclause)>0 %then %do; and all_ses_known = 1 %end; %else %do; and missing(all_ses_known)=1 %end; %if %length(&byvar)=0 %then %do; and missing(urban_cat) = 1 %end;)) as z on a.ClassVal0 = z.race %if %length(&byvar.)>0 %then %do; and a.&byvar. = z.&byvar. %end; ; quit; proc append base=msoc.&runid._oddsratios data=_or force; run; proc datasets nowarn noprint lib=work; delete param clodds _or fit converge nobs simple itprint finalcorrst corrs:; quit; %end; proc datasets nowarn noprint lib=work; delete totalcounts &runid._ads_mstr; quit; ods listing; %end; /************************************************/ /* Propensity Score/Covariate adjusted analysis */ /************************************************/ %if "&run_ps_cov_analysis." = "Y" %then %do; proc printto log="&MSOC.&RUNID._covariateadjustment.log" new; run; %if %eval(&type.=2) %then %do; %ms_covariateadjustment(indata=dplocal.&runid._ads_mstr); %end; %if %eval(&type.=4) %then %do; %ms_covariateadjustment(indata=dplocal.&runid._ads_mstr_mi); %end; proc printto log="&MSOC.&RUNID._cida.log"; run; %end; proc datasets library=worktemp nowarn nolist; delete _: drugs lab: mil: death: meds: drug: denom: enr_: enc:; quit; /****************************/ /* Freeze Patients Data - M */ /****************************/ %macro wrapper(); %if %str("&FREEZEDATA.")=%str("m") %then %do; %ms_starttimer(timestart=freezeruntime); data _PtsList(keep=patid); set %do look=%eval(&periodidstart.) %to %eval(&periodidend.); dplocal.&runid._adjusted_&look.(keep=patid matchid) %end; ; where missing(matchid)=0; run; %if %eval(&type.=4) %then %do; data _PtsList2(rename=linkedid=patid); set %do look=%eval(&periodidstart.) %to %eval(&periodidend.); dplocal.&runid._adjusted_&look.(keep=linkedid matchid); %end; ; where missing(matchid) and missing(linkedid)=0; keep linkedid; run; data _ptslist; set _PtsList _PtsList2; run; %end; %isdata(dataset=_PtsList); %if %eval(&nobs.>0) %then %do; %IF %STR(&ENRTABLE.) ne %STR() or %LENGTH(&ENRTABLE.) > 0. %THEN %DO;%MS_FREEZEDATA(INFILE=indata.&ENRTABLE, PATLISTINFILE=_PtsList,OUTFILE=freedir.&RUNID._enrtable);%END; %IF %STR(&DEMTABLE.) ne %STR() or %LENGTH(&DEMTABLE.) > 0. %THEN %DO;%MS_FREEZEDATA(INFILE=indata.&DEMTABLE, PATLISTINFILE=_PtsList,OUTFILE=freedir.&RUNID._demtable);%END; %IF %STR(&DISTABLE.) ne %STR() or %LENGTH(&DISTABLE.) > 0. %THEN %DO;%MS_FREEZEDATA(INFILE=indata.&DISTABLE, PATLISTINFILE=_PtsList,OUTFILE=freedir.&RUNID._distable);%END; %IF %STR(&DIATABLE.) ne %STR() or %LENGTH(&DIATABLE.) > 0. %THEN %DO;%MS_FREEZEDATA(INFILE=indata.&DIATABLE, PATLISTINFILE=_PtsList,OUTFILE=freedir.&RUNID._diatable);%END; %IF %STR(&PROCTABLE.) ne %STR() or %LENGTH(&PROCTABLE.) > 0. %THEN %DO;%MS_FREEZEDATA(INFILE=indata.&PROCTABLE,PATLISTINFILE=_PtsList,OUTFILE=freedir.&RUNID._proctable);%END; %IF %STR(&ENCTABLE.) ne %STR() or %LENGTH(&ENCTABLE.) > 0. %THEN %DO;%MS_FREEZEDATA(INFILE=indata.&ENCTABLE, PATLISTINFILE=_PtsList,OUTFILE=freedir.&RUNID._enctable);%END; %IF %STR(&LABTABLE.) ne %STR() or %LENGTH(&LABTABLE.) > 0. %THEN %DO;%MS_FREEZEDATA(INFILE=indata.&LABTABLE, PATLISTINFILE=_PtsList,OUTFILE=freedir.&RUNID._labtable);%END; %IF %STR(&VITTABLE.) ne %STR() or %LENGTH(&VITTABLE.) > 0. %THEN %DO;%MS_FREEZEDATA(INFILE=indata.&VITTABLE, PATLISTINFILE=_PtsList,OUTFILE=freedir.&RUNID._vittable);%END; %IF %STR(&DEATHTABLE.) ne %STR() or %LENGTH(&DEATHTABLE.) > 0. %THEN %DO;%MS_FREEZEDATA(INFILE=indata.&DEATHTABLE, PATLISTINFILE=_PtsList,OUTFILE=freedir.&RUNID._deathtable);%END; %IF %STR(&MILTABLE.) ne %STR() or %LENGTH(&MILTABLE.) > 0. %THEN %DO;%MS_FREEZEDATA(INFILE=indata.&MILTABLE, PATLISTINFILE=_PtsList,OUTFILE=freedir.&RUNID._miltable);%END; %IF %STR(&pretable.) ne %STR() or %LENGTH(&pretable.) > 0. %THEN %DO;%MS_FREEZEDATA(INFILE=indata.&pretable, PATLISTINFILE=_PtsList,OUTFILE=freedir.&RUNID._pretable);%END; /*Facility and provider table are lookup tables without patID - will freeze entire table*/ %IF %STR(&factable.) ne %STR() or %LENGTH(&factable.) > 0. %THEN %DO; data freedir.&RUNID._factable; set indata.&factable.; run; %end; %IF %STR(&pvdtable.) ne %STR() or %LENGTH(&pvdtable.) > 0. %THEN %DO; data freedir.&RUNID._pvdtable; set indata.&pvdtable.; run; %end; *This datalib will point to the subset of PatId data generated by Freeze data; %let datalib_enr=freedir.&runid._enrtable; %let datalib_dem=freedir.&runid._demtable; %let datalib_dis=freedir.&runid._distable; %let datalib_dia=freedir.&runid._diatable; %let datalib_proc=freedir.&runid._proctable; %let datalib_enc=freedir.&runid._enctable; %let datalib_lab=freedir.&runid._labtable; %let datalib_vit=freedir.&runid._vittable; %let datalib_death=freedir.&runid._deathtable; %let datalib_mil=freedir.&runid._miltable; %let datalib_pre=freedir.&runid._pretable; %end; /*Output freezedata runtime*/ %ms_stoptimer(timestart=freezeruntime); %ms_outputruntimes(timevar=freezeruntime, step=%str(Freeze Data), group=, monitoringperiod=); %end; %mend wrapper; %wrapper(); /*******************/ /* Tree extraction */ /*******************/ %if "&analysis" = "tree" %then %do; %if %eval(&type.=2) | %eval(&type.=4) %then %do; %isdata(dataset=dplocal.&runid._adjusted_&periodidstart.); %if %eval(&nobs.>0) %then %do; %ms_treeextraction(data=dplocal.&runid._adjusted_&periodidstart.(where=(missing(matchid)=0 and missing(subgroup))), grp=analysisgrp); %end; %end; %if %eval(&type.=3) %then %do; %isdata(dataset=dplocal.&runid._mstr); %if %eval(&nobs.>0) %then %do; %ms_treeextraction(data=dplocal.&runid._mstr, grp=group); %end; %end; %end; * Reset global macro variables; %let COMBORUN=; *Create the number of groups to create cohorts (into NOBS); %ISDATA(dataset=infolder.&COHORTFILE.); /*Output QRP runtime*/ %ms_stoptimer(timestart=qrpruntime); data msoc.&runid._runtimes; set msoc.&runid._runtimes; if step = 'QRP Runtime' then do; format start stop datetime21.2; start=input("&qrpruntime.",best.); stop=input("&STOP.",best.); format Seconds $20.; Seconds=put(int(&stop.-&qrpruntime.),best.)||" s"; enddate = "&qrpruntimeenddate."; endtime = "&qrpruntimeendtime."; runtime = strip("&hours. h &minutes. m &seconds. s"); drop start stop seconds; end; run; *Signature file; data signature; /*Request meta data*/ ReqID="&REQID."; ProjID="&PROJID."; WPType="&WPTYPE."; WPID="&WPID."; DPID="&DPID."; VerID="&VERID."; RunID="&RUNID."; MPVer="&QRPVer."; CustomCodeVersion="&CustomCodeVer."; format StartTime StopTime datetime21.2; StartTime=input("&qrpruntime.",best.); StopTime=input("&STOP.",best.); format Seconds $20.; Seconds=put(int(&stop.-&qrpruntime.),best.)||" s"; ExecutionTime="&hours. h &minutes. m &seconds. s"; /*Data Partner meta data*/ DP="&DP."; format DPMINDATE DPMAXDATE date9.; DPMINDATE=&DP_MinDate.; DPMAXDATE=&DP_MaxDate.; PATIDEXCL="&PATIDEXCL."; ETLNUMBER="&ETL."; BYPASSCC="&ccbypass."; SCDMVERSION="&scdmver."; RUNTYPE="&SYSENV."; SASVERSION="&SYSVER."; SASVERSIONLONG="&SYSVLONG."; OSABBR="&SYSSCP."; OSNAME="&SYSSCPL."; NCPU="&SYSNCPU."; /*Run Parameters*/ ScenarioCnt=strip("&NOBS."); PERIODIDSTART="&PERIODIDSTART."; PERIODIDEND="&PERIODIDEND."; ANALYSIS="&ANALYSIS."; MONITORINGFILE="&MONITORINGFILE."; USERSTRATA="&USERSTRATA"; COMBOFILE="&COMBOFILE."; COHORTFILE="&COHORTFILE."; COHORTCODES="&COHORTCODES."; INCLUSIONCODES="&INCLUSIONCODES."; STOCKPILINGFILE="&STOCKPILINGFILE."; RUN_ENVELOPE = "&RUN_ENVELOPE."; FREEZEDATA="&FREEZEDATA."; ZIPFILE="&ZIPFILE."; LABSCODEMAP="&LABSCODEMAP."; DISTINDEX = "&DISTINDEX."; TYPE1FILE="&TYPE1FILE."; TYPE2FILE="&TYPE2FILE."; TYPE3FILE="&TYPE3FILE."; TYPE4FILE="&TYPE4FILE."; MODPREGDUR="&MODPREGDUR."; TYPE5FILE="&TYPE5FILE."; TYPE6FILE="&TYPE6FILE."; METADATAFILE="&METADATAFILE."; SURVEILLANCEMODE = "&SURVEILLANCEMODE"; COVARIATECODES="&COVARIATECODES."; UTILFILE="&UTILFILE."; COMORBFILE="&COMORBFILE."; DRUGCLASSFILE="&DRUGCLASSFILE."; PROFILE = "&PROFILE."; MFUFILE="&MFUFILE."; MULTEVENTFILE="&MULTEVENTFILE."; MULTEVENTFILE_ADHERE="&MULTEVENTFILE_ADHERE."; CONCFILE="&CONCFILE."; OVERLAPFILE="&OVERLAPFILE."; OVERLAPFILE_ADHERE="&OVERLAPFILE_ADHERE."; ITSFILE="&ITSFILE."; TREATMENTPATHWAYS="&TREATMENTPATHWAYS."; MICOHORTFILE="&MICOHORTFILE."; TREEFILE="&TREEFILE."; TREELOOKUP="&TREELOOKUP."; ICD10ICD9MAP="&ICD10ICD9MAP."; /*Matching parameters*/ PSESTIMATIONFILE="&PSESTIMATIONFILE."; PSMATCHFILE = "&PSMATCHFILE."; STRATIFICATIONFILE = "&STRATIFICATIONFILE."; COVSTRATFILE = "&COVSTRATFILE."; IPTWFILE = "&IPTWFILE."; PSCSSUBGROUPFILE = "&PSCSSUBGROUPFILE."; %if "&runhdps" = "Y" %then %do; HDVARSEL_INPUT="&HDVARSEL_INPUT."; %end; %else %do; HDVARSEL_INPUT=""; %end; INDLEVEL="&INDLEVEL."; DIAGNOSTICS="&DIAGNOSTICS."; output; run; proc transpose data=signature out=msoc.&runid._signature(rename=_NAME_=Var rename=COL1=VALUE); var _ALL_; run; data msoc.&RUNID._signature; set msoc.&RUNID._signature; value = strip(value); run; /*save SCDM specific meta data to separate signature file in FREEZEDATA directory*/ %if %str("&FREEZEDATA.")=%str("y") | %str("&FREEZEDATA.")=%str("a") | %str("&FREEZEDATA.")=%str("m") %then %do; data freedir.&RUNID._signature_freezedata; set msoc.&RUNID._signature; where upcase(var) in ('DPMINDATE', 'DPMAXDATE', 'ETLNUMBER', 'BYPASSCC', 'SCDMVERSION'); run; %end; %put NOTE: ********END OF MACRO: ms_cidanum ********; %mend ms_cidanum;