BookmarkSubscribeRSS Feed
Leo_2021
Fluorite | Level 6

Hello,

I have two datasets. The dataset have1 is original dataset. The have2 is the lateset dataset.

I hope to put different color onto corresponding records in order to display different status (added, deleted and modified) of each observation.

I do not know how to use this report function to make it work.

I do not know how to do this by ODS with destination is Excel file as well at the same time.

Could you please give me help?  Thank you in advance!

sorry, this is my first send question in the forum.  if my operation is incorrect,  please correct me. Thank you!

 

data test1;
input name & $12. age subject & $8. folderseq RecordPosition term & $48. rate ;
cards;
Frank 20 301001 1.0 1 Headache 5
Frank 20 301001 1.0 2 pain 5
Annie 31 301002 2.0 1 abc 4
Annie 31 301002 2.0 2 abcd 4
Jessica 38 301005 5.0 0 a1 3
;
run;
data test2;
input name & $12. age subject & $8. folderseq RecordPosition term & $48. rate ;
cards;
Frank 21 301001 1.0 1 headache 6
Frank 20 301001 1.0 2 pain 5
Annie 31 301002 2.0 1 abcd 4
Annie 31 301002 2.0 2 abcd 4
Andy 40 301004 4.0 0 b1 3
;
run;
data have1;
set test1;
run;
data have2;
set test2;
run;

%let key_col=subject folderseq RecordPosition;
/* %let compare_col=name age sex rate; */
%let key_col_cnt=%sysfunc(countw(&key_col));
/* Code to find compare column list - START */
proc contents data=have2 out=contents2 noprint;
run;

%macro where_cond;
%do i=1 %to &key_col_cnt;
%if &i < &key_col_cnt %then
%do;
%let col=%sysfunc(scan( &key_col,&i));
"&col" ","
%end;
%else
%do;
%let col=%sysfunc(scan( &key_col,&i));
"&col" ", "
%end;

%end;
%mend;

 

proc sql noprint;
select name into :compare_col separated by ' '
from contents2
where name not in (%where_cond);
quit;
%put COMPARE COLUMN = &compare_col ;
/* Code to find compare column list - END */


%macro select_col;
%do i=1 %to &key_col_cnt;
%let col=%sysfunc(scan( &key_col,&i));
coalesce(a.&col,b.&col) as &col,
%end;
%mend;

 

%macro join_cond;
%do i=1 %to &key_col_cnt;
%let col=%sysfunc(scan( &key_col,&i));
a.&col =b.&col and
%end;
%mend;


proc sort data=have1 out=have1_sorted;
by &key_col ;run;
proc sort data=have2 out=have2_sorted;;
by &key_col ;run;

proc transpose data=have1 out=have1_trans (rename= (_name_=col_name));
by &key_col ;
var &compare_col ;
run;

proc transpose data=have2 out=have2_trans(rename= (_name_=col_name)) ;
by &key_col ;
var &compare_col;
run;

proc sql;
create table compare_table
as
select %select_col
coalesce(a.col_name,b.col_name) as variable_name
,strip(a.col1) as old_val
,strip(b.col1) as new_val
,case when strip(a.col1) <> strip(b.col1) and a.subject= b.subject and a.folderseq =b.folderseq then 'Modified'
when strip(a.col1) <> strip(b.col1) and (a.subject='' or a.folderseq=.) then 'Added'
when strip(a.col1) <> strip(b.col1) and (b.subject='' or b.folderseq=.) then 'Deleted' end as remark

from have1_trans a
full join have2_trans b
on %join_cond
a.col_name = b.col_name;
quit;
Data compare_table_2;
set compare_table;
if remark in ("Added") then newval=strip(strip(new_val)||"|"||"added");
else if remark in ("Deleted") then newval=catx('|',"@","Deleted",old_val);
else if remark in ("Modified") then newval=catx('|',new_val,"Modified",old_val);
run;
/* Transpose second time */
proc transpose data=compare_table_2 out=have2_new_trans_2;
by subject FolderSeq RecordPosition;
*copy Subject FolderSeq RecordPosition;
var new_val newval remark;
id variable_name;
run;
/* OUTPUT */
proc report data=have2_new_trans_2 nowd;
column;
define/style={tagattr='Type:string'} display;
compute;
if scan(,2,'|')="Deleted" then do;
flyover2="deleted:"||kscan(,3,'|');
call define("","style={background=LIGHTRED flyover='"||strip(flyover2)"'}");
end;
endcomp;
quit;

 

Best Regards

Leo

3 REPLIES 3
ballardw
Super User

Please make sure that your code for data will work. The main message windows on this forum will reformat text and often result in code that won't run. That may mean paste into the forum and then copy back to your editor and see if it still runs.

Example when I copy your first data step and run it I get:

618  data test1;
619  input name & $12. age subject & $8. folderseq RecordPosition term & $48. rate ;
620  cards;

