Hi: What you want cannot be done with TABULATE. It ALWAYS merges the row area cells, unlike PROC REPORT or PROC PRINT, which do NOT merge the cells for detail reports. PROC REPORT will perform spanned rows, if you want it to but you have to ask for it. Anyway, the default will show empty row header cells for GROUPED reports, but you can make a "helper" variable to fill every row using a COMPUTE block. The challenge with outputting TABULATE to a dataset and then trying to print it is that the dataset will be "flattened" and not in the same structure as the tabulate cross-tab -- which, I assume is the output structure you want. But without any data to test against, it is hard to come up with code. And, you did NOT explain how you were getting your output into Excel -- ODS HTML, ODS TAGSETS.EXCELXP, ODS CSV?? -- the Excel file that you posted could be either HTML or TAGSETS.EXCELXP -- you did not say which. But, let's assume that your variables are called OPTA, GRP, N1, then your PROC REPORT code would look like the program below. In the PROC REPORT part of the program, a "helper" column is created called DISPA -- it is meant to display the value of OPTA for every row. To make life easy, I made OPTA and DISPA both character. At the beginning of each value of OPTA, the variable value is grabbed and put into a temporary variable called HOLDIT. Then in the COMPUTE block for DISPA, the HOLDIT variable is used to fill the value of DISPA on that row. Since DISPA is now a duplicate of OPTA, except with a value on every row, the OPTA variable can be hidden with the NOPRINT option. The PROC REPORT code needs COMPLETEROWS so that you will see A, B, C, D, etc, on every row, even if there is no value for GRP on that row (which is not the case in my fake data, but appears to be the case in your data). In your TABULATE output, the cells without any counts were set to missing, PROC REPORT sets those values to 0. In the absence of any data from you, I made some fake data using SASHELP.SHOES. I also put in subtotals and an overall report total and a summary column on the far right and "reader breaks" between every group on the report. cynthia ** make some fake data; data fakedata(keep=opta grp n1 sales); length opta $4 grp $1; set sashelp.shoes; where stores le 26; ** make N1; n1 = stores; ** make OPTA; if substr(region,1,1) = 'A' then opta = '4005'; else if substr(region,1,1) = 'C' then opta = '4003'; else if substr(region,1,1) in ('E', 'M') then opta = '4004'; else if substr(region,1,1) in ('P', 'S') then opta = '4002'; else opta = 4006; ** make GRP; if product = 'Slipper' then product = 'A'; else if product = "Men's Casual" then product = 'C'; else if product = "Women's Casual" then product = 'F'; else if product = 'Sandal' then product = 'G'; grp = substr(product,1,1); ** label variables; label opta = 'Option A' grp = 'Group' n1 = 'N1'; format sales comma10.; run; proc sort data=fakedata; by opta grp; run; ods listing close; title; ods tagsets.excelxp file='c:\temp\toExcel.xml' style=printer; proc report data=fakedata completerows nowd; column opta dispa grp n,n1 sales=tot; define opta / group noprint order=data; define dispa / computed 'Option A' style(column)=Header; define grp / group style(column)=Header; define n1 / across; define n / ' '; define tot / n 'Total' f=comma10.; compute before opta; holdit = opta; endcomp; compute dispa / character length=14; dispa=holdit; endcomp; break after opta / summarize style=Header; rbreak after / summarize style=Header; compute after; dispa = 'Total'; endcomp; compute after opta; ** custom text at subtotal; dispa = catx(' ',holdit,'Total'); ** blank line at subtotal; line ' '; endcomp; run; ods _all_ close;
... View more