sas >> Basic help regarding MACROS

by Sarav » Fri, 05 Aug 2005 15:47:11 GMT

Hi all,

I am a rookie programmer in SAS. I was trying to learn SAS Macros and I
got myself into a real mess in a basic step. I need to store a variable
list to a macro variable and then export the variable list in another

I have a data set flights.diabetes which has 20 records in a character
variable 'ID'. I am trying to store the entire 20 records into
'varlist'. Then I would like to create a new dataset 'new' and would
like to transfer all the 20 records to a new variable 'wt' in the new

I tried the following code:

data _null_;
set flights.diabetes;
allid = left(id);
call symput('varlist', allid);

%put &varlist;

data new;
wt = &varlist;

All I get in 'wt' is the last value of ID. What should I do to get the
entire list of values. Should I try to use arrays to store the entire

It would be great if you guys can help me on this as I presume simple
MACRO concept.


sas >> Basic help regarding MACROS

by vaishali_mn » Fri, 05 Aug 2005 16:34:27 GMT


Try the following code.

data _null_;
set flights.diabetes;
allid = left(id);
call symput('varlist' || left(_n_), allid);
call symput('varcnt', left(_n_));

%macro getvars;
%let allvars=;

%do i=1 %to &varcnt;
%let allvars = &allvars &&varlist&i;

data new;
wt = "&allvars";

%mend getvars;




Do You Yahoo!?
Tired of spam? Yahoo! Mail has the best spam protection around

sas >> Basic help regarding MACROS

by ddiskin » Fri, 05 Aug 2005 19:04:18 GMT

Vaishali gave you a good datastep solution. SQL has options that do this=
more easily:
proc sql noprint;
select id into :varlist separated by ' ' from flights.diabetes;
/*or to get them into distinct macro variables: */
select id into :var1 thru :var99 from flights.diabetes;
%let nvar =3D &sqlobs;
Dennis Diskin

sas >> Basic help regarding MACROS

by peter1.crawford » Sat, 06 Aug 2005 00:20:19 GMT

how about avoiding macro until you really need it ! Try this:

%let id_len = 32; * or some simpler default ;
proc sql noprint ; * to collect the length of ID ;
select length into :id_len
from dictionary.columns
where libname= 'FLIGHTS'
& memname= 'DIABETES'
& upcase( name )= 'ID'
data new_layout;
attrib wt length= $1000 ;
do row= 1 to nobs_diabe ;
set flights.diabetes( keep= id ) point= row
nobs= nobs_diabe;
substr( wt, 1+ (row-1)*&id_len ) = left( id );
*................ other processing of wt
or other data ;
* and when ready ;

If any of these statements and statement options are unfamiliar,
then learn about them, before you try to master base sas macros.

Good Luck

Pete Crawford

sas >> Basic help regarding MACROS

by Toby » Sat, 06 Aug 2005 04:13:24 GMT


Well I have seen you have been given a multitude of macro methods. And
yet no one has given you an explaination as to why you only get the
last value for Id in your macro variable.

Basically, you are creating a macro variable with the call symput.
However you are recreating that macro var with each iteration of the
data step. Thus over writing any previuos value you had in it.
Therefor you end up with one macro var with the last obs value for ID.

Now you have been given the data step solution that creates a many
macro vars, basically by adding on the _n_ value to the macros name.
But then you have the whole house keeping problem of how many did I
really create and then you have to get a count of that so you can use
the macro vars later, it is in my opinion way more trouble than it is

You also have been given the standard SQL solution which is to load a
distinct set of those values for ID into a macro var. While a much
better solution than the previuos one it still feels like your trying
to do to much where less is needed.

So with that in mind consider the following:

You don't need Macros at all to get to where you want to go to:

data new (keep = wf) ;
set flights.diabetes end = eof ;
length wf $200. ;
retain wf ;

wf = compbl(wf || id) ;

if eof then output ;

run ;

Should do it.

sas >> Basic help regarding MACROS

by nospam » Sat, 06 Aug 2005 05:11:19 GMT

Then, to complete this roundabout exercise:

data new;
do n = 1 to &nvar; drop n;
id = symget(compress('var'||put(n,2.) ) );

sas >> Basic help regarding MACROS

by davidlcassell » Sat, 06 Aug 2005 05:47:26 GMT

I see that you have already gotten lots of excelletn advice. Let me
throw some more at you.

Try to do this with *no* macro code and *no* macro variables.

At best, you'll see that you just don't need to use macros in this case.
Macro programming is really useful in SAS, but it is often over-used and
abused too. SAS has so many powerful features that in many cases,
you just don't need the macro code.

At worst, you'll see how the code should look when you have the macro
built and executing.

Perhaps, if you wrote back to the SAS-L list and explained why you're
doing this, we could show you how to achieve your goals in a simpler

Express yourself instantly with MSN Messenger! Download today - it's FREE!

Similar Threads

1. Hi Regarding visual basic

2. FW: A MACRO HELP NEEDED - I am new in Macro (please help me)