NOTE: Invalid data for age in line 622 1-5.
NOTE: Invalid data for folderseq in line 623 1-5.
NOTE: Invalid data for rate in line 624 1-5.
RULE:      ----+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+--
624        Annie 31 301002 2.0 2 abcd 4
NOTE: Invalid data errors for file CARDS occurred outside the printed range.
NOTE: Increase available buffer lines with the INFILE n= option.
name=Frank 20 301 age=. subject=20 30100 folderseq=. RecordPosition=31 term=301002 2.0 1 abc 4
rate=. _ERROR_=1 _N_=1
NOTE: LOST CARD.
626        ;
name=Jessica 38 3 age=. subject=  folderseq=. RecordPosition=. term=  rate=. _ERROR_=1 _N_=2
NOTE: SAS went to a new line when INPUT statement reached past the end of a line.
NOTE: The data set WORK.TEST1 has 1 observations and 7 variables.
NOTE: DATA statement used (Total process time):
      real time           0.00 seconds
      cpu time            0.00 seconds

Likely because spaces between values in the datalines have been removed or possibly tabs replaced. If you look at your posted code there are not 12 characters before the value of Age.

Paste code in a text or code box opened on the forum with either the </> or "running man" icon to preserve text example:

data test1;
input name $ age subject & :$8. folderseq RecordPosition term $ rate;
cards;
Frank   20 301001  1.0 1 Headache 5
Frank   20 301001  1.0 2 pain     5
Annie   31 301002  2.0 1 abc      4
Annie   31 301002  2.0 2 abcd     4
Jessica 38 301005  5.0 0 a1       3
;

Better is just provide the data you are trying to use for the report instead of making us run a bunch of extra code unless your question is whether that code is working properly. In which case tell us what you think is wrong with the results and at which step.

When the first data step failed I was not interested in fixing possible coding problems in that many lines of code to make a dataset.

 

This example uses a data set you should have available and does something similar to what I think you want.

Proc report data=sashelp.class;
   columns name sex age;    /*<=specify the names of the variables to use in desired order*/
   define name/display;     /*<=specify the role the variable plays display is show, group or order create groups*/
   define sex/ display;
   define age/ display;
   compute name;  /*<= specify the name of the column to modify and/or values to use*/
      /* this tests if the Cell will contain a given name*/
      if name in ('John' 'Alfred' 'Mary') then 
         /* the _col_ means modify the Column (i.e. Name column) by setting the
            background color to light blue*/
         call define(_col_,'style','style=[backgroundcolor=lightblue]');
      /* test if the variable has different values to highlight green*/
      else if name in ('Robert' 'Carol') then 
         call define(_col_,'style','style=[backgroundcolor=lightgreen]');
   endcomp;
run;

