/* Direct Access Merge Method                                    */

%macro damerge(src_ds   =,    /* NAME OF SOURCE DATASET (E.G. LAB)  */
               mrg_ds   =,    /* NAME OF TARGET DATASET (E.G.       */
                              /* DRUG)                              */
               wrk_ds   =,    /* NAME OF TEMPORARY DATASET (E.G.    */
                              /* TEMP)                              */
               criteria =,    /* SELECTION CRITERIA AS A FULL       */
                              /* IF .. THEN STATEMENT (E.G. IF      */
                              /* LABDATE GE START AND LABDATE LE    */
                              /* STOP THEN)                         */
               src_sort =,    /* SORT ORDER OF SOURCE DATASET       */
                              /* (E.G. PATID LABDATE)               */
               com_sort =,    /* SORT ORDER OF VARIABLE COMMON TO   */
                              /* BOTH (E.G. PATID)                  */
               breakby  =);   /* BREAK VARIABLE IN THE SORT ORDER   */
                              /* (E.G. PATID)                       */


      /* SORT EACH DATA SET BY THE APPROPRIATE KEY VARIABLES.       */
   proc sort data=&src_ds;
      by &src_sort;
   proc sort data=&mrg_ds;
      by &com_sort;

      /* DETERMINE THE FIRST AND LAST POINTER IN THE TARGET DATA    */
      /* SET FOR EACH KEY BREAK GROUP.                              */
   data &wrk_ds (keep=&com_sort tempibeg tempiend);
      set &mrg_ds;
      by &com_sort;
      retain tempibeg 1 tempiend 0;
      tempiend=tempiend+1;
      if last.&breakby then do;
         output;
         tempibeg=tempiend+1;
      end;

      /* MERGE THOSE POINTERS INTO THE SOURCE DATA SET.             */
   data &src_ds;
      merge &src_ds (in=a) &wrk_ds;
      by &com_sort;
      if a then output;

      /* CREATE A DATA SET WITH 1 OBSERVATION WHOSE VARIABLES ARE   */
      /* THOSE IN THE MRG_DS BUT WHOSE VALUES ARE MISSING. THIS IS  */
      /* NEEDED TO FORCE THE ADDED VARIABLES TO BE MISSING WHEN NO  */
      /* MATCHES ARE FOUND. IF THIS STEP IS NOT TAKEN, THEN THE     */
      /* ADDED VARIABLES WOULD HAVE THE LAST READ VALUES IN MRG_DS, */
      /* WHICH WOULD BE MEANINGLESS AND POTENTIALLY PROBLEMATIC     */
      /* TO THE CALLING PROGRAM.                                    */
   data &wrk_ds;
      if _n_ eq 1 then output;
      tempi=1;
      set &mrg_ds(drop=&com_sort) point=tempi;
      stop;

      /* PROCESS THE SOURCE DATA SET BY EXAMINING EACH RECORD IN    */
      /* THE TARGET DATA SET THAT APPLIES TO THE CURRENT RECORD IN  */
      /* THE SOURCE DATA SET. OUTPUT THOSE THAT MATCH THE DESIRED   */
      /* CRITERIA.                                                  */
   data &src_ds(drop=tempi tempibeg tempiend tempmat);
      set &src_ds;
      tempmat=0;
      if tempibeg ne . then do;
         do tempi=tempibeg to tempiend;
            set &mrg_ds point=tempi;
            &criteria
            do;
               tempmat=1;
               output;
            end;
         end;                                                        
      end;
      if tempmat eq 0 then do;
         tempi=1;
         set &wrk_ds point=tempi;
         output;
      end;
%mend damerge;