ODS and Base Reporting

Build reports by using ODS to create HTML, PDF, RTF, Excel, text reports and more!
BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.

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?

The Boston Area SAS Users Group is hosting free webinars!
Next up: SAS Trivia Quiz hosted by SAS on Wednesday May 21.
Register now at https://www.basug.org/events.
1 ACCEPTED SOLUTION

Accepted Solutions
Cynthia_sas
SAS Super FREQ

Hi:

  No need for lag or for a dummy variable.

Cynthia_sas_0-1591385550693.png

 

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

View solution in original post

7 REPLIES 7
ballardw
Super User

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.

Quentin
Super User

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.

The Boston Area SAS Users Group is hosting free webinars!
Next up: SAS Trivia Quiz hosted by SAS on Wednesday May 21.
Register now at https://www.basug.org/events.
Quentin
Super User

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...

The Boston Area SAS Users Group is hosting free webinars!
Next up: SAS Trivia Quiz hosted by SAS on Wednesday May 21.
Register now at https://www.basug.org/events.
FreelanceReinh
Jade | Level 19

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.

Quentin
Super User

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.

The Boston Area SAS Users Group is hosting free webinars!
Next up: SAS Trivia Quiz hosted by SAS on Wednesday May 21.
Register now at https://www.basug.org/events.
Cynthia_sas
SAS Super FREQ

Hi:

  No need for lag or for a dummy variable.

Cynthia_sas_0-1591385550693.png

 

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

Quentin
Super User

Thanks @Cynthia_sas , that's a tremendous help (as always!).

 

In my journey through the documentation, I did re-read most of:

https://documentation.sas.com/?docsetId=proc&docsetTarget=n1gb1fq6jc5syxn162qoa8k6kc20.htm&docsetVer...

 

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.

The Boston Area SAS Users Group is hosting free webinars!
Next up: SAS Trivia Quiz hosted by SAS on Wednesday May 21.
Register now at https://www.basug.org/events.

sas-innovate-white.png

Our biggest data and AI event of the year.

Don’t miss the livestream kicking off May 7. It’s free. It’s easy. And it’s the best seat in the house.

Join us virtually with our complimentary SAS Innovate Digital Pass. Watch live or on-demand in multiple languages, with translations available to help you get the most out of every session.

 

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.

SAS Training: Just a Click Away

 Ready to level-up your skills? Choose your own adventure.

Browse our catalog!

Discussion stats
  • 7 replies
  • 5703 views
  • 4 likes
  • 4 in conversation