If you wish to continue using Proc IMPORT then you will need to ensure the columns are like-typed. In your case you know column_k should be numeric, so a DATA step can convert the character values to numeric using the INPUT function.
proc import … out = dataA;
proc import … out = dataB;
data dataA;
set dataA;
_num = input(column_k, best12.);
drop column_k;
rename _num = column_k;
run;
data dataB;
set dataB;
_num = input(column_k, best12.);
drop column_k;
rename _num = column_k;
run;
data want;
set dataA dataB;
run;
In a larger scope mismatched data types for a column name can occur in a scenario such as dealing with multi-year imports.
Suppose the older data can't be re-read and the newer data has different column type.
For the case of wanting numeric values, one approach is to have macro that writes source code that converts, if necessary, specified variables from character to numeric.
Example:
%enforce_num (perm.loans2015, age amount remaining, out=work.loans2015)
%enforce_num (perm.loans2016, age amount remaining, out=work.loans2016)
%enforce_num (perm.loans2017, age amount remaining, out=work.loans2017)
data loans_3yrs;
set work.loans2015-loans2017;
run;
Going back to your simpler case:
proc import … out = dataA;
proc import … out = dataB;
%enforce_num(dataA, column_k)
%enforce_num(dataB, column_k)
data want;
set dataA dataB;
run;
What would the macro enforce_num look like? It would have to:
- scan the input data set meta data
- determine if a variable is one of those specified and is character type
- write source code to convert the variable to numeric
- maintain original variable order
%macro enforce_num(data, vars, out=&data);
/*
* Arguments:
* data - name of input data set
* vars - space separated list of variables that must be numeric, convert type if necessary
* out - name of output data set, default same as input data set
*
* Output:
* - Unchanged data set if data and out are the same and no conversion needed
* - Changed data set if some columns in data need conversion to numeric
* - replaces data if out is same as data
* - replaces out if out is different then data
* - the column order of the changed data set will be the same as the original data set
*/
%local dsid index index2 vars varname vartype varnames debug;
%let index2 = 0; %* number of variables determined to be requiring conversion;
%let debug = 0;
%if &debug %then %put NOTE: &SYSMACRONAME: data=%superq(data);
%let dsid = %sysfunc(open(&data));
%if &dsid %then %do;
%do index = 1 %to %sysfunc(attrn(&dsid, nvars));
%let varname = %sysfunc(varname(&dsid, &index));
%let varnames = &varnames &varname;
%if %sysfunc(indexw(&varname, &vars)) %then %do;
%if C = %sysfunc(vartype(&dsid, &index)) %then %do;
%* Data contains character variable requiring enforcement;
%let index2 = %eval(&index2+1);
%local convert&index2;
%let convert&index2 = &varname;
%let varnames = &varnames ___&index2 ; %* Variables that will be converted will be named __<#> during conversion;
%end;
%end;
%end;
%let dsid = %sysfunc(close(&dsid));
%end;
%else
%put %sysfunc(sysmsg());
%*put NOTE: &=vars;
%*put NOTE: &=varnames;
%if &index2 = 0 %then %do;
%* No columns need to be converted to numeric, copy to out if necessary;
%if &data ne &out %then %do;
data &out;
set &data;
run;
%end;
%return;
%end;
%* Some columns need to be converted to numeric;
%* Ensure the converted column is at the same position (varnum) as in the original data set;
data &out;
retain &varnames;
set &data;
%do index = 1 %to &index2;
___&index = input(&&convert&index,?? best12.);
%end;
drop
%do index = 1 %to &index2;
&&convert&index
%end;
;
rename
%do index = 1 %to &index2;
___&index = &&convert&index
%end;
;
run;
%put NOTE: ------------------------------------------------;
%put NOTE: &data has been subjected to numeric enforcement.;
%put NOTE: ------------------------------------------------;
%mend enforce_num;