> -----Original Message-----
> From: SAS(r) Discussion [mailto: XXXX@XXXXX.COM ] On
> Behalf Of Tom Smith
> Sent: Monday, May 19, 2008 1:45 PM
> Subject: A MACRO HELP NEEDED - I am new in Macro (please help me)
> I have a sample code as below:
> %Macro select (AgB, CAB);
> if &AgB = '1' then AgB = "Aucun sympt^ome";
>      else if &AgB = "2" then AgB = "Atteinea";
>   else if &AgB = "3" then AgB = "Atteineb";
>      else if &AgB = "4" then AgB = "Atteinec";
>      else if &AgB = "p" then AgB = "Atteined";
>      else if &AgB = "q" then AgB = "Atteinee";
>     else if &AgB = "z" then AgB = "Atteinef";
> if &CAB = '1' then CAB = "Aucun sympt^ome";
>      else if &CAB = "2" then CAB = "Atteinea";
>   else if &CAB = "3" then CAB = "Atteineb";
>      else if &CAB = "4" then CAB = "Atteinec";
>      else if &CAB = "p" then CAB = "Atteined";
>      else if &CAB = "q" then CAB = "Atteinee";
>     else if &CAB = "z" then CAB = "Atteinef";
>   run;
> %Mend select;
> %select (Choutri, Passenger)
> run;
> Now there is a repitation of the same group of statements or group of
> codes twice ( actually
> in the original program there is hundreds time repitaion).
> How can I put
> those
> repeted statements or codes in a Macro? The program already
> has a Macro
> select.


When beginning to learn macro it is important to keep in mind two concepts (among others):
1. macro and data step code are run at different times.
2. macro processing is text substitution (over-simplified but essentially true).

It looks like you might be inappropriately mixing macro and data step code.  At the very least your choice of macro parameter names may be confusing.

If you want to include the macro generated statements more than once in a program then just include the macro call more than once

Data want;
  set have;
  ... More statements

But as Ron Fehd has pointed out, macro may not be the tool that you want to use to solve your problem.  Why are you using macro code at all here.  What is the problem that macro is supposed to solve for you that you can't use plain old data step code for?

If you tell us more about what you are trying to accomplish, someone may be able to give you better advice.


Daniel J. Nordlund
Washington State Department of Social and Health Services
Planning, Performance, and Accountability
Research and Data Analysis Division
Olympia, WA  98504-5204

3. A MACRO HELP NEEDED - I am new in Macro (please help me)

4. Help: computing basic stats by group

5. Basic Logistic Regression Help....plz?

6. Need help with basic IML, "RTFM"


I'm trying to do a basic task in IML and failing miserably.  This is a
true "RTFM" question, so if that offends you, please read no further.

I want to read a data set into IML, run a procedure, and put the output
into a data set.  Here is what happened:

1659  proc    iml ;
1661      use inds  (drop   =   idvar)   ;

1662      read    all var _num_   into    datamat ;
NOTE: I/O required temporary file to be opened.
1663      optn    =   j(8,1,.)    ;
1664      optn[1] =   0   ;
1664!                             /*  print nothing   */
1666      CALL    MCD(sc,xmcd,dist,optn,datamat)  ;
1668      colnams =   {"mahalanobis"  "robust"    "q975weight"}   ;
1670      create  distout   from    dist[colname    =   colnams]    ;

NOTE: Initial allocation of symbol space exhausted. You may specify
      statement to increase its allocation for more efficiency.
1672  quit    ;
NOTE: Exiting IML.
NOTE: The data set DISTOUT has 0 observations and 10000 variables.
      real time           22.28 seconds
      cpu time            5.87 seconds

1)  The data set, inds, has 10,000 records and around 400 variables.
2)  All the variables are numeric, and all except the id variable
("idvar") are to be used in the MCD procedure.  I dropped the idvar in
order to keep it out of the MCD procedure.  I would prefer to keep it and
not use it, but if the output comes out in the right order, it doesn't
3)  The dist matrix should have 10,000 rows and three columns.  The three
columns are mahalanobis distance, robust distance, and weight (in that
order, according to the documentation).
4)  I want to output the dist matrix to the data set, distout.
5)  I tried to provide names for the columns of distout by creating a
matrix of names, colnams, to be used in the create statement.  I didn't
find the documentation very helpful for this.
6)  I expected the output data set to have 10,000 rows and three columns.
As you can see, it has 10,000 columns (and came out empty).

How can I get what I want?


--  TMK  --
"The Macro Klutz"

7. Multiple ELSEs, was: Retain and Basic SAS help

8. Retain and Basic SAS help

The following code:

data cmp_7;
   set cmp_6;
   retain endshare;
   by ticker date;
   if then if ticker = '*$$$' then startshare = 0;

**  startshare depends on retained value of endshare;
   else if not then if ticker = '*$$$' then startshare =
**  endshare depends on new value of startshare;
    if ticker = '*$$$' then endshare = startshare + tot_dol_div


proc print data=cmp_7;
where ticker='*$$$';
var date ticker startshare endshare price tot_dol_div tot_sales

IS PROducing the following output:

tot_dol_      t_
   TICKER   startshare     endshare   PRICE      div       sales

   *$$$         0             0.00     1         0.00   9617604
   *$$$         0       -184845.50     1     17028.50    789484
   *$$$         0           675.25     1     20471.25    667704
   *$$$         0         42797.84     1     12244.84    760469
   *$$$         0         12764.50     1     12764.50         0

THE OUTPUT that I am trying to get is:

                0              0
                0        -184845.50
         -184845.50      -184170.25
         -184170.50      -141372.41
         -141372.41      -128607.91

all other numbers stay the same.

You will notice that in the actual ouput div + purchase + sales =

and the difference between what I'm getting is I'm not accumulating the
previous value of endshare.

I thought the retain would place the old value of endshare into
startshare and then I could add the last three columns to get the new
endshare.  I did something close to this before and it worked.  I think
the problem is with the staement if not but I'm not getting
an error.