The online help for Proc Report has multiple examples. I suggest that start with some of those and make small modifications to see what happens (or fails, there are lots of interactions that won't work).

 

When you have working report code then place that part inside an ODS destination "sandwich" which means an Ods destination file and ods destination close after the output.

 

ods excel file="yourpath\filename.xlsx" <other options>;

Proc report data = ...
run;

<other procedures producing output if wanted>
ods excel close;

 

 

Leo_2021
Fluorite | Level 6

Thank you! I will make sure the code pasted can work in the forum future.  I will learn this example you given and then send update to you later.  Have a nice weekend! 

Regrads

Leo

Leo_2021
Fluorite | Level 6

Hello, I have updated code to add color and stick onto each column. but I have question yet.

Now the color only can add onto one column and then generate several reports.  Can the color add onto all columns at one time and generate only one report?   Any suggestion would be appreciated.

 

data test1;
input name & $12. age subject & $8. folderseq RecordPosition term & $48. rate ;
cards;
Frank 20 301001 1.0 1 Headache 5
Frank 20 301001 1.0 2 pain 5
Annie 31 301002 2.0 1 abc 4
Annie 31 301002 2.0 2 abcd 4
Jessica 38 301005 5.0 0 a1 3
;
run;
data test2;
input name & $12. age subject & $8. folderseq RecordPosition term & $48. rate ;
cards;
Frank 21 301001 1.0 1 headache 6
Frank 20 301001 1.0 2 pain 5
Annie 31 301002 2.0 1 abcd 4
Annie 31 301002 2.0 2 abcd 4
Andy 40 301004 4.0 0 b1 3
;
run;
data have1;
set test1;
run;
data have2;
set test2;
run;

%let key_col=subject folderseq RecordPosition;
/* %let compare_col=name age sex rate; */
%let key_col_cnt=%sysfunc(countw(&key_col));
/* Code to find compare column list - START */
proc contents data=have2 out=contents2 noprint;
run;

%macro where_cond;
%do i=1 %to &key_col_cnt;
%if &i < &key_col_cnt %then
%do;
%let col=%sysfunc(scan( &key_col,&i));
"&col" ","
%end;
%else
%do;
%let col=%sysfunc(scan( &key_col,&i));
"&col" ", "
%end;

%end;
%mend;

 

proc sql noprint;
select name into :compare_col separated by ' '
from contents2
where name not in (%where_cond);
quit;
%put COMPARE COLUMN = &compare_col ;
/* Code to find compare column list - END */


%macro select_col;
%do i=1 %to &key_col_cnt;
%let col=%sysfunc(scan( &key_col,&i));
coalesce(a.&col,b.&col) as &col,
%end;
%mend;

 

%macro join_cond;
%do i=1 %to &key_col_cnt;
%let col=%sysfunc(scan( &key_col,&i));
a.&col =b.&col and
%end;
%mend;


proc sort data=have1 out=have1_sorted;
by &key_col ;run;
proc sort data=have2 out=have2_sorted;;
by &key_col ;run;

proc transpose data=have1 out=have1_trans (rename= (_name_=col_name));
by &key_col ;
var &compare_col ;
run;

proc transpose data=have2 out=have2_trans(rename= (_name_=col_name)) ;
by &key_col ;
var &compare_col;
run;

proc sql;
create table compare_table
as
select %select_col
coalesce(a.col_name,b.col_name) as variable_name
,strip(a.col1) as old_val
,strip(b.col1) as new_val
,case when strip(a.col1) <> strip(b.col1) and a.subject= b.subject and a.folderseq =b.folderseq then 'Modified'
when strip(a.col1) <> strip(b.col1) and (a.subject='' or a.folderseq=.) then 'Added'
when strip(a.col1) <> strip(b.col1) and (b.subject='' or b.folderseq=.) then 'Deleted' end as remark

from have1_trans a
full join have2_trans b
on %join_cond
a.col_name = b.col_name;
quit;
Data compare_table_2;
set compare_table;
if remark in ("Added") then newval=strip(strip(new_val)||"|"||"Added");
else if remark in ("Deleted") then newval=catx('|',"@","Deleted",old_val);
else if remark in ("Modified") then newval=catx('|',new_val,"Modified",old_val);
else Newval=new_val;
run;
/* Transpose second time */
proc transpose data=compare_table_2 out=have2_new_trans_2;
by subject FolderSeq RecordPosition;
var new_val newval;
id variable_name;
run;
data temp1;
set have2_new_trans_2;
delim='|';
if scan(age,2,delim)="Modified" then flag='M';
else if scan(age,2,delim)="Added" then flag='A';
else if scan(age,2,delim)="Deleted" then flag='D';
run;

%let compare_col_cnt=%sysfunc(countw(&compare_col));
%put &compare_col;
%put &compare_col_cnt;
%macro check(var);
data temp2;
set have2_new_trans_2;
delim='|';
if scan(&var,2,delim)="Modified" then flag='M';
else if scan(&var,2,delim)="Added" then flag='A';
else if scan(&var,2,delim)="Deleted" then flag='D';
run;
%mend check;
*%check(name);
*%check(rate);
%Macro eachvar(compare_col_cnt,compare_col);
%LET nummem = &compare_col_cnt;
%LET memlist = &compare_col;
%do i=1 %to &nummem;
%let memname=%scan(&memlist,&i);
%Check(&memname);
%end;
%MEND eachvar;
%eachvar(&compare_col_cnt,&compare_col);
data temp3;
set temp2;
where flag ^="";
run;
data temp4(drop=delim);
set temp3;
run;
%Macro addcolor;
%do i=1 %to &compare_col_cnt;
%let var1=%scan(&compare_col, &i);
proc report data=temp4;
column _all_;
define _col_/display;
compute &var1;
if scan(&var1,2,'|') = "Modified" then do;
flyover2="modified:"||kscan(&var1,3,'|');
call define(_col_,"style","style={background=LIGHTBLUE flyover='"||strip(flyover2)||"'}");
&var1 = kscan(&var1,1,'|');
end;
else if scan(&var1,2,'|') = "Added" then do;
flyover2="added:"||kscan(&var1,1,'|');
call define(_col_,"style","style={background=LIGHTGREEN flyover='"||strip(flyover2)||"'}");
&var1 = kscan(&var1,1,'|');
end;
else if scan(&var1,2,'|') = "Deleted" then do;
flyover2="deleted:"||kscan(&var1,3,'|');
call define(_col_,"style","style={background=LIGHTRED flyover='"||strip(flyover2)||"'}");
&var1 = "";
end;
endcomp;
quit;
%end;
%mend addcolor;

/* output excel file */
ods excel
file="/home/leo.zhang/sasuser.v94/STUDY_TEST/MML_Compare.xlsx";
%addcolor;

ods excel close;

 

 

Thanks and Best Regards Leo

Ready to join fellow brilliant minds for the SAS Hackathon?

Build your skills. Make connections. Enjoy creative freedom. Maybe change the world. Registration is now open through August 30th. Visit the SAS Hackathon homepage.

Register today!
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
  • 3 replies
  • 543 views
  • 0 likes
  • 2 in conversation