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

@Astounding Okay this makes sense.. when I checked the line breaks in macro it was somewhere after 250 characters.. let me try this and tell you how it goes..

AshleyBright
Obsidian | Level 7
lrecl is not allowed in infile statement... It says "Invalid Context"
Astounding
PROC Star

Well, we've made some progress by identifying the problem.  As much as I hate to say it, I would bet that SAS's tech support can figure it out from here.  

AshleyBright
Obsidian | Level 7

Thank you @Astounding! Tried different ways and learnt several new things. This helped in digging through the problem.

Tom
Super User Tom
Super User

You cannot use CARDS (aka DATALINES) inside a macro.  The macro processor parses the lines and "ruins" them for the SAS processor.  You have demonstrated that when you execute a macro via CALL EXECUTE you can circumvent that restriction.  When CALL EXECUTE() pushed the string to SAS to put on the stack it runs the macro immediately and pushes the generated text onto the stack for the SAS processor.  When the SAS processor pulls the generated code back off of the stack it does not treat it as being in a macro. Which makes sense because by the time the data step ends and SAS starts trying to interpret the code from the stack the macro has ended execution already.

 

The reason you get LOST CARD message is because you haven't given the data step any lines of data. When you use CARDS in-line data stops BEFORE the first line that contains a semi-colon.  Since the macro processor/call execute combination does not generate lines you get something like:

data want; input x y ; datalines; 1 2; 

So there is no data there.

 

Either parse the string yourself. 

Or if you want to use the INPUT statement then create a temporary file and put the text in there and read from there.

%macro createDS(dsname, colnames, colvalues);
filename lines temp;
data _null_;
  file lines;
  put "&colvalues";
run;
data &dsname;
  length &colnames $1000;
  infile lines dlm='|' dsd ;
  input &colnames @@;
run;
filename lines;
%mend createDS;

options mprint;
%createDS(xxx,name value,a|100|b|200|c|300);
proc print;
run;
Obs    name    value

 1      a       100
 2      b       200
 3      c       300

 

AshleyBright
Obsidian | Level 7

Thanks a ton, @Tom.. for your clear and detailed answer.. This is really a good learning. Really helpful.  I just tried this and it is working! Got to test it for a couple of other scenarios though!

novinosrin
Tourmaline | Level 20

@AshleyBright Is this what you are after?

 


data have;
infile cards  dlm='|';
array col(10)$;
input  col(*)  @@;
cards;
abc|def ghi|jkl
mno|pqr|stu||vw
x|y|z
;
AshleyBright
Obsidian | Level 7

Thank you @novinosrin! I event tried this arrays for a different problem

AshleyBright
Obsidian | Level 7
But the macro variables are resolving here.. I am just getting lost card message... And is there any other way to achieve dynamic dataset creation?
Kurt_Bremser
Super User

@AshleyBright wrote:
But the macro variables are resolving here.. I am just getting lost card message... And is there any other way to achieve dynamic dataset creation?


DATALINES DO NOT WORK IN MACROS, AND MACRO REFERENCES DO NOT WORK IN DATALINES.

 

You may want to believe SAS themselves http://support.sas.com/kb/43/902.html, if you don't want to believe me.

 

The fact that you tricked the SAS interpreter into not noticing your mistake by hiding the macro references through call execute does not change that fact.

 

Once again, READ THE LOG (and use proper debugging options for macro code):

I made up a sample dataset by putting your data into a dataset, and ran your code against it:

data raw;
infile cards dlm=',' dsd;
input dsn :$32. columns :$100. values :$100.;
cards;
newds,col1 col2 col3 col4 col5 col6 col7 col8 col9,abc|def ghi|jkl mno|pqr|stu||vw x|y|z
;
run;

options mprint symbolgen;

%macro createDS(dsname, colnames, colvalues);

data &dsname;
attrib &colnames length = $1000;
infile datalines dlmstr='|';
input &colnames @@;
datalines;
&colvalues
;
run;

%mend createDS;

data test;
set raw;
call execute('%createDS('||dsn||','||columns||','||values||');');
run;

Note that I use options mprint and symbolgen to reveal more about what the macro does.

Here's the log:

37         data raw;
38         infile cards dlm=',' dsd;
39         input dsn :$32. columns :$100. values :$100.;
40         cards;

NOTE: The data set WORK.RAW has 1 observations and 3 variables.
2                                                          Das SAS System                             08:36 Friday, January 18, 2019

NOTE: DATA statement used (Total process time):
      real time           0.00 seconds
      cpu time            0.00 seconds
      
42         ;

43         run;
44         
45         options mprint symbolgen;
46         
47         %macro createDS(dsname, colnames, colvalues);
48         
49         data &dsname;
50         attrib &colnames length = $1000;
51         infile datalines dlmstr='|';
52         input &colnames @@;
53         datalines;
54         &colvalues
55         ;
56         run;
57         
58         %mend createDS;
59         
60         data test;
61         set raw;
62         call execute('%createDS('||dsn||','||columns||','||values||');');
63         run;

