Hello
I am using SAS9.4 on a Windows10 PC environment.
I am trying to create a string column to contain a full description by using a format within a PUT statement. I want the format name to be generated dynamically based on a value in a different column. This seems feasible but I can't quite nail it, example program attached.
I have this problem on a couple of programs so all help will be gratefully received, thank you.
/* T1002580 Using putc or putn with format names in your data
Using putc or putn with format names in your data
This seems to work
inspired by
https://goo.gl/ktxY1O
https://communities.sas.com/t5/Base-SAS-Programming/Dynamic-apply-format-by-making-the-fmtname-from-a-value-in-the/m-p/335244
HAVE
====
proc format;
value $ FMTA1X
"A" = "this was discount $10"
"B" = "this was discount $20"
;
value $ FMTA2X
"A" = "this was discount $300"
"B" = "this was discount $400"
;
run;
Up to 40 obs WORK.HAVE total obs=5
Obs PRODTYPE DISCOUNT
1 A1 B
2 A2 A
3 A2 A
4 A2 B
5 A1 B
WANT
====
Up to 40 obs WORK.DEMO_DESCRIPTION_HARDCODE total obs=5
Obs PRODTYPE DISCOUNT DISCOUNT_DESC
1 A1 B this was discount $20 putc(discount,$fmta1x.)
2 A2 A this was discount $300
3 A2 A this was discount $300
4 A2 B this was discount $400
5 A1 B this was discount $20
SOLUTION
========
data have;
input Prodtype $ Discount $;
cards4;
A1 B
A2 A
A2 A
A2 B
A1 B
;;;;
run;quit;
data want;
retain prodtype discount discount_desc;
length discount_desc $44;
set have;
fmt=cats('$fmt',prodtype,'x');
Discount_desc = putc(Discount,fmt);
run;quit;
Up to 40 obs WORK.WANT total obs=5
Obs PRODTYPE DISCOUNT DISCOUNT_DESC FMT
1 A1 B this was discount $20 $fmtA1x
2 A2 A this was discount $300 $fmtA2x
3 A2 A this was discount $300 $fmtA2x
4 A2 B this was discount $400 $fmtA2x
5 A1 B this was discount $20 $fmtA1x
Not possible.
The format is set when the data step is compiled, so formats need to be named literally.
From the documentation of the put() function:
format.
contains the SAS format that you want applied to the value that is specified in the source. This argument must be the name of a format with a period and optional width and decimal specifications, not a character constant, variable, or expression.
(Emphasis by me)
Read the documentation.
Post your examples as text in a code window ({i} above post). Is there a reason you want to try to automate it, you will need to have the list somewhere if so. If its just a couple then what you have is fine. To automate will take more code:
data fmts; length fmt_cond fmt $200; input fmt_cond $ fmt $; datalines; A1 $fmt2 A2 $fmt1 ; run; data _null_; set fmts end=last; if _n_=1 then call execute('data want; set have;'); call execute('if variable="'||strip(fmt_cond)||'" then res=put( ...); if last then call execute('run;'); run;
Just as an example, however I would really question why this is necessary at all.
PUTC/PUTN allow format names that are from a variable.
Borrowing code:
data fmts;
length fmt_cond fmt $200;
input fmt_cond $ fmt $;
datalines;
A1 $fmt2
A2 $fmt1
;
run;
Data want;
set fmts;
want_var = putc(fmt_cond, fmt);
Run;
I suspect you would also be well served by a hash lookup table, keyed on 2 vars: PRODTYPE and DISCOUNT. Make a lookup dataset, with all the expected combinations of prodtype,discount, and discount_desc. Then load it into a hash object to use in the data step:
data lookup;
input prodtype :$2. discount :$1. @6 discount_desc $30.;
datalines;
A1 A this was discount $10
A1 B this was discount $20
A2 A this was discount $300
A2 B this was discount $400
run;
data demo_description_dynamic (drop=rc);
set demodata;
if _n_=1 then do;
if 0 then set lookup;
declare hash h (dataset:'lookup');
h.definekey('prodtype','discount');
h.definedata(all:'Y');
h.definedone();
end;
rc=h.find();
if rc^=0 then call missing(discount_desc);
run;
When the h.find() method is successful, two things happen: RC=0 and discount_desc is retrieved from the desired item in hash object h. If it's unsuccessful, RC ^=0 and discount_desc is unchanged from the last successful h.find(). That's why you see discount_desc set to missing when rc^=0.
/* T1002580 Using putc or putn with format names in your data
Using putc or putn with format names in your data
This seems to work
inspired by
https://goo.gl/ktxY1O
https://communities.sas.com/t5/Base-SAS-Programming/Dynamic-apply-format-by-making-the-fmtname-from-a-value-in-the/m-p/335244
HAVE
====
proc format;
value $ FMTA1X
"A" = "this was discount $10"
"B" = "this was discount $20"
;
value $ FMTA2X
"A" = "this was discount $300"
"B" = "this was discount $400"
;
run;
Up to 40 obs WORK.HAVE total obs=5
Obs PRODTYPE DISCOUNT
1 A1 B
2 A2 A
3 A2 A
4 A2 B
5 A1 B
WANT
====
Up to 40 obs WORK.DEMO_DESCRIPTION_HARDCODE total obs=5
Obs PRODTYPE DISCOUNT DISCOUNT_DESC
1 A1 B this was discount $20 putc(discount,$fmta1x.)
2 A2 A this was discount $300
3 A2 A this was discount $300
4 A2 B this was discount $400
5 A1 B this was discount $20
SOLUTION
========
data have;
input Prodtype $ Discount $;
cards4;
A1 B
A2 A
A2 A
A2 B
A1 B
;;;;
run;quit;
data want;
retain prodtype discount discount_desc;
length discount_desc $44;
set have;
fmt=cats('$fmt',prodtype,'x');
Discount_desc = putc(Discount,fmt);
run;quit;
Up to 40 obs WORK.WANT total obs=5
Obs PRODTYPE DISCOUNT DISCOUNT_DESC FMT
1 A1 B this was discount $20 $fmtA1x
2 A2 A this was discount $300 $fmtA2x
3 A2 A this was discount $300 $fmtA2x
4 A2 B this was discount $400 $fmtA2x
5 A1 B this was discount $20 $fmtA1x
Thank you all for your contributions.
The other way I was looking at the problem was to use create a function (Proc FCMP) which would have been stored in one place and then reference across the different programs.
Don't miss out on SAS Innovate - Register now for the FREE Livestream!
Can't make it to Vegas? No problem! Watch our general sessions LIVE or on-demand starting April 17th. Hear from SAS execs, best-selling author Adam Grant, Hot Ones host Sean Evans, top tech journalist Kara Swisher, AI expert Cassie Kozyrkov, and the mind-blowing dance crew iLuminate! Plus, get access to over 20 breakout sessions.
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.