Hello,
I would appreciate if you can advise regarding how I would conditionally process the do loops below :
data test;
set test1;
if Year <= 2016 then process 35 diag codes
array _diag_code (35)$ DIAG_CODE_: ;
do i=1 to 35;
IF SUBSTR(_diag_code{i},1,4) in : ('B182') or SUBSTR(_diag_code{i}, 1,3) in ('C22','K70', 'K71', 'K72', 'K73', 'K74', 'K75', 'K76', 'K77', 'R18') then DIAG=1;
end;
if DIAG=1 ;
array _diag_code (50)$ DIAG_CODE_: ;
If year >2017 then process 50 diag codes
do i=1 to 50;
IF SUBSTR(_diag_code{i},1,4) in : ('B182') or SUBSTR(_diag_code{i}, 1,3) in ('C22','K70', 'K71', 'K72', 'K73', 'K74', 'K75', 'K76', 'K77', 'R18') then DIAG=1;
end;
if DIAG=1 ;
run;
Is Year part of the Test1 dataset? Or is Year provided separately somehow in advance?
If year is separate, you can use a macro variable as in the first example below. This example will work in SAS 9.4 M5 or newer. It will not work in M4 and prior.
data test;
set test1;
array _diag_code (*) $ DIAG_CODE_: ;
%IF &Year <= 2016 %THEN
%DO;
do i=1 to 35;
IF SUBSTR(_diag_code{i},1,4) in : ('B182') or SUBSTR(_diag_code{i}, 1,3) in ('C22','K70', 'K71', 'K72', 'K73', 'K74', 'K75', 'K76', 'K77', 'R18') then DIAG=1;
end;
if DIAG=1 ;
%END;
%ELSE
%DO;
do i=1 to 50;
IF SUBSTR(_diag_code{i},1,4) in : ('B182') or SUBSTR(_diag_code{i}, 1,3) in ('C22','K70', 'K71', 'K72', 'K73', 'K74', 'K75', 'K76', 'K77', 'R18') then DIAG=1;
end;
if DIAG=1 ;
%END;
run;
If Year is part of the Test1 dataset, you could code the following:
data test;
DROP Nbr_of_Diag;
set test1;
array _diag_code (*) $ DIAG_CODE_: ;
IF Year <= 2016 THEN
Nbr_of_Diag = 35;
ELSE
Nbr_of_Diag = 50;
do i=1 to Nbr_of_Diag;
IF SUBSTR(_diag_code{i},1,4) in : ('B182') or SUBSTR(_diag_code{i}, 1,3) in ('C22','K70', 'K71', 'K72', 'K73', 'K74', 'K75', 'K76', 'K77', 'R18') then DIAG=1;
end;
if DIAG=1 ;
run;
Jim
With this stated as part of your macro
set dss.Hmdb_dss_core_20&yr.;
That strongly implies you &yr is going to be a two digit value to make names like Hmdb_dss_core_2016 for example. Which
makes this
%If &yr. <= 2016 %Then
a serious problem.
Suggestion: make sure that your YR macro parameter is a 4 digit year then use
set dss.Hmdb_dss_core_&yr.
Your output data sets would also have 4 digit year names.
If you are using the Do i=1 to 50 to adjust for the number of elements in your array then instead of the "50" use dim(arrayname). The DIM function returns the number of elements in an array. So if you have a small change in the data you don't have to change code as it will match the number of elements defined in an array statement like
array _diag_code (*)$ DIAG_CODE_: ;
BTW since the variables already exist the $ in above array statement is redundant.
data yr06;
array ds (*) DIAG_CODE_1-DIAG_CODE_35;
do i=1 to 35;
ds(i)=i;
end;
array os (*) OOH_IND_1-OOH_IND_35;
do j=1 to 35;
os(j)=j;
end;
run;
data yr07;
array ds (*) DIAG_CODE_1-DIAG_CODE_50;
do i=1 to 50;
ds(i)=i;
end;
array os (*) OOH_IND_1-OOH_IND_50;
do j=1 to 50;
os(j)=j;
end;
run;
data yr08;
array ds (*) DIAG_CODE_1-DIAG_CODE_25;
do i=1 to 25;
ds(i)=i;
end;
array os (*) OOH_IND_1-OOH_IND_25;
do j=1 to 25;
os(j)=j;
end;
run;
%macro test(yr);
data new;
set yr&yr;
array _diag_code (*)$ DIAG_CODE_: ;
do i=1 to dim(_diag_code);
put _diag_code(i)=;
end;
array _ooh (*)$ ooh_ind_:;
do j=1 to dim(_ooh);
put _ooh(j)=;
end;
run;
%mend;
options mprint;
%test(06)
%test(07)
%test(08)
Hello would appreciate if you can advise how using the dim function i can ensure that all the elements in an array are looked at for all the years
Yes, I think that makes sense, but it's very hard to read your code. When you post code, please use the below icon:
Jim
Alternatively
How do I correct the error below:
2933 /**HMDB QC Records F2006/07 to F2019/20.**/
2934
2935
2936 %macro run_hmdb(yr=);
2937
2938 data hmdb&yr.;
2939 set dss.Hmdb_dss_core_20&yr.;
2940
2941 format AGE_GRP $20.;
2942 format PROVINCE $20.;
2943 if analytical_inst_type_code in ('1','A') and strip(submitting_prov_code) in ('4');
2944 /*if upcase(admission_category) not in ('R') and upcase(admission_category) not in ('S')
2944! and upcase(entry_code) not in ('S' 'N' );*/
2945
2946
2947
2948 /* general inclusion/exclusion */
2949 if UPCASE(ENTRY_CODE) not in ( "S" "N") ;
2950 if UPCASE(ADMISSION_CATEGORY) not in ("R" "S") ;
2951
2952
2953 /*GENDER*/
2954 if gender_code in ("F" , "M") then gender_include=1;
2955 if gender_include=1;
2956
2957 /**AGE**/
2958 if UPCASE(age_code) in ("D" ) and AGE_UNITS <=29 then delete;
2959
2960
2961 /* AGE GROUPS */
2962 if UPCASE(age_code) in ("Y" )and AGE_UNITS <30 then AGE_GRP = "Group 1: <30 yrs.";
2963 else if UPCASE(age_code) in ("Y" )and 30 <= AGE_UNITS <= 49 then AGE_GRP = "Group 2:
2963! 30-49 yrs.";
2964 else if UPCASE(age_code) in ("Y" )and 50 <= AGE_UNITS <= 64 then AGE_GRP = "Group 3:
2964! 50-64 yrs.";
2965 else if UPCASE(age_code) in ("Y" )and AGE_UNITS >= 65 then AGE_GRP = "Group 4: >= 65
2965! yrs.";
2966 /*Acute IP*/
2967 if ANALYTICAL_INST_TYPE_CODE in ("1") then inpatient = 1;
2968 if inpatient = 1;
2969
2970 /**Diagnosis of interest HCV, CLD, or HCC **/
2971 array _diag_code (*)$ DIAG_CODE_: ;
2972 %If &yr. <= 2016 %Then
2973 %Do
2974
2975 do i=1 to 35;
ERROR: Expected %TO not found in %DO statement.
ERROR: A dummy macro will be compiled.
2976 IF SUBSTR(_diag_code{i},1,4) in : ('B182') or SUBSTR(_diag_code{i}, 1,3)
2977 in ('C22','K70', 'K71', 'K72', 'K73', 'K74', 'K75', 'K76', 'K77', 'R18')
2978 then DIAG=1;
2979
2980 end;
2981
2982 if DIAG=1 ;
2983 %end;
2984 %Else
2985 %Do;
2986
2987 do i=1 to 50;
2988 IF SUBSTR(_diag_code{i},1,4) in : ('B182') or SUBSTR(_diag_code{i}, 1,3)
2989 in ('C22','K70', 'K71', 'K72', 'K73', 'K74', 'K75', 'K76', 'K77', 'R18')
2990 then DIAG=1;
2991
2992 end;
2993
2994 if DIAG=1 ;
2995 %end;
2996
2997 array _cci_code (*)$ interv_cci_code_:;
2998 array _ooh (*)$ ooh_ind_:;
2999 array _status(*)$ status_attribute_code_:;
3000
3001 %If &yr. <= 2016 %Then
3002 %Do
3003 do j=1 to 20;
ERROR: Expected %TO not found in %DO statement.
3004
3005 IF _cci_code{j} in :('1OA85LAXXK','1OA85VCXXK','1OA85WLXXJ', '1OA85WLXXK')
3006 and _ooh[j] = ' ' and
3007 _status[j] ne 'A' then INTERV=1;
3008
3009 end;
3010 %end;
3011 %Else
3012 %Do;
3013
3014 do j=1 to 35;
3015
3016 IF _cci_code{j} in :('1OA85LAXXK','1OA85VCXXK','1OA85WLXXJ', '1OA85WLXXK')
3017 and _ooh[j] = ' ' and
3018 _status[j] ne 'A' then INTERV=1;
3019
3020 %end;
3021
3022
3023
3024 if DIAG=1 and INTERV=1 THEN FLAG=1;
3025
3026 /* DEATHS */
3027 if Discharge_disposition in ('07' '72' '73' '74') then flag_InHospDeath = 1;
3028
3029
3030 %if &yr. <= 18 %then %do;if DISCHARGE_DISPOSITION in ("07") then flag_InHospDeath = 1;
3030! %end;
3031 %if &yr. >= 18 %then %do;if DISCHARGE_DISPOSITION in ("72" "73" "74") then
3031! flag_InHospDeath = 1 ;%end;
3032
3033
3034 /**/
3035
3036
3037 keep
3038 fiscal_year
3039 dad_transaction_id
3040 SUBMITTING_PROV_CODE
3041 province
3042 ENTRY_CODE
3043 ADMISSION_CATEGORY
3044 ANALYTICAL_INST_TYPE_CODE
3045 gender_code
3046 age_code
3047 age_units
3048
3049 gender_include
3050 AGE_GRP
3051 inpatient
3052 DISCHARGE_DISPOSITION
3053 DIAG_CODE_:
3054 interv_cci_code_:
3055 ooh_ind_:
3056 status_attribute_code_:
3057 FLAG
3058 DIAG
3059 INTERV
3060 flag_InHospDeath
3061
3062 ;
3063 run;
3064
3065 %mend;
3066 %run_hmdb(yr=15);
-
180
WARNING: Apparent invocation of macro RUN_HMDB not resolved.
ERROR 180-322: Statement is not valid or it is used out of proper order.
WARNING: Apparent invocation of macro RUN_HMDB not resolved.
3066 %run_hmdb(yr=16);
-
180
ERROR 180-322: Statement is not valid or it is used out of proper order.
WARNING: Apparent invocation of macro RUN_HMDB not resolved.
3066 %run_hmdb(yr=17);
-
180
ERROR 180-322: Statement is not valid or it is used out of proper order.
WARNING: Apparent invocation of macro RUN_HMDB not resolved.
3066 %run_hmdb(yr=18);
-
180
ERROR 180-322: Statement is not valid or it is used out of proper order.
WARNING: Apparent invocation of macro RUN_HMDB not resolved.
3067 %run_hmdb(yr=19);
-
180
ERROR 180-322: Statement is not valid or it is used out of proper order.
How would i correct the error above
Make sure to end your macro %DO statement. Without the ending semi-colon it thinks you are trying to code an iterative %DO with a index variable named DO.
I find it make much more sense to place the %DO in these cases on the same line as the %THEN or %ELSE. It makes the code much easier to scan for humans.
You have left them out in more than one place. In this one you also left out an END for one of the DO statement that the macro is generating.
Keeping track of missing ends is much easier if you treat the indentation of the macro code and the SAS code it is generating separate. That way when you are scanning the SAS code it is easier to check if the block closing lines are indented at the same place as the lines that open the block.
%if &yr. <= 2016 %then %do;
do j=1 to 20;
IF _cci_code{j} in: ('1OA85LAXXK','1OA85VCXXK','1OA85WLXXJ','1OA85WLXXK')
and _ooh[j] = ' '
and _status[j] ne 'A' then INTERV=1;
end;
%end;
%else %do;
do j=1 to 35;
IF _cci_code{j} in: ('1OA85LAXXK','1OA85VCXXK','1OA85WLXXJ','1OA85WLXXK')
and _ooh[j] = ' '
and _status[j] ne 'A' then INTERV=1;
end;
%end;
But looking the difference between the two sets of SAS code being generated the only difference I see is the upper bound on the DO loop. If the goal is to scan the whole array this is where DIM() function can help. It should let you eliminate the macro logic.
Since you are referencing three arrays you might want to make sure J never gets too large for any of them.
You could also save some time by stopping when you finally set INTERV to 1.
do j=1 to min(dim(_ooh),dim(_status),dim(_cci_code)) while (interv ne 1);
if _cci_code[j] in: ('1OA85LAXXK','1OA85VCXXK','1OA85WLXXJ','1OA85WLXXK')
and _ooh[j] = ' '
and _status[j] ne 'A' then INTERV=1;
end;
Learn how use the CAT functions in SAS to join values from multiple variables into a single value.
Find more tutorials on the SAS Users YouTube channel.
Ready to level-up your skills? Choose your own adventure.