SYMBOLGEN:  Makrovariable DSNAME wird in newds aufgelöst
MPRINT(CREATEDS):   data newds;
SYMBOLGEN:  Makrovariable COLNAMES wird in col1 col2 col3 col4 col5 col6 col7 col8 col9 aufgelöst
MPRINT(CREATEDS):   attrib col1 col2 col3 col4 col5 col6 col7 col8 col9 length = $1000;
MPRINT(CREATEDS):   infile datalines dlmstr='|';
SYMBOLGEN:  Makrovariable COLNAMES wird in col1 col2 col3 col4 col5 col6 col7 col8 col9 aufgelöst
MPRINT(CREATEDS):   input col1 col2 col3 col4 col5 col6 col7 col8 col9 @@;
MPRINT(CREATEDS):   datalines;
SYMBOLGEN:  Makrovariable COLVALUES wird in abc|def ghi|jkl mno|pqr|stu||vw x|y|z aufgelöst
MPRINT(CREATEDS):   abc|def ghi|jkl mno|pqr|stu||vw x|y|z ;
MPRINT(CREATEDS):   run;
NOTE: There were 1 observations read from the data set WORK.RAW.
NOTE: The data set WORK.TEST has 1 observations and 3 variables.
NOTE: DATA statement used (Total process time):
      real time           0.00 seconds
      cpu time            0.00 seconds
      

NOTE: CALL EXECUTE generated line.
1         + data newds; attrib col1 col2 col3 col4 col5 col6 col7 col8 col9 length = $1000; infile datalines dlmstr='|'; input col1 
col2 col3 col4 col5 col6 col7 col8 col9 @@; datalines;

NOTE: LOST CARD.
REGEL:     ----+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0                     
67         GOPTIONS NOACCESSIBLE;
col1=  col2=  col3=  col4=  col5=  col6=  col7=  col8=  col9=  _ERROR_=1 _N_=1
NOTE: SAS went to a new line when INPUT statement reached past the end of a line.
NOTE: The data set WORK.NEWDS has 0 observations and 9 variables.
NOTE: DATA statement used (Total process time):
      real time           0.01 seconds
3                                                          Das SAS System                             08:36 Friday, January 18, 2019

      cpu time            0.00 seconds
      
1         +
       abc|def ghi|jkl mno|pqr|stu||vw x|y|z ; run;;

What's most important here is the fact that the data step starts to run BEFORE the content of the datalines is fed to it. This happens because the macro variables are resolved before the data step code is fed into the execution pipe, and this seems to create an artificial step boundary, so you get an empty datalines block. Adding a truncover option to the infile statement even causes an endless loop that crashes when the resulting dataset runs into a disk full condition.

Skewering the macro timing by using call execute() without %nrstr() prevents SAS from noticing that there's something wrong here; when feeding macros to call execute(), it is always a good idea to use %nrstr() to prevent premature macro resolution:

data test;
set raw;
call execute('%nrstr(%createDS('||dsn||','||columns||','||values||'));');
run;

When you do this, macro and Base code are excecuted in their "natural" order, and SAS notices the problem:

37         data test;
38         set raw;
39         call execute('%nrstr(%createDS('||dsn||','||columns||','||values||'));');
40         run;

NOTE: There were 1 observations read from the data set WORK.RAW.
NOTE: The data set WORK.TEST has 1 observations and 3 variables.
NOTE: DATA statement used (Total process time):
      real time           0.02 seconds
      cpu time            0.00 seconds
      

NOTE: CALL EXECUTE generated line.
1         + %createDS(newds                           ,col1 col2 col3 col4 col5 col6 col7 col8 col9                                 
2                                                          Das SAS System                             08:36 Friday, January 18, 2019

                       ,abc|def ghi|jkl mno|pqr|stu||vw x|y|z                                                               );
SYMBOLGEN:  Makrovariable DSNAME wird in newds aufgelöst
MPRINT(CREATEDS):   data newds;
SYMBOLGEN:  Makrovariable COLNAMES wird in col1 col2 col3 col4 col5 col6 col7 col8 col9 aufgelöst
MPRINT(CREATEDS):   attrib col1 col2 col3 col4 col5 col6 col7 col8 col9 length = $1000;
MPRINT(CREATEDS):   infile datalines dlmstr='|' truncover;
SYMBOLGEN:  Makrovariable COLNAMES wird in col1 col2 col3 col4 col5 col6 col7 col8 col9 aufgelöst
MPRINT(CREATEDS):   input col1 col2 col3 col4 col5 col6 col7 col8 col9 @@;
MPRINT(CREATEDS):   datalines;

ERROR: The macro CREATEDS generated CARDS (data lines) for the DATA step, which could cause incorrect results.  The DATA step and 
       the macro will stop executing.
NOTE: The data set WORK.NEWDS has 0 observations and 9 variables.
NOTE: DATA statement used (Total process time):
      real time           0.02 seconds
      cpu time            0.00 seconds
      

ERROR: The macro CREATEDS will stop executing.

 

AshleyBright
Obsidian | Level 7

Thank you, @Kurt_Bremser. It's a good experience to be learning from all of you through this forum. This really helped.

Ksharp
Super User

Try infile 's option RECFM=N .

 

data temp;
infile "c:\temp\temp.txt" dlm='|' dsd recfm=n;
input x : $80. @@;
run;

SAS Innovate 2025: Call for Content

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 25. Read more here about why you should contribute and what is in it for you!

Submit your idea!

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
  • 27 replies
  • 2039 views
  • 3 likes
  • 7 in conversation