BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.
BryanMarks
Calcite | Level 5

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;                  

1 ACCEPTED SOLUTION

Accepted Solutions
Tom
Super User Tom
Super User

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;

View solution in original post

20 REPLIES 20
Quentin
Super User

What error messages do you get in the log?  Perhaps post the full log, if it's not too long.

BASUG is hosting free webinars Next up: Jane Eslinger presenting PROC REPORT and the ODS EXCEL destination on Mar 27 at noon ET. Register now at the Boston Area SAS Users Group event page: https://www.basug.org/events.
BryanMarks
Calcite | Level 5

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                                                                      

Reeza
Super User

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   

BryanMarks
Calcite | Level 5

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.

Tom
Super User Tom
Super User

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.

BryanMarks
Calcite | Level 5

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. Smiley Happy

Tom
Super User Tom
Super User

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?

BryanMarks
Calcite | Level 5

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.

Ron_MacroMaven
Lapis Lazuli | Level 10

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;

BryanMarks
Calcite | Level 5

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                            

Ron_MacroMaven
Lapis Lazuli | Level 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.

Tom
Super User Tom
Super User

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;

BryanMarks
Calcite | Level 5

Tom, your code worked except for getting the following error:  ERROR: Invalid value for the LRECL option.

Tom
Super User Tom
Super User

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.

sas-innovate-2024.png

Join us for SAS Innovate April 16-19 at the Aria in Las Vegas. Bring the team and save big with our group pricing for a limited time only.

Pre-conference courses and tutorials are filling up fast and are always a sellout. Register today to reserve your seat.

 

Register now!

How to Concatenate Values

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.

Click image to register for webinarClick image to register for webinar

Classroom Training Available!

Select SAS Training centers are offering in-person courses. View upcoming courses for:

View all other training opportunities.

Discussion stats
  • 20 replies
  • 2185 views
  • 6 likes
  • 5 in conversation