- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
I have a data set with BY groups, and there is a variable with a sentence about each group:
data have ;
input id x sentence $50.;
cards ;
1 1 I am a sentence about BYgroup #1
1 2 I am a sentence about BYgroup #1
1 3 I am a sentence about BYgroup #1
2 4 I am a sentence about BYgroup #2
2 5 I am a sentence about BYgroup #2
2 6 I am a sentence about BYgroup #2
;
run ;
I'm using PROC REPORT by ID, and I want to use a LINE statement in a COMPUTE block to display the sentence after each group.
My first try was:
proc report data=have ;
col id x sentence ;
define id /order ;
define x /display ;
define sentence /display ;
by id;
compute after id;
line sentence $50. ;
endcomp ;
run ;
Which does not work. I guess because SENTENCE is null for the "after ID" line. Is that right?
So my second thought was to make SENTENCE an order variable, like:
proc report data=have ;
col id x sentence ;
define id /order ;
define sentence /order noprint;
define x /display ;
by id;
compute after sentence;
line sentence $50. ;
endcomp ;
run ;
Which does what I want.
But I'm wondering if there is a better way I could do this, without making SENTENCE an order variable?
I feel like I should be able to make a retained PROC REPORT temporary variable which holds the value SENTENCE, and then reference the temporary variable inside the COMPUTE AFTER ID block?
Next up: SAS Trivia Quiz hosted by SAS on Wednesday May 21.
Register now at https://www.basug.org/events.
Accepted Solutions
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
Hi:
No need for lag or for a dummy variable.
As long as your sentence is the same for every row (as you indicated), then you can test whether it's a _BREAK_ for IDVAR or not. Then you can grab the value of SENTENCE in a COMPUTE block for SENTENCE. I changed your data a bit because I never name variables the same as PROC REPORT options (there is an ID option) to avoid confusion. Don't stress over the red highlighting for the LENGTH statement in the COMPUTE block. PROC REPORT's syntax checking doesn't include LENGTH, but it is valid.
Hope this helps,
Cynthia
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
Does your Sentence variable have a non-missing value for every record in your actual data or is it only appearing once per by group? I ask that because of your use of the word "retain" in you thinking of a possible solution.
And can you provide your reason why an order variable is objectionable. I realize that your example is here is likely simpler than your actual report and it may help to know a bit about what issues the "order" causes.
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
My sentence variable appears on every record, as in the example, and is constant within by-group.
The order variable is not objectionable (I don't think, will see how far I get with the real example), just didn't know if this was a silly way to approach the problem.
By "retain" I meant I feel like I should be able to create a temporary variable outside of the compute after block and use it to store the value of sentence from the last read detail row, and then use it inside of the compute after block to write the summary line. So I was playing a little with ugly stuff like:
proc report data=have ;
col id x sentence z;
define id /order ;
define x /display ;
define sentence /display ;
define z/ computed noprint;
compute z;
foo=sentence ; *assign value of sentence to temp var foo ;
endcomp ;
compute after id;
line foo $50. ; *print temp var foo - but its null;
endcomp ;
by id;
run ;
So I was thinking there must be a way to compute a temporary variable outside of the compute after block, and then "retain" it so that it can be used inside the compute after block. But maybe that's not the way temporary variables work.
Next up: SAS Trivia Quiz hosted by SAS on Wednesday May 21.
Register now at https://www.basug.org/events.
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
It's killing me that I left my so many of my SAS books at the office when we left for extended COVID-19 distancing. I may have to make my first trip back to the office this weekend, just to pick up Art's PROC REPORT book... Or I guess I could by a copy for home...
Next up: SAS Trivia Quiz hosted by SAS on Wednesday May 21.
Register now at https://www.basug.org/events.
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
Hi @Quentin,
The LAG function could provide the desired "retain" functionality, but I don't think that this is more elegant than your own concise solution:
proc report data=have;
col id x sentence;
define id /order ;
define x /display ;
define sentence /noprint;
by id;
compute sentence;
sentence=lag(sentence);
endcomp ;
compute after id;
line sentence $50. ;
endcomp ;
run ;
It overwrites variable sentence, but you could define sentence=coalescec(sentence, lag(sentence)) if that was a problem.
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
Thanks much @FreelanceReinh ,
That helps a lot (at least points out how little I understand PROC REPORT timing).
Below variant works, creating a temp variable from lag():
proc report data=have;
col id x sentence;
define id /order ;
define x /display ;
define sentence /display;
by id;
compute sentence;
mysentence= lag(sentence);
endcomp ;
compute after id;
line mysentence $50. foo;
endcomp ;
run ;
So that demonstrates that temporary variables created in one compute block can be used in a separate compute block, which makes sense.
I guess it also means that the code inside the compute sentence block executes for the compute after row. Which I hadn't expected. I definitely need to read up on the inner workings of PROC REPORT.
Next up: SAS Trivia Quiz hosted by SAS on Wednesday May 21.
Register now at https://www.basug.org/events.
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
Hi:
No need for lag or for a dummy variable.
As long as your sentence is the same for every row (as you indicated), then you can test whether it's a _BREAK_ for IDVAR or not. Then you can grab the value of SENTENCE in a COMPUTE block for SENTENCE. I changed your data a bit because I never name variables the same as PROC REPORT options (there is an ID option) to avoid confusion. Don't stress over the red highlighting for the LENGTH statement in the COMPUTE block. PROC REPORT's syntax checking doesn't include LENGTH, but it is valid.
Hope this helps,
Cynthia
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
Thanks @Cynthia_sas , that's a tremendous help (as always!).
In my journey through the documentation, I did re-read most of:
which does a nice job of defining temporary variables, and also does document that they are automatically retained:
PROC REPORT retains the value of a temporary variable from the execution of one compute block to another.
Next up: SAS Trivia Quiz hosted by SAS on Wednesday May 21.
Register now at https://www.basug.org/events.