/*-------------------------------------------------------------------------------------*\
|  PROGRAM NAME:                                                                        |
|     scdm_data_qa_review-labs.sas                                                      |
|                                                                                       |
|---------------------------------------------------------------------------------------|
|  PURPOSE:                                                                             |
|     The purpose of this program is to perform general Laboratory Result table data    |
|     checks and gather information on data characteristics by resulted lab test.       |
|---------------------------------------------------------------------------------------|
|  PROGRAM INPUT:                                                                       |
|     see 00.0_scdm_data_qa_review_master_file.sas                                      |
|                                                                                       |
|  PROGRAM OUTPUT:                                                                      |
|     see Workplan PDF                                                                  |
|---------------------------------------------------------------------------------------|
|  CONTACT:                                                                             |
|     Sentinel Coordinating Center                                                      |
|     info@sentinelsystem.org                                                           |
\*-------------------------------------------------------------------------------------*/

*-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-;
*  PLEASE DO NOT EDIT BELOW WITHOUT CONTACTING THE SENTINEL OPERATIONS CENTER           ;
*-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-;

/**********************************************************************************/
/* Define hierachy for Laboratory Result Table date selection                     */
/*   Default order of preference: 1-lab_dt 2-result_dt 3-order_dt                 */
/**********************************************************************************/


/*--------------------------------------------------------------------------------*\
  * Establish a temporary subset of SCDM LAB variables to work with or review
  * Create derived variable TestDate based on 3 date fields using the hierarchy
     defined at the start of the module
\*--------------------------------------------------------------------------------*/
%let qa_table= ;
%let qa_table_1= ;
%let qa_table_2= ;
%macro get_qa_table ;
  %if &do_partitions and not %eval(&module in &tabid_exc) %then %do ;
    data t_view /view=t_view ;
      set qadata.&&&module.table.:(keep=ms_test_name result_type ms_test_sub_category fast_ind
            specimen_source loinc stat pt_loc result_loc px_codetype order_dt lab_dt lab_tm
            result_dt result_tm orig_result ms_result_c ms_result_n modifier orig_result_unit
            std_result_unit ms_result_unit norm_range_low modifier_low norm_range_high modifier_high abn_ind) ;
    ;run;
    %let qa_table = t_view ;
  %end ;
  %else %do;
    %let qa_table = qadata.&&&module.table(keep=ms_test_name result_type ms_test_sub_category fast_ind
            specimen_source loinc stat pt_loc result_loc px_codetype order_dt lab_dt lab_tm
            result_dt result_tm orig_result ms_result_c ms_result_n modifier orig_result_unit
            std_result_unit ms_result_unit norm_range_low modifier_low norm_range_high modifier_high abn_ind) ;
  %end;
