Hi,
I'm trying to fix a program that used to work but no longer does. The goal is to have a user input their data library and the data file that they want to delimit with pipes (|). However, the program now crashes every time it tries to read the SAS data library step. Ideally, it would also write the variable names out into the delimited text file as well, but we've been living with that hassle for years.
Here is the code as I have it so far. Any help would be greatly appreciated!
DATA DATA1;
%WINDOW INFO
#1 @5 'THIS PROGRAM PIPE DELIMITS A SAS DATASET.'
#3 @5 ' TYPE THE INPUT & OUTPUT DATASETS BELOW. '
#4 @5 ' DO NOT PLACE NAMES IN QUOTES! '
#6 @5 'INPUT SAS LIBRARY AS FOLLOWS:'
#9 @5 'MAINFRAME (MVS/TSO): USERID.LIBNAME'
#11 @5 ' INPUT SAS LIBRARY: '
#11 @30 SAS_LB 19 ATTR=UNDERLINE
#12 @5 ' INPUT SAS MEMBER: '
#12 @30 SAS_MB 8 ATTR=UNDERLINE
#14 @5 'OUTPUT NAMES SHOULD BE ENTERED AS FOLLOWS:'
#16 @5 'OUTPUT DELIMITTED DATA TO: MRKTBJM.OUT.OUT';
/*DISPLAY THE WINDOW & PERFORM ANY INPUT VALIDATION*/
%DISPLAY INFO;
CALL SYMPUT('SAS_LB',SAS_LB);
CALL SYMPUT('SAS_MB',SAS_MB);
%put ---------SAS LIBRARY ENTERED WAS &SAS_LB;
%put ---------SAS MEMBER ENTERED WAS &SAS_MB;
STOP;
RUN;
LIBNAME SASDATA "&SAS_LB";
FILENAME SASOUT 'MRKTBJM.OUT.OUT';
/*GET THE TYPE & VARIABLE NAMES OF THE INPUT SAS DATASET*/
PROC CONTENTS DATA=SASDATA.&SAS_MB NOPRINT OUT=DATA1;
/*CREATE MACRO VARIABLES IN THE FORM "NAMEXX" AND "TYPEXX" */
/*TO HOLD THE INPUT DATASETS VARIABLE NAMES AND TYPE, WHERE */
/*"XX" IS THE VARIABLE NUMBER (1,2,3..ETC.). */
/*FOR EXAMPLE, MACRO VARIABLE "NAME1" WILL CONTAIN THE NAME */
/*OF THE FIRST VARIABLE IN THE INPUT DATASET & MACRO VARIABLE */
/*"TYPE1" WILL CONTAIN ITS TYPE (1=NUMERIC 2=CHARACTER). */
DATA DATA1; SET DATA1;
LNAME="'"||TRIM(NAME)||"'";
CALL SYMPUT('NAME'||COMPRESS(VARNUM),NAME);
CALL SYMPUT('LNAME'||COMPRESS(VARNUM),LNAME);
CALL SYMPUT('TYPE'||COMPRESS(VARNUM),TYPE);
/*GET NUMBER OF OBSERVATIONS IN 'DATA1' WHICH IS EQUAL TO THE */
/*NUMBER OF VARIABLES IN THE INPUT SAS DATASET. */
PROC CONTENTS DATA=DATA1 NOPRINT OUT=DATA2;
DATA DATA2; SET DATA2; CALL SYMPUT('COUNT',NOBS);
%MACRO VARS1;
%DO I=1 %TO &COUNT;
'"' &&LNAME&I '"|';
%END;
%MEND VARS1;
%MACRO VARS2;
%DO I=1 %TO &COUNT;
%IF &&TYPE&I=1 %THEN
&&NAME&I +(-1)'|';
%ELSE
&&NAME&I +(-1)'|';
%END;
%MEND VARS2;
DATA DATA2;
SET SASDATA.&SAS_MB;
FILE SASOUT;
PUT %VARS2 +(-1)' ';
RUN;
The INFO window is probably NOT your problem.
It looks like the issue is not being able to access the dataset.
It looks like the purpose of this program is to dump a dataset into a pipe delimited text file. You do NOT need macro code to do that.
%let ds= DS.NOT.FOUND ;
%let fname='MRKTBJM.OUT.OUT';
DATA _null_;
length sas_lb $40 sas_mb $32;
WINDOW INFO
#1 @5 'THIS PROGRAM PIPE DELIMITS A SAS DATASET.'
#3 @5 ' TYPE THE INPUT & OUTPUT DATASETS BELOW. '
#4 @5 ' DO NOT PLACE NAMES IN QUOTES! '
#6 @5 'INPUT SAS LIBRARY AS FOLLOWS:'
#9 @5 'MAINFRAME (MVS/TSO): USERID.LIBNAME'
#11 @5 ' INPUT SAS LIBRARY: '
#11 @30 SAS_LB ATTR=UNDERLINE
#12 @5 ' INPUT SAS MEMBER: '
#12 @30 SAS_MB ATTR=UNDERLINE
#14 @5 'OUTPUT NAMES SHOULD BE ENTERED AS FOLLOWS:'
#16 @5 'OUTPUT DELIMITTED DATA TO: MRKTBJM.OUT.OUT'
;
DISPLAY INFO;
rc = libname('SASDATA',sas_lb);
if rc then put 'ERROR: Could not make libref.';
else do;
ds=catx('.','SASDATA',sas_mb);
if not exist(ds) then put 'ERROR: Member ' sas_mb 'not found in ' sas_lb '.' ;
else CALL SYMPUTX('DS',ds);
end;
STOP;
RUN;
data _null_;
set &ds ;
file &fname dsd dlm='|' lrecl=64000;
%* Need to use LINK statement so that _NAME_ is not included in _ALL_ ;
if _n_ eq 1 then link names;
put (_all_)(:);
return;
names:
length _name_ $32;
do while(1);
call vnext(_name_);
if upcase(_name_) eq '_NAME_' then leave;
put _name_ @;
end;
put;
return;
run;
What error messages do you get in the log? Perhaps post the full log, if it's not too long.
Here is the SAS log for the critical part of the program:
137 DATA DATA1;
138 %WINDOW INFO
139 #1 @5 'THIS PROGRAM PIPE DELIMITS A SAS DATASET.'
140 #3 @5 ' TYPE THE INPUT & OUTPUT DATASETS BELOW. '
141 #4 @5 ' DO NOT PLACE NAMES IN QUOTES! '
142 #6 @5 'INPUT SAS LIBRARY AS FOLLOWS:'
143 #9 @5 'MAINFRAME (MVS/TSO): USERID.LIBNAME'
144 #11 @5 ' INPUT SAS LIBRARY: '
145 #11 @30 SAS_LB 19 ATTR=UNDERLINE
146 #12 @5 ' INPUT SAS MEMBER: '
147 #12 @30 SAS_MB 8 ATTR=UNDERLINE
148 #14 @5 'OUTPUT NAMES SHOULD BE ENTERED AS FOLLOWS:'
149 #16 @5 'OUTPUT DELIMITTED DATA TO: XXXXXXX.OUT.OUT';
150
151 /*DISPLAY THE WINDOW & PERFORM ANY INPUT VALIDATION*/
152 %DISPLAY INFO;
153 CALL SYMPUT('SAS_LB',SAS_LB);
154 CALL SYMPUT('SAS_MB',SAS_MB);
155 %put ---------SAS LIBRARY ENTERED WAS &SAS_LB;
---------SAS LIBRARY ENTERED WAS XXXXXXX.sas.p5587d3
156 %put ---------SAS MEMBER ENTERED WAS &SAS_MB;
---------SAS MEMBER ENTERED WAS appolsp
157 STOP;
158 RUN;
NOTE: Numeric values have been converted to character
values at the places given by: (Line):(Column).
153:22 154:22
NOTE: The data set WORK.DATA1 has 0 observations and 2 variables.
NOTE: The DATA statement used 0.02 CPU seconds and 25571K.
NOTE: The address space has used a maximum of 1156K below the line and
29136K above the line.
159
160 LIBNAME SASDATA "&SAS_LB";
NOTE: Libref SASDATA was successfully assigned as follows:
Engine: V9
Physical Name: /
161 FILENAME SASOUT 'XXXXXXX.OUT.OUT';
162 /*GET THE TYPE & VARIABLE NAMES OF THE INPUT SAS DATASET*/
163 PROC CONTENTS DATA=SASDATA.&SAS_MB NOPRINT OUT=DATA1;
ERROR: Invalid data set name SASDATA..
NOTE: Line generated by the macro variable "SAS_MB".
163 SASDATA. .
-
22
200
WARNING: Ignoring second data set reference.
ERROR 22-322: Syntax error, expecting one of the following: ;, (, CENTILES,
DATA, DETAILS, DIR, DIRECTORY, FMTLEN, LIB, MEMTYPE, MT,
MTYPE, NODETAILS, NODS, NOPRINT, ORDER, OUT, OUT2, SHORT,
VARNUM.
ERROR 200-322: The symbol is not recognized and will be ignored.
164
Is the SAS library the macro is passing a valid library reference for your system?
155 %put ---------SAS LIBRARY ENTERED WAS &SAS_LB;
---------SAS LIBRARY ENTERED WAS XXXXXXX.sas.p5587d3
Yes, the %PUT statement shows a correct library reference. The XXXXXXX was used by me to replace the actual library name before posting the SAS log.
So I see two possible issues.
1) You did not actually enter a member name. Since your error message is not listing the member name, but perhaps you just blanked that out.
2) Your data is NOT in V9 format. Perhaps it is still in SAS 6 format? You probable need to convert the data before you can read it with version 9 of SAS.
Hi, Tom,
In response to #1 of your post, there is (or should be) a SAS member name entered (APPOLSP--see below).
156 %put ---------SAS MEMBER ENTERED WAS &SAS_MB;
---------SAS MEMBER ENTERED WAS appolsp
But in the libname statement, SASDATA was assigned a null value. Could this be an issue where the code needs to be rearranged or needs to have %GLOBAL added to keep the macro variables from disappearing?
160 LIBNAME SASDATA "&SAS_LB";
NOTE: Libref SASDATA was successfully assigned as follows:
Engine: V9
Physical Name: /
In response to #2, DAT3.APPOLSP.DATA is a Version 6 data set. If I hardcode the SAS data library into the program instead of using the &SAS_LB macro variable, the whole thing works fine.
I'm going to look at your most recent post now.
Why do you have the macro statement %WINDOW embedded into the middle of a DATA step? Perhaps you meant to use the WINDOW statement instead?
The original code did have WINDOW instead of %WINDOW. I modified that line hoping it would fix the problem. The program used to run okay until we upgraded SAS from something like v6 to v9.4.
gee whiz
you are working too hard, having to read all that old-style UPCASE
Here is code that is easier on the eyes for the task of writing the list of variables and types to output file.
%let libname = sashelp;
%let memname = class;
DATA _null_;
dsid = open ("&libname..&memname" );
lrecl = attrn(dsid,'lrecl');
n_obs = attrn(dsid,'nobs ');
n_vars = attrn(dsid,'nvars');
do i = 1 to n_vars;
name = varname(dsid,i);
type = vartype(dsid,i);
putlog name= type=;
end;
rc = close (dsid);
stop;
run;
Ron, I tried running your code, but there were errors with the DO loop.
145 %let libname = XXXXXXX.SAS.P5587D3;
146 %let memname = APPOLSP;
147 DATA _null_;
148 dsid = open ("&libname..&memname" );
149 lrecl = attrn(dsid,'lrecl');
150 n_obs = attrn(dsid,'nobs ');
151 n_vars = attrn(dsid,'nvars');
152
153 do i = 1 to n_vars;
154 name = varname(dsid,i);
155 type = vartype(dsid,i);
156 putlog name= type=;
157 end;
158 rc = close (dsid);
159 stop;
160 run;
NOTE: Argument 1 to function ATTRN(0,'lrecl') at line 149 column 10 is invalid.
NOTE: Argument 1 to function ATTRN(0,'nobs ') at line 150 column 10 is invalid.
NOTE: Argument 1 to function ATTRN(0,'nvars') at line 151 column 10 is invalid.
ERROR: Invalid DO loop control information, either the INITIAL or TO expression is missing or the BY expression is missing, zero, or invalid.
dsid=0 lrecl=. n_obs=. n_vars=. i=1 name= type= rc=. _ERROR_=1 _N_=1
NOTE: Mathematical operations could not be performed at the following places. The results of the operations have been set to missing values.
Each place is given by: (Number of times) at (Line):(Column).
1 at 149:10 1 at 150:10 1 at 151:10
libname libref '<directory-specification>';
despite my macro variable name of libname
sashelp is a libref, i.e. maximum length of 8 characters.
to me it looks like you provided the directory-specification for the value of a libname statement.
The INFO window is probably NOT your problem.
It looks like the issue is not being able to access the dataset.
It looks like the purpose of this program is to dump a dataset into a pipe delimited text file. You do NOT need macro code to do that.
%let ds= DS.NOT.FOUND ;
%let fname='MRKTBJM.OUT.OUT';
DATA _null_;
length sas_lb $40 sas_mb $32;
WINDOW INFO
#1 @5 'THIS PROGRAM PIPE DELIMITS A SAS DATASET.'
#3 @5 ' TYPE THE INPUT & OUTPUT DATASETS BELOW. '
#4 @5 ' DO NOT PLACE NAMES IN QUOTES! '
#6 @5 'INPUT SAS LIBRARY AS FOLLOWS:'
#9 @5 'MAINFRAME (MVS/TSO): USERID.LIBNAME'
#11 @5 ' INPUT SAS LIBRARY: '
#11 @30 SAS_LB ATTR=UNDERLINE
#12 @5 ' INPUT SAS MEMBER: '
#12 @30 SAS_MB ATTR=UNDERLINE
#14 @5 'OUTPUT NAMES SHOULD BE ENTERED AS FOLLOWS:'
#16 @5 'OUTPUT DELIMITTED DATA TO: MRKTBJM.OUT.OUT'
;
DISPLAY INFO;
rc = libname('SASDATA',sas_lb);
if rc then put 'ERROR: Could not make libref.';
else do;
ds=catx('.','SASDATA',sas_mb);
if not exist(ds) then put 'ERROR: Member ' sas_mb 'not found in ' sas_lb '.' ;
else CALL SYMPUTX('DS',ds);
end;
STOP;
RUN;
data _null_;
set &ds ;
file &fname dsd dlm='|' lrecl=64000;
%* Need to use LINK statement so that _NAME_ is not included in _ALL_ ;
if _n_ eq 1 then link names;
put (_all_)(:);
return;
names:
length _name_ $32;
do while(1);
call vnext(_name_);
if upcase(_name_) eq '_NAME_' then leave;
put _name_ @;
end;
put;
return;
run;
Tom, your code worked except for getting the following error: ERROR: Invalid value for the LRECL option.
Change it to something that will work on your system.
The idea was to set a big enough value that it would be able to accommodate most datasets without causing the data to wrap. Usually for most datasets the header line is the longest.
Join us for SAS Innovate 2025, our biggest and most exciting global event of the year, in Orlando, FL, from May 6-9. Sign up by March 14 for just $795.
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.