Hi, I'm trying to import lots of text files and am having problems creating the macro variables which will allow me to do this.
I've been able to assign the file names to variables so when I run;
%put _user_ ;
I get the following;
filenm1 text_file_01326
filenm2 text_file_14568
filenm3 text_file_08554
filenm4 text_file_99954
As these files have different schemas, I'm trying to create a second macro variable for each file identifying the schema.
The schema identifier is on the first line of the text file. I've isolated this record and am trying to use call symput to assign a value to a macro variable as such.
The macro loop works and the if then else block works but no macro variable gets assigned.
If I remove the strip function from the call symput, I get an error in the log stating;
ERROR: Symbolic variable name Filetp 1 must contain only letters, digits, and underscores.
This indicates that the index function is correctly identifying the existance of the text in the var1 string and it's the call symput which is not functioning as I want.
I've read SUGI papers which suggest that the variables can in some instances be created locally but I don't think that this what's happening here.
I've also tried assigning numbers and SAS data set variables as macro values but this also hasn't worked.
Any help with this would be greatly appreciated.
Cheers,
Paul.
The following worked for me:
data ob_2_1;
var1='xx DMMT ss';
run;
data ob_2_2;
var1='xx DDDD ss';
run;
data ob_2_3;
var1='xx DMLN ss';
run;
%macro ftmac ;
%do i = 1 %to 3 ;
data _null_ ;
set ob_2_&i ; /*this data set contains only the first record from the text file*/
if index(var1,'DMMT') ge 1 then do;
%global %sysfunc(cats(filetp,&i.));
call symput('filetp'||strip(&i),'DM1') ;
end;
else if index(var1,'DMLN') ge 1 then do;
%global %sysfunc(cats(filetp,&i.));
call symput('filetp'||strip(&i),'DM2') ;
end;
run ;
%put _user_ ;
%end ;
%mend ftmac ;
%ftmac
%put &filetp1. ;
Paul,
One problem lies in the first parameter to CALL SYMPUT. Within the context of a DATA step, &i is a number where the software is looking for characters. Change this:
strip(&i)
Instead, while this would be acceptable:
"&i"
It would be easier to just use a first parameter that looks like this (and use double quotes, not single):
"filetp&i"
This streamlines the situation, but doesn't really fix it.
Yes, it is true in your examples that the macro variables created by CALL SYMPUT will be %LOCAL, not %GLOBAL. If you need to reference them once the macro has finished executing, add this statement as the first statement in the %DO loop:
%global filetp&i;
Good luck.
I've edited my answer a couple of times. Sorry about that. Please use the latest suggestions, and re-post what your program now looks like.
According to the test code I just ran your macro variables ARE being created, but only locally. If you need them to be global, why not just add %global statements creating them as global before you create them?
data ob_2_1;
var1='xx DMMT ss';
run;
data ob_2_2;
var1='xx DDDD ss';
run;
data ob_2_3;
var1='xx DMLN ss';
run;
%macro ftmac ;
%do i = 1 %to 3 ;
data _null_ ;
set ob_2_&i ; /*this data set contains only the first record from the text file*/
if index(var1,'DMMT') ge 1 then
call symput('filetp'||strip(&i),'DM1') ;
else if index(var1,'DMLN') ge 1 then
call symput('filetp'||strip(&i),'DM2') ;
run ;
%put _user_ ;
%end ;
%mend ftmac ;
%ftmac
%put &filetp1. ;
Art,
OK, here's a headscratcher for you.
As you noticed, the macro variables are %LOCAL if you run the program as is.
However, try adding this statement before running the macro:
%global i;
You'll find that the macro variables are now all %GLOBAL, including those generated by CALL SYMPUT. The rules are that CALL SYMPUT will not force the creation of a %LOCAL symbol table. When &I already exists in the %GLOBAL table, there is no local table needed and CALL SYMPUT is forced to add to the %GLOBAL table. It's a case where you can look at the macro in its entirety, but can't tell ahead of time whether CALL SYMPUT will use the %GLOBAL or %LOCAL table.
The following worked for me:
data ob_2_1;
var1='xx DMMT ss';
run;
data ob_2_2;
var1='xx DDDD ss';
run;
data ob_2_3;
var1='xx DMLN ss';
run;
%macro ftmac ;
%do i = 1 %to 3 ;
data _null_ ;
set ob_2_&i ; /*this data set contains only the first record from the text file*/
if index(var1,'DMMT') ge 1 then do;
%global %sysfunc(cats(filetp,&i.));
call symput('filetp'||strip(&i),'DM1') ;
end;
else if index(var1,'DMLN') ge 1 then do;
%global %sysfunc(cats(filetp,&i.));
call symput('filetp'||strip(&i),'DM2') ;
end;
run ;
%put _user_ ;
%end ;
%mend ftmac ;
%ftmac
%put &filetp1. ;
Thank you both for your help with this.
Cheers,
Paul.
Instead of using %global and call symput you can do call symputx with the 'G' modifier.
Arthur Tabachneck wrote:
data _null_ ;
...
%global %sysfunc(cats(filetp,&i.));
call symputx('filetp'||strip(&i),'DM1','G') ;
...
The SYMPUTX routine will also eliminate the numeric to character conversion note as it does not expect the second argument to be character as does SYMPUT.
FriedEgg: Nice addition .. very much appreciated!
Astounding: Agreed, unless you force the issue as I did in my previous post
SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!
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.