%mend;
%get_qa_table ;
  data _null_;
    length labdt resdt orddt labtm restm 3 yearmonth $7;
      if _n_ = 1 then do;
      /* msoc.&module._l2_record_count */
      declare hash reccount(ordered:'a', hashexp:8);
      reccount.DefineKey('key1');
      reccount.DefineData('ms_test_name','result_type','ms_test_sub_category', 'fast_ind',
                          'specimen_source', 'loinc', 'count');
      reccount.DefineDone();

      /* msoc.&module._l2_test_units */
      declare hash testunit(ordered:'a', hashexp:8);
      testunit.DefineKey('key2');
      testunit.DefineData('ms_test_name','result_type','ms_test_sub_category', 'fast_ind',
                          'specimen_source', 'orig_result_unit', 'std_result_unit', 'ms_result_unit', 'count');
      testunit.DefineDone();

      /* &module._l2_temp_ms_result */
      declare hash msres(hashexp:8);
      msres.DefineKey('key3');
      msres.DefineData('ms_test_name','result_type','ms_test_sub_category', 'fast_ind',
                       'specimen_source', 'loinc', 'orig_result', 'ms_result_c', 'modifier',
                       'ms_result_n', 'ms_result_unit', 'count');
      msres.DefineDone();

      /* dplocal.&module._l2_mapped_tests */
      declare hash maptest(ordered:'a', hashexp:8);
      maptest.DefineKey('ms_test_name','result_type','loinc');
      maptest.DefineData('ms_test_name','result_type','loinc', 'n');
      maptest.DefineDone();

      /* dplocal.&module._testdates_ym */
      declare hash testym(ordered:'a', hashexp:8);
      testym.DefineKey('yearmonth');
      testym.DefineData('yearmonth','count');
      testym.DefineDone();

      /* dplocal.temp_date_all */
      declare hash dtym(hashexp:8);
      dtym.DefineKey('ms_test_name','result_type','lab_dt','result_dt','order_dt');
      dtym.DefineData('ms_test_name','result_type','lab_dt','result_dt','order_dt','n');
      dtym.DefineDone();

      /* msoc.&module._l3_record_lrodt_ptloc_ym */
      declare hash lropat(ordered:'a', hashexp:8);
      lropat.DefineKey('ms_test_name','result_type', 'ms_test_sub_category', 'fast_ind', 'pt_loc', 'yearmonth');
      lropat.DefineData('ms_test_name','result_type', 'ms_test_sub_category', 'fast_ind', 'pt_loc', 'yearmonth', 'count');
      lropat.DefineDone();

      /* msoc.&module._l3_record_lrodt_ym */
      declare hash lroym(ordered:'a', hashexp:8);
      lroym.DefineKey('ms_test_name','result_type', 'ms_test_sub_category', 'fast_ind', 'yearmonth');
      lroym.DefineData('ms_test_name','result_type', 'ms_test_sub_category', 'fast_ind', 'yearmonth', 'count');
      lroym.DefineDone();

      /* msoc.lab_l3_dates */
      declare hash l3dates(ordered:'a', hashexp:8);
      l3dates.DefineKey('ms_test_name', 'result_type','orddt', 'labdt', 'resdt');
      l3dates.DefineData('ms_test_name', 'result_type','orddt', 'labdt', 'resdt', 'count');
      l3dates.DefineDone();

      /* msoc.lab_l3_times */
      declare hash l3times(ordered:'a', hashexp:8);
      l3times.DefineKey('ms_test_name', 'result_type','labtm', 'restm');
      l3times.DefineData('ms_test_name', 'result_type','labtm', 'restm', 'count');
      l3times.DefineDone();

      /*msoc.lab_l3_test_resultc_stats */
      declare hash rescst(ordered: 'a', hashexp:8);
      rescst.DefineKey("key4");
      rescst.DefineData("ms_test_name", "ms_test_sub_category", "fast_ind", "specimen_source",
                        "pt_loc", "ms_result_c", "orig_result", "count");
      rescst.DefineDone();

      /* msoc.lab_l3_stat */
      declare hash st(ordered: 'a', hashexp:8);
      st.DefineKey("ms_test_name", "result_type", "stat");
      st.DefineData("ms_test_name", "result_type", "stat", "count");
      st.DefineDone();

      /* msoc.lab_l3_result_loc */
      declare hash resloc(ordered: 'a', hashexp:8);
      resloc.DefineKey("ms_test_name", "result_type", "ms_test_sub_category", "fast_ind", "result_loc");
      resloc.DefineData("ms_test_name", "result_type", "ms_test_sub_category", "fast_ind", "result_loc" ,"count");
      resloc.DefineDone();

      /* msoc.lab_l3_pt_loc */
      declare hash ptloc(ordered: 'a', hashexp:8);
      ptloc.DefineKey("ms_test_name", "result_type", "pt_loc");
      ptloc.DefineData("ms_test_name", "result_type", "pt_loc" ,"count");
      ptloc.DefineDone();

      /* msoc.lab_l3_abn_ind */
      declare hash abn(ordered: 'a', hashexp:8);
      abn.DefineKey("ms_test_name", "result_type", "abn_ind");
      abn.DefineData("ms_test_name", "result_type", "abn_ind" ,"count");
      abn.DefineDone();

      /* msoc.lab_l3_px_codetype */
      declare hash pxtype(ordered: 'a', hashexp:8);
      pxtype.DefineKey("ms_test_name", "result_type", "ms_test_sub_category", "fast_ind", "px_codetype");
      pxtype.DefineData("ms_test_name", "result_type", "ms_test_sub_category", "fast_ind", "px_codetype" ,"count");
      pxtype.DefineDone();

      /* msoc.&module._l3_range */
      declare hash rnge(ordered: 'a', hashexp:8);
      rnge.DefineKey("key5");
      rnge.DefineData("ms_test_name", "result_type", "ms_test_sub_category", "fast_ind", "specimen_source",
                      "modifier_low","norm_range_low","modifier_high","norm_range_high" ,"count");
      rnge.DefineDone();
      end;

    do until(end);
          set &qa_table end=end;
          length key1 key2 key3 key4 key5 $16;

          yearmonth=put(coalesce(lab_dt,result_dt,order_dt),yymmd.);
          labdt=ifn(not missing(lab_dt),1,0);
          resdt=ifn(not missing(result_dt),1,0);
          orddt=ifn(not missing(order_dt),1,0);
          labtm=ifn(not missing(lab_tm),1,0);
          restm=ifn(not missing(result_tm),1,0);
          /* Create compressed keys to reduce memory footprint */
          key1=md5(cats(ms_test_name,result_type,ms_test_sub_category, fast_ind, specimen_source, loinc));
          key2=md5(cats(ms_test_name,result_type,ms_test_sub_category, fast_ind, specimen_source,
                        orig_result_unit, std_result_unit, ms_result_unit));
          key3=md5(cats(ms_test_name,result_type,ms_test_sub_category, fast_ind, specimen_source, loinc,
                        orig_result, ms_result_c, modifier, ms_result_n, ms_result_unit));
          key4=md5(cats(ms_test_name, ms_test_sub_category, fast_ind, specimen_source, pt_loc, ms_result_c, orig_result));
          key5=md5(cats(ms_test_name, result_type, ms_test_sub_category, fast_ind, specimen_source,
                        modifier_low,norm_range_low,modifier_high,norm_range_high));

              if reccount.find() ^= 0 then count=0;
              count+1;
              reccount.replace();

              if testunit.find() ^= 0 then count=0;
              count+1;
              testunit.replace();

              if msres.find() ^= 0 then count=0;
              count+1;
              msres.replace();

              if maptest.find() ^= 0 then n=0;
              if upcase(ms_test_name) ^= 'UNMAPPED' then do;
              n+1;
              maptest.replace();
              end;

              if testym.find() ^= 0 then count=0;
              count+1;
              testym.replace();

              if dtym.find() ^= 0 then n=0;
              n+1;
              dtym.replace();

              if lropat.find() ^= 0 then count=0;
              count+1;
              lropat.replace();

              if lroym.find() ^= 0 then count=0;
              count+1;
              lroym.replace();

              if l3dates.find() ^= 0 then count=0;
              count+1;
              l3dates.replace();

              if l3times.find() ^= 0 then count=0;
              count+1;
              l3times.replace();

              if rescst.find() ^= 0 then count=0;
              if not missing(ms_result_c) then do;
              count+1;
              rescst.replace();
              end;

              if st.find() ^= 0 then count=0;
              count+1;
              st.replace();

              if resloc.find() ^= 0 then count=0;
              count+1;
              resloc.replace();

              if ptloc.find() ^= 0 then count=0;
              count+1;
              ptloc.replace();

              if abn.find() ^= 0 then count=0;
              count+1;
              abn.replace();

              if pxtype.find() ^= 0 then count=0;
              count+1;
              pxtype.replace();

              if rnge.find() ^= 0 then count=0;
              if result_type = 'N' then do;
                count+1;
                rnge.replace();
              end;
    end;
    attrib _all_ label='';
    format count comma15.;

    reccount.output(dataset:"msoc.&module._l2_record_count");
    testunit.output(dataset:"msoc.&module._l2_test_units");
    msres.output(dataset:"&module._l2_temp_ms_result");
    maptest.output(dataset:"dplocal.&module._l2_mapped_tests");
    testym.output(dataset:"dplocal.&module._testdates_ym");
    dtym.output(dataset:"dplocal.temp_date_all");
    lropat.output(dataset:"msoc.&module._l3_record_lrodt_ptloc_ym");
    lroym.output(dataset:"msoc.&module._l3_record_lrodt_ym");
    l3dates.output(dataset:"msoc.&module._l3_dates");
    l3times.output(dataset:"msoc.&module._l3_times");
    rescst.output(DATASET:"msoc.&module._l3_test_resultc_stats");
    st.output(DATASET:"msoc.&module._l3_stat");
    resloc.output(DATASET:"msoc.&module._l3_result_loc");
    ptloc.output(DATASET:"msoc.&module._l3_pt_loc");
    abn.output(DATASET:"msoc.&module._l3_abn_ind");
    pxtype.output(DATASET:"msoc.&module._l3_ms_test_sub_category");
    rnge.output(DATASET:"msoc.&module._l3_range");
    stop;
  run;


%macro get_qa_table ;
  %if &do_partitions and not %eval(&module in &tabid_exc) %then %do ;
    data t_view_1 /view=t_view_1 ;
      set qadata.&&&module.table.: (keep=patid ms_test_name result_type order_dt lab_dt result_dt) ;
    run;
    data t_view_2 /view=t_view_2 ;
      set qadata.&&&module.table.: (keep=patid ms_test_name result_type) ;
    run;
    %let qa_table_1 = t_view_1 ;
    %let qa_table_2 = t_view_2 ;
  %end ;
  %else %do;
    %let qa_table_1 = qadata.&&&module.table (keep=patid ms_test_name result_type order_dt lab_dt result_dt) ;
    %let qa_table_2 = qadata.&&&module.table (keep=patid ms_test_name result_type) ;
  %end;
%mend;
%get_qa_table ;
 proc sql NOPRINT;

  create table msoc.&module._l3_n_patid_test_ym as 
  select ms_test_name , 
         result_type , 
         put(coalesce(lab_dt,result_dt,order_dt),yymmd.) as YearMonth , 
         count(unique patid) as count label="PatID Count" format=comma15. 
         from &qa_table_1
         group by ms_test_name, result_type, calculated YearMonth ;

  create table msoc.&module._l3_n_patid_test_y as 
  select ms_test_name , 
         result_type , 
         put(coalesce(lab_dt,result_dt,order_dt),year4.) as Year , 
         count(unique patid) as count label="PatID Count" format=comma15. 
         from &qa_table_1
         group by ms_test_name, result_type , calculated Year ;


  create table msoc.&module._l3_n_patid_test as 
  select ms_test_name , 
         result_type ,  
         count(unique patid) as count label="PatID Count" format=comma15. 
         from &qa_table_2
         group by ms_test_name, result_type;


  create table msoc.&module._l3_n_patid_enrolled_test_y as 
  select a.ms_test_name , 
         a.result_type , 
         put(coalesce(lab_dt,result_dt,order_dt),year4.) as Year , 
         count(unique a.PatID) as count label="PatID Count" format=comma15. 
         from &qa_table_1 as a
           right join dplocal._01_lab (keep=patid) as b 
           on a.patid=b.patid 
         group by a.ms_test_name, a.result_type, calculated Year ;

