I have config file that contains the following info:
The user might provide me with a specific source information and value to be updated.
I need to read the config file and find out the Field name to be updated and update the corresponding field with the user input value.
Below is my code:
data config;
length source $1 updt_Field $12 ;
input source $ updt_Field $;
datalines;
A field1
B field2
;
run;
data out;
length field1 $20 field2 $20 value $10;
if 0 then set config;
if _N_ = 1 then do;
/* load config data set into the hash object */
declare hash h_src(dataset: 'work.config');
/* define SMALL data set variable K as key and S as value */
h_src.defineKey('source');
h_src.defineData('updt_Field');
h_src.defineDone();
/* avoid uninitialized variable notes */
call missing(source,updt_Field);
end;
value='0000099999';
drop rc;
source='2';
rc = h_src.find();
put updt_Field;
* I want to update the field represented in the updt_Field variable with the value;
vnamex(updt_Field)=value;
run;
Does the code do as you expect or what results differ from your expected results? 🙂
It errors out at the vnamex function. I was kind of hoping the vnamex function would do the job for me but its not the case!!
Ok. Just to be clear. The source='2'; statemet, does that indicate that it is the second variable that has to be updated with the given value?
Actually the statement should be source='A'; which indicates that field1 should be updated with the value "0000099999".
How will you know which value to use? Will it always be the '0000099999' as a character?
Register today and join us virtually on June 16!
sasglobalforum.com | #SASGF
View now: on-demand content for SAS users
For now, we can assume the value would be always constant. but again, I can always read this as input from a user.
I'm intrigued using a hash in a datastep to do this. @PeterClemmensen do you know if it's possible to use the vnamex function on the left-hand side of an expression?
Register today and join us virtually on June 16!
sasglobalforum.com | #SASGF
View now: on-demand content for SAS users
@noling wrote:
I'm intrigued using a hash in a datastep to do this. @PeterClemmensen do you know if it's possible to use the vnamex function on the left-hand side of an expression?
Pretty sure that use of VNAMEX(anything) = causes an
ERROR: Undeclared array referenced: vnamex.
As will VNAME and all the variable information functions except for the CALL functions. They return some sort of value given a variable name, array reference or for the correct functions, an expression that resolves to a name and can assign that resolved value to another variable
There are several ways to work around this issue. Here is one.
data config;
length source $1 updt_Field $12 ;
input source $ updt_Field $;
datalines;
A field1
B field2
;
run;
data out;
length field1 $20 field2 $20 value $10;
if 0 then set config;
if _N_ = 1 then do;
/* load config data set into the hash object */
declare hash h_src(dataset: 'work.config');
/* define SMALL data set variable K as key and S as value */
h_src.defineKey('source');
h_src.defineData('updt_Field');
h_src.defineDone();
/* avoid uninitialized variable notes */
call missing(source,updt_Field);
end;
value='0000099999';
drop rc;
source='A';
rc = h_src.find();
call symputx('updt_Field', updt_Field);
&updt_Field.=value;
run;
Agree, using symputx() won't work here as the macro variable will only become available after the data step (timing issue).
Eventually one could get around this via dosubl() but I believe that still wouldn't resolve the issue. Basically: The variable assignment code needs to exist during the compilation phase. There is no way to generate such syntax during execution time of the data step.
Below code should do what you want:
data config;
length source $1 updt_Field $12;
input source $ updt_Field $;
datalines;
A field1
B field2
;
run;
data fmtds;
set config;
rename source=start updt_field=label;
retain fmtname '$CodeToVname';
run;
proc format cntlin=fmtds;
run;
/* option 1 */
data fmtds(drop=_:);
length field1 $20 field2 $20 value $10;
array _cvars {*} _character_;
fmtname='VnameToArrElement'; type='I';
do _i=1 to dim(_cvars);
start=vname(_cvars[_i]);
label=_i;
output;
end;
stop;
run;
proc format cntlin=fmtds;
run;
data out;
length field1 $20 field2 $20 value $10;
array _cvars {*} _character_;
source='A';
value='0000099999';
_cvars[input(put(source,$CodeToVname.),VnameToArrElement.)]=value;
run;
/* option 2 */
data out(drop=_i);
length field1 $20 field2 $20 value $10;
array _cvars {*} _character_;
source='A';
value='0000099999';
do _i=1 to dim(_cvars);
if vname(_cvars[_i])=put(source,$CodeToVname.) then
do;
_cvars[_i]=value;
leave;
end;
end;
run;
If this is some sort of request/response scenario where you only create a single row per table "OUT" then I'd go for Option 2 and I'd also consider to create a permanent format from the Config table (updated via a housekeeping job).
If you've got "many" rows in table 'OUT" to process then I'd go for Option 1.
You might also want to add some "upcasing" to the code I've posted so that codes and variable names match if casing in sources differs.
As a last resort, you could always split the DATA step in two. Instead of VNAMEX, capture the variable name as a macro variable:
call symputx('varname', Updt_field);
Then use a new DATA step to utilize &VARNAME. However, before resorting to that, let's explore some other lookup methods other than a hash table.
It seems that the user chooses the value to be updated. Presumably, that can be captured as a macro variable, equivalent to:
%let user_choice=A;
Looking at the CONFIG file, the UPDT_FIELD values must be legal SAS variable names. Is the same true for the values of SOURCE? Are they always a single letter (or a set of letters that could be a valid SAS variable name)? If so, the problem lends itself to a different approach. First, convert the CONFIG file to a set of macro variables:
data _null_;
length source $1 updt_Field $12 ;
input source $ updt_Field $;
call symputx(source, updt_field);
datalines;
A field1
B field2
;
Having done that, the look-up is simple:
data out;
&&&user_choice = '0000099999';
run;
The only downside to this approach is that you lose error-handling ability if the user enters a bad value (if the CONFIG file defines "A" and "B", and the user enters "C" instead).
Are you ready for the spotlight? We're accepting content ideas for SAS Innovate 2025 to be held May 6-9 in Orlando, FL. The call is open until September 16. Read more here about why you should contribute and what is in it for you!
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.
Select SAS Training centers are offering in-person courses. View upcoming courses for: