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

 

Dear All,

 

I have a macro generated automatically from the sas environment(measures).

I need to get the macro through sas dictionary.macros.

As the length of the macro is too large, the value column cannot accommodate the contents. I hope the default length is 200(showing in the offset column). I need the 4 rows in to one.

macros.PNG

 

The change in the length of value column is not possible(see the program).

 

Can you please help?

 

Program:

/*below is the amcro which i declared manually(automatically created)*/

%let measures=BUILDINGS_IOTRM CONTENTS_IOTRM TIME_ELEMENT_IOTRM BUILDINGS_IOTRM_AVG CONTENTS_IOTRM_AVG TIME_ELEMENT_IOTRM_AVG PTRM_CNT PTRM PTRM_AVG BUILDINGS_PTRM_CNT BUILDINGS_PTRM BUILDINGS_PTRM_AVG CONTENTS_PTRM_CNT CONTENTS_PTRM CONTENTS_PTRM_AVG STOCK_PTRM_CNT STOCK_PTRM STOCK_PTRM_AVG APPURT_STRUCT_PTRM_CNT APPURT_STRUCT_PTRM APPURT_STRUCT_PTRM_AVG COMBINED_PROP_PTRM_CNT COMBINED_PROP_PTRM COMBINED_PROP_PTRM_AVG TIME_ELEMENT_PTRM_CNT TIME_ELEMENT_PTRM TIME_ELEMENT_PTRM_AVG IOTRM_CNT IOTRM IOTRM_AVG BUILDINGS_IOTRM_CNT CONTENTS_IOTRM_CNT STOCK_IOTRM_CNT STOCK_IOTRM STOCK_IOTRM_AVG APPURT_STRUCT_IOTRM_CNT APPURT_STRUCT_IOTRM APPURT_STRUCT_IOTRM_AVG COMBINED_PROP_IOTRM_CNT COMBINED_PROP_IOTRM COMBINED_PROP_IOTRM_AVG TIME_ELEMENT_IOTRM_CNT;

proc sql;

create table vars as

select name,offset,value as value1 length 10000 from dictionary.macros

where scope eq 'GLOBAL';

 

/* create table macro_variables as*/

/* select catx(' ','%let ',strip(name),'=',strip(value),';') as statement length 700,*/

/* catx(' ','%global', strip(name)) as global_statement length 100*/

/* from vars;*/

quit;

 

Thanks,

Chithra

1 ACCEPTED SOLUTION

Accepted Solutions
Tom
Super User Tom
Super User

Use the SYMGET() function to retrieve the value of a macro variable.

data vars ;
  length name $32 value $32767 ;
  set sashelp.vmacro ;
  where scope='GLOBAL';
  by name notsorted ;
  if first.name;
  value=symget(name);
  keep name value;
run;

But note that macro variables can be up to 64K bytes and datasetp variables can only be 32K bytes.  You could use RESOLVE() to get the macro variable's length and so be able to create two dataset variables so that you could store macro variable values longer than 32K.

data vars ;
  length name $32 length 8 value1 value2 $32767 ;
  set sashelp.vmacro ;
  where scope='GLOBAL' ;
  by name notsorted;
  if first.name;
  length=input(resolve(cats('%length(%superq(',name,'))')),32.);
  value1=symget(name);
  if length > 32767 then value2 = resolve(cats('%qsubstr(%superq(',name,'),32768)'));
  keep name length value1 value2;
run;

Example result:

365   proc print;
366    where name='TESTVAR';
367   run;

WARNING: Data too long for column "value1"; truncated to 103 characters to fit.
WARNING: Data too long for column "value2"; truncated to 103 characters to fit.
NOTE: There were 1 observations read from the data set WORK.VARS.
      WHERE name='TESTVAR';

Obs  name      length

 58 TESTVAR     35177

Obs                                                 value1

 58 Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut bibendum ullamcorper consequat. Nulla ut co

Obs                                                 value2

 58 endum dignissim.  Morbi tincidunt at quam eu placerat. Ut felis turpis, suscipit ac metus id, pellentes

image.png

 

Also note that if you are running inside a macro, so that one or more local symbol tables are currently active, then SYMGET() and RESOLVE() might not be able to fetch the value from the global symbol table.  If you need to retrieve values for macro variables that are hidden by more local macro variables then use this utility macro:

https://github.com/sasutils/macros/blob/master/symget.sas

 

View solution in original post

8 REPLIES 8
RW9
Diamond | Level 26 RW9
Diamond | Level 26

Why?  Macro isn't the place for data.  Variable lengths can only go up to 2000, and long macro strings get split up into shorter blocks.  Put data in datasets which are unlimted in size.  There are numerous methods for working with lists of variables available in Base SAS, such as:

_all_

_numeric_

_character_

varprefix:

firstvar--lastvar

etc.

chithra
Quartz | Level 8

Thanks for your reply.

 

But here the case is something different right?

The macro which I declared manually in the example was just for reference. This macro (measures) is something which is get via sas webservice which I declared manually here. Through dictionary.macros I can get these values of macros.

LinusH
Tourmaline | Level 20

I still think there is a why (you need to get it from dictionary.macros).

What is the application (more than it is a web service involved)?

You could however get the macro variable name from the dictionary, but then fetch the actual value from the macro variable itself (which could be up to 32k in size).

Data never sleeps
chithra
Quartz | Level 8

Yes. Thanks. But instead of macro I does the concatenation in the data step

 

I modified the script like below.

 

proc sql;

create table vars as

select name,value from dictionary.macros

where scope eq 'GLOBAL';

quit;

 

proc sort data=vars;

by name;

quit;

 

data want(drop=value rename=(concatenate=value));

length concatenate $ 10000;

do until (last.name);

set vars;

by name;

concatenate = strip(concatenate)||strip(value);

end;

run;

 

Astounding
PROC Star

You can rebuild the macro variable by copying from dictionary.macros:

 

proc sql;

select value into : measures separated by ''

from dictionary.macros where
name='MEASURES' and scope='GLOBAL';

quit;

 

It's important that the "separated by" is null ... two quotes without a blank between the quotes.  That's one of the few places in the software where it makes a difference.

chithra
Quartz | Level 8

Thanks for your reply.

Instead of macro, I used this in the data step itself.

Tom
Super User Tom
Super User

Use the SYMGET() function to retrieve the value of a macro variable.

data vars ;
  length name $32 value $32767 ;
  set sashelp.vmacro ;
  where scope='GLOBAL';
  by name notsorted ;
  if first.name;
  value=symget(name);
  keep name value;
run;

But note that macro variables can be up to 64K bytes and datasetp variables can only be 32K bytes.  You could use RESOLVE() to get the macro variable's length and so be able to create two dataset variables so that you could store macro variable values longer than 32K.

data vars ;
  length name $32 length 8 value1 value2 $32767 ;
  set sashelp.vmacro ;
  where scope='GLOBAL' ;
  by name notsorted;
  if first.name;
  length=input(resolve(cats('%length(%superq(',name,'))')),32.);
  value1=symget(name);
  if length > 32767 then value2 = resolve(cats('%qsubstr(%superq(',name,'),32768)'));
  keep name length value1 value2;
run;

Example result:

365   proc print;
366    where name='TESTVAR';
367   run;

WARNING: Data too long for column "value1"; truncated to 103 characters to fit.
WARNING: Data too long for column "value2"; truncated to 103 characters to fit.
NOTE: There were 1 observations read from the data set WORK.VARS.
      WHERE name='TESTVAR';

Obs  name      length

 58 TESTVAR     35177

Obs                                                 value1

 58 Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut bibendum ullamcorper consequat. Nulla ut co

Obs                                                 value2

 58 endum dignissim.  Morbi tincidunt at quam eu placerat. Ut felis turpis, suscipit ac metus id, pellentes

image.png

 

Also note that if you are running inside a macro, so that one or more local symbol tables are currently active, then SYMGET() and RESOLVE() might not be able to fetch the value from the global symbol table.  If you need to retrieve values for macro variables that are hidden by more local macro variables then use this utility macro:

https://github.com/sasutils/macros/blob/master/symget.sas

 

chithra
Quartz | Level 8

Many Thanks for your explanation.

I rewrite as per your writings.

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
  • 8 replies
  • 1944 views
  • 0 likes
  • 5 in conversation