quit;

/*create list of all testnum for numeric tests that only have one result_type*/
proc sql noprint;
  select quote(strip(ms_test_name)) into :testlist separated by ','
  from (select count(distinct result_type) as typect, testnum, ms_test_name, result_type
  from infolder.lkp_lab_test (where=(characterized='Y'))
  group by testnum, ms_test_name
  having calculated typect=1)
  where result_type='N'
  ;
quit;

*Remove records for numeric tests with character results due to ranges (e.g. 10|50 MG/DL);
data msoc.&module._l2_ms_result msoc.&module._l2_ms_result_x;
  set &module._l2_temp_ms_result;
  if result_type = 'N' then output msoc.lab_l2_ms_result;
  else if ms_test_name in (&testlist.) and result_type = 'C' then output msoc.lab_l2_ms_result_x;
  else output msoc.lab_l2_ms_result;
run;


/**********************************************************************************/
/* Evalauate stamdard Level 2 non-aborting single table checks                    */

%level2;

/**********************************************************************************/
/* Create Level 2 flags for 3-variable cross-checks (checkid=23x)  */
  proc sort data = infolder.lkp_all_flags nodupkey out=_temp_flags_lab(keep=checkid varid variable1 variable2 variable3 variable4 dataset ms_test_name result_type lookup_table);
    by checkid varid variable1 variable2 variable3 variable4 dataset lookup_table;
    where checkid in ('230', '231', '232', '234', '235');
  run;

  proc sql noprint undo_policy=none;
    create table _temp_flags_lab as 
    select distinct a.checkid, a.varid, a.variable1, a.variable2, a.variable3, a.variable4, a.dataset, a.lookup_table, b.testid
    from _temp_flags_lab a
    left join (select a.testid, a.ms_test_name, a.result_type 
                from infolder.lkp_lab_test(keep=testid ms_test_name result_type characterized where=(characterized='Y')) a
                inner join _temp_flags_lab b
                on a.ms_test_name=b.ms_test_name and a.result_type=b.result_type
                where b.checkid='232') b
    on a.ms_test_name=b.ms_test_name and b.result_type=b.result_type
    where checkid in ('230', '231', '232', '234', '235');
  quit;


  data _null_;
    set _temp_flags_lab;
    length wherecond $23;
    if checkid = '230' then wherecond=' is missing';
    else if checkid = '231' then wherecond=' is not missing';
    else if checkid = '234' then wherecond=' <0';
    else if checkid = '235' then wherecond=' =0';
    if checkid in ('230','231','234','235') then do;
    call execute(cat("proc sql noprint; create table ",cats('flag_',checkid,'_',varid),' as 
      select flagid, count from (select ',cats('a.',variable2,',a.',variable3,',a.',variable1,
      ',b.flagid as flagid length=21,sum(a.count) as count format=comma15.'),
      ' from ', dataset,'(keep=',cat(variable2,variable3,variable1,
      ' count) a left join infolder.lkp_all_flags b on '),cats('a.',variable2,'=','b.',variable2), ' and ',
      cats('a.',variable3,'=','b.',variable3), ' where b.checkid= "', checkid, '" and b.varid= "',
           varid, '" and ', cat(variable1,wherecond), ' group by 1,2,3,4 having not missing(flagid));'));
    end;
    if checkid = '232' then do; 
    call execute(cat("proc sql noprint; create table ",cats('flag_',checkid,'_',varid),' as 
      select flagid, count from (select ',cat('a.',variable2,',a.',variable3,',a.',variable1,', 
             sum(a.count) as count format=comma15., 
             case when ',cats('a.',variable1,'^=','b.',variable1),' then ',
             upcase(cats('"','LAB_2_',varid,'_',testid,'_',checkid,'"')),' else " " end as FlagID length=21'),
      ' from (select c.*, d.testid from ', dataset,'(keep=',cat(variable2,variable3,variable1,' count) c inner join 
             infolder.lkp_lab_test(keep=ms_test_name result_type testid characterized where=(characterized="Y")) d on '),
             cats('c.',variable2,'=','d.',variable2), ' and ',
             cats('c.',variable3,'=','d.',variable3), ') a left join (select distinct testid,', cats(variable2, ",",
             variable3, "," ,variable1),' from ',cats('infolder.',lookup_table),') b 
      on ', cat('a.', variable2, '=','b.',variable2,' and ', 'a.',variable3,'=','b.',variable3,' and ', 'a.',
             variable1,'=','b.',variable1),' group by 1, 2, ',cats('a.',variable1),
             ' ,flagid having not missing(flagid));'));
    end;
  run;

  proc sort data = _temp_flags_lab nodupkey out=unique_checkid(keep=checkid);
    by checkid;
  run;


  data _null_;
    set unique_checkid;
        call execute(cats('data _null_; 
                  if _n_=1 then do;
                  declare hash f(ordered:"a");
                  f.DefineKey("flagid");
                  f.DefineData("flagid","_count");
                  f.DefineDone();
                  end;
                  do until (end);
                    set work.flag_',checkid,'_: end=end;
                    if f.find() ^= 0 then _count=0;
                    _count=sum(_count,count);
                    f.replace();
                  end;
                  f.output(dataset:','"work.flag_',checkid,'(rename=(_count=count))");'));
        call execute(cats('proc datasets lib=work nolist nowarn nodetails; delete flag_',checkid,'_: ;quit;'));
  run;
 
  data work.l2_flags_lab;
    set work.flag_:;
  run;

proc sql noprint;
  create table dplocal.custom_l2_flags_&module. as
  select b.flagid
       , b.flagtype
       , b.flag_descr
       , b.flagyn
       , b.abortyn
       , a.count as count label=' ' format=comma15.
  from l2_flags_&module. as a left join infolder.lkp_all_flags as b
    on a.flagid=b.flagid
  where b.flag_descr ne " "
  ;
quit;

data dplocal.l2_flags_&module;

    set dplocal.l2_flags_&module 
        dplocal.custom_l2_flags_&module;

run;

proc datasets lib=dplocal  nolist nowarn nodetails;
    delete custom_l2_flags_&module;
quit;

proc datasets lib=work kill nolist nowarn nodetails;
quit;

/********** End of Level 2 ********************************************************/


/*---------------------------------------------------------------------------------------*/
/*  START Level 3 Data                                                                   */
/*---------------------------------------------------------------------------------------*/
%macro lab_date_dist;

  %let datelist=lab result order;
  %do j=1 %to 3;
    %let date = %scan(&datelist,&j);

      data _null_;
        declare hash dt();
        dt.DefineKey("&date._dt");
        dt.DefineData("&date._dt","_n");
        dt.DefineDone();

        do until (end);
        set dplocal.temp_date_all(keep=n &date._dt where=(not missing(&date._dt))) end=end;
        if dt.find() ^= 0 then _n=0;
        _n=sum(_n,n);
        dt.replace();
        end;
        dt.output(dataset:"dplocal.temp_date(rename=(_n=n))");
      run;

      %let datenobs=0;
      %if %sysfunc(exist(dplocal.temp_date)) %then %do;
        data _null_;
          if 0 then set dplocal.temp_date nobs=datenobs;
          call symputx('datenobs',datenobs);
        run; 
      %end;

    %if &datenobs. gt 0 %then %do;
      %date_percentiles (libin=dplocal, dsin=temp_date, libout=dplocal, dsout=temp_date_dist_&module._&j., vars=&date._dt);
    %end;

    proc datasets lib=dplocal nolist nowarn nodetails; delete temp_date; quit;
  %end;

    data _null_;
    if _n_ = 1 then do;
    declare hash l3dt();
    l3dt.DefineKey("ms_test_name","result_type","YearMonth_lab","YearMonth_result","YearMonth_order");
    l3dt.DefineData("ms_test_name","result_type","YearMonth_lab","YearMonth_result","YearMonth_order","count");
    l3dt.DefineDone();
    end;
    do until (end);
        set dplocal.temp_date_all(keep=ms_test_name result_type order_dt lab_dt result_dt n) end=end;

        YearMonth_lab=put(lab_dt,yymmd.);
        YearMonth_result=put(result_dt,yymmd.);
        YearMonth_order=put(order_dt,yymmd.);
        if l3dt.find() ^= 0 then count=0;
        count=sum(count,n);
        l3dt.replace();
    end;
    l3dt.output(dataset:"msoc.lab_l3_dates_ym");
  run;
%mend;
%lab_date_dist;

%set_ds (libin=dplocal, dsin_prefix=temp_date_dist_&module., libout=dplocal, dsout=date_dist_&module.);

  proc datasets lib=dplocal nolist;
    delete temp_date_all;
  quit;

/**********************************************************************************/
/* Create msoc.lab_l3_n_unmap_loinc_all as one way frequencies of unmapped LOINCS */
/* Create msoc.lab_l3_n_unmap_loinc_ym as unmapped LOINC frequencies stratified by year-month (top 5000 LOINCS) */
/* Create msoc.lab_l3_n_unmap_loinc_agegrp_sex as unmapped LOINC requencies stratified by agegroup and sex (top 5000 LOINCS) */

%macro get_qa_table ;
  %if &do_partitions and not %eval(&module in &tabid_exc) %then %do ;
    data t_view /view=t_view ;
      set qadata.&&&module.table.:(keep=LOINC PatID ms_test_name) ;
    run;
    %let qa_table = t_view ;
  %end ;
  %else %do;
    %let qa_table = qadata.&&&module.table(keep=LOINC PatID ms_test_name) ;
  %end;
%mend;
%get_qa_table ;
/*msoc.lab_l3_n_unmap_loinc_all*/
proc sql noprint;
  create table msoc.&module._l3_n_unmap_loinc_all as
  select LOINC
        ,count(distinct PatID) as PatID_count format=comma15.
        ,count(LOINC) as Count format=comma15.
  from &qa_table
  where ms_test_name='UNMAPPED'
  group by LOINC
  order by Count descending
  ;
quit;

data loinc5000;
  set msoc.&module._l3_n_unmap_loinc_all(obs=5000);
run;

%macro get_qa_table ;
  %if &do_partitions and not %eval(&module in &tabid_exc) %then %do ;
    data t_view /view=t_view ;
      set qadata.&&&module.table:(keep=patid loinc lab_dt result_dt order_dt) ;
    run;
    %let qa_table = t_view ;
  %end ;
  %else %do;
    %let qa_table = qadata.&&&module.table(keep=patid loinc lab_dt result_dt order_dt) ;
  %end;
%mend;
%get_qa_table ;
proc sql noprint;
  create table msoc.&module._l3_n_unmap_loinc_ym as 
  select put(coalesce(lab_dt,result_dt,order_dt),yymmd.) as YearMonth
         ,LOINC
         ,count(distinct patid) as PatID_count format=comma15.
         ,count(*) as count format=comma15.
  from &qa_table
  where loinc in (select loinc from loinc5000)
  group by calculated YearMonth, LOINC;
quit;

*Merge &demtable and &labtable to calculate age/agegroups;
%macro get_qa_table ;
  %if &do_partitions and not %eval(&module in &tabid_exc) %then %do ;
    data t_view_1 /view=t_view_1 ;
      set qadata.&DemTable.: (keep = PatID sex birth_date) ;
    run;
    data t_view_2 /view=t_view_2 ;
      set qadata.&&&module.table.: (keep = LOINC PatID lab_dt result_dt order_dt) ;
    run;
    %let qa_table_1 = t_view_1 ;
    %let qa_table_2 = t_view_2 ;
  %end ;
  %else %do;
    %let qa_table_1 = qadata.&DemTable. (keep = PatID sex birth_date) ;
    %let qa_table_2 = qadata.&&&module.table (keep = LOINC PatID lab_dt result_dt order_dt) ;
  %end;
%mend;
%get_qa_table ;
proc sql noprint;
  create table msoc.&module._l3_n_unmap_loinc_agegrp_sex as
  select sex,
         AgeGroup,
         LOINC,
         count(distinct PatID) as PatID_count format=comma15., 
         count(LOINC) as Count format=comma15.
  from (select a.PatID
        ,a.sex
        ,b.LOINC
        ,coalesce(lab_dt,result_dt,order_dt) as TestDate
        ,floor((intck('month',a.birth_date, calculated testdate)-(day(calculated testdate)<day(a.birth_date)))/12) as age_years
        ,case when calculated age_years = . then 'Missing'
              when calculated age_years between 0 and 17 then '0-17 yrs'
              when calculated age_years  between 18 and 39 then '18-39 yrs'
              when calculated  age_years between 40 and 64 then '40-64 yrs'
              else '65+ yrs'
         end as AgeGroup
  from &qa_table_1 as a
       right join &qa_table_2 as b
  on a.PatID=b.PatID
  where b.LOINC in (select loinc from loinc5000))
  group by sex, AgeGroup, LOINC
  ;
quit;

/**********************************************************************************/
/* Create msoc.lab_l3_test_resultn_stats_ms as descriptive statistics of MS_result_n by test */
/* Create msoc.lab_l3_test_resultn_stats_orig as descriptive statistics of orig_result_n by test */
%let pn= ;
%macro get_qa_pn ;
  %if &do_partitions and not %eval(&module in &tabid_exc) %then %let pn=: ; %else %let pn= ;
%mend;
%get_qa_pn ;
data _lab_temp;
  set qadata.&&&module.table&pn.(keep=MS_result_n orig_result
                   MS_test_name result_type MS_test_sub_category fast_ind specimen_source pt_loc
                   modifier orig_result_unit std_result_unit MS_result_unit);
  if result_type = 'N' then orig_result_n=input(strip(orig_result),8.);
run;

%macro mean1 (var=, out=);
  proc means data=_lab_temp
             (keep=MS_result_n %if &var.=orig_result_n %then %do; &var. %end;
                   MS_test_name result_type MS_test_sub_category fast_ind specimen_source pt_loc
                   modifier orig_result_unit std_result_unit MS_result_unit) noprint nway;
    var &var.;
    class MS_test_name result_type MS_test_sub_category fast_ind specimen_source pt_loc modifier MS_result_unit std_result_unit orig_result_unit / missing;
    where MS_result_n ne . ;
    output out=temp (drop=_type_ rename=_freq_=count)
       mean=Mean stddev=Std min=Min p5=P5 p25=P25 median=Median mode=Mode p75=P75 P95=P95 max=Max /keeplen;
  run;
  data msoc.&module._l3_test_resultn_stats_&out.;
    retain MS_test_name Result_type MS_Test_Sub_Category Fast_Ind Specimen_Source Pt_Loc Orig_Result_Unit Std_Result_unit MS_Result_Unit;
    set temp;
    format mean median std 10.2 count comma15.;
  run;
  proc datasets lib=work nolist nowarn nodetails; delete temp; quit;
%mend;
%mean1 (var=ms_result_n, out=ms);
%mean1 (var=orig_result_n, out=orig);


/**********************************************************************************/
/* MS_Result_N by Range category */
proc sort data=infolder.lkp_lab_result_ranges out=work.range;
  by fmtname;
run;

proc format cntlin=range;
run;

%macro ranges (var=, var_short=);

  proc sql noprint;
    select distinct strip(fmtname),  
                    count(distinct fmtname) 
           into :fmtlist separated by " ", 
                :nfmt trimmed
    from work.range
    ;
  quit;

  %do i=1 %to &nfmt.;
    %let fmt=%scan(&fmtlist., &i.);
    %if &do_partitions and not %eval(&module in &tabid_exc) %then %do ;
      data t_view /view=t_view ;
        set qadata.&&&module.table.: (keep=ms_test_name result_type ms_test_sub_category
                            fast_ind &var. ms_result_n ms_result_unit modifier) ;
        where result_type='N' and modifier='EQ' and ms_result_n ne . and
             compress(ms_test_name||ms_test_sub_category||fast_ind||ms_result_unit,'/ ')="&fmt." ;
      run;
      %let qa_table = t_view ;
    %end ;
    %else %do;
      %let qa_table = qadata.&&&module.table (keep=ms_test_name result_type ms_test_sub_category
                            fast_ind &var. ms_result_n ms_result_unit modifier)
       where result_type='N' and modifier='EQ' and ms_result_n ne . and
             compress(ms_test_name||ms_test_sub_category||fast_ind||ms_result_unit,'/ ')="&fmt." ;

    %end;
    proc sql noprint;
      create table work.temp as
      select ms_test_name
           , ms_test_sub_category
           , fast_ind
           , &var.
           , ms_result_unit
           , put(ms_result_n, &fmt..) as ms_result_range length=25
           , count(*) as count format=comma15.
           , min(ms_result_n) as OrderVar
      from &qa_table
      group by ms_test_name, ms_test_sub_category, fast_ind, &var., ms_result_unit, ms_result_range
      order by ms_test_name, ms_test_sub_category, fast_ind, &var., ms_result_unit, ordervar
      ;
    quit;

    %if %unquote(&sqlobs.) ne 0 %then %do;
      proc sql noprint;
        select sum(count), substr(ms_test_name, 1, 6) into :ntest trimmed, :test trimmed
        from work.temp
      ;
      create table msoc.lab_l3_cat_resultn_&var_short._&test. (drop=ordervar) as
      select *
      from work.temp
      ;
    quit;
    %end;

  %end;
  proc datasets lib=work nolist;
    delete temp;
  quit;

%mend;
%ranges (var=pt_loc, var_short=ptloc);
%ranges (var=specimen_source, var_short=ss);

/********** End of Level 3 ********************************************************/

/* Clean up temporary or empty datasets and end module */
proc datasets kill lib=work memtype=data nolist nodetails nowarn;
quit;

*-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-;
*  END of scdm_data_qa_review-labs.sas                                                  ;
*-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-;