You are on page 1of 44

Blogs

Long texts in SAP BW: Modeling


Eugene Khusainov
Business Card
Posted on May. 27, 2006 12:26 PM in Beginner, Business Intelligence
(BI)

Subscrib
e
Print
Permali
nk

The questions about representing in BW the texts longer than 60 symbols almost disappeared in BI forums. I
hope that my detailed posting with explanation of how to do it was not the least reason of it:
Link to the posting
However, the questions about formatting workbooks and representing long texts are still there. It was the main
motive for writing this blog. I'm going to demonstrate how to show long texts in Business Explorer Analyzer. Also
it is to be an introduction to formatting workbooks in Excel using Visual Basic for Applications (VBA) code. The
code is based on the modeling scheme for long texts that I proposed in my posting. That's why I'll explain this
scheme again as a prerequisite for formatting with my VBA code.
As a side effect, itll be shown how to use a flexible infosource for simultaneous upload of texts and attributes
(master data).
Suppose, for simplification, that we need to keep in SAP BW the long text (description) with length of 240
characters and show this text in Business Analyzer workbook.
I often encountered such an approach when this long description has been cut in four parts, 60-symbol peaces
each (due to the well-known limitation of SAP BW), and been kept as characteristic values of four infoobjects,
type of CHAR 60.
I don't like this approach, because:

it's difficult to display this long text in queries and workbooks as a whole

it's impossible to have such long descriptions time or language dependent

it's somewhat slower to retrieve from the database long alphanumeric keys.

there is no problems with lowercase and uppercase in reports.

All this is enough for me to come up with another approach.


I also use four infoobjects (hereinafter referred to as IOs). But, the peaces of the long text are kept in the long
texts of the IOs, not in their characteristic values (keys).
We will create three IOs and assign them as attributes of the one, basic (master) infoobject. The advantage of
this - we dont have to pass to the infoprovider all four IOs. We load in there just one, master infoobject.
I will demonstrate it on the example of the long description of foreign trade goods groups. The picture below
shows an Excel file prepared for data load. Notice, that some description lengths definitely exceed 60
characters.

So, here we go.


First, we create an infoobject for the 2nd part of the description. There is no need to create it as CHAR 60,
because we will keep the peaces of the long description (60 symbols each) in the long texts, totaling 240
characters maximum length. It is even more convenient to determine each IO as NUMC 2 (the natural code of
the goods group).

Since we are not going to use the peaces of the long description for displaying separately, sorting or analyzing;
we declare them as Attribute Only.
Uncheck With master data flag since our attributes will not have their own attributes. And you see also that our
texts are going to be language-dependent.

Create the 3rd and 4th parts, ZGROUP_3 and ZGROUP_4 infoobjects similarly.
Finally, create the master/basis infoobject ZGROUP_1 which will have all the three created earlier infoobjects as
attributes.
The master IO has the same type and features, except the following:
Attribute Only flag unchecked
With master data flag is checked
In the Attributes tab of the infoobject include all the three created IOs.

Activate it.
Create an infosource with the shown below IOs.
Assign the flat file source system.
In case of flat file source system, the transfer structure (hereinafter referred to as TS) and transfer rules are
generated automatically by the system which uses the communication structure (hereinafter referred to as
CS) as a template. Hence, the sequence of fields in the CS is important.

In order to load four peaces of the long description we need to have four infoobjects of CHAR 60 type. Well not
need them after load. Thats why we are not creating such IOs. We use the system standard infoobjects like
0ADDR_LINEx (or similar) instead.
Notice, that in the TS we increased the length of the 0ADDR_LINE1 infoobject to 240 symbols. It is allowed in the
TS. Doing so, we can upload just three fields, as has been shown in the first picture. The 3rd field will carry the
whole 240-symbol long description. The rest of fields are to be empty.
Create a start routine in transfer rules. Place there the following code.

This code cuts the three peaces from the long description and put them into 0ADDR_LINE2, 0ADDR_LINE3 and
0ADDR_LINE4. Pay attention to that there is no need to do it for the first peace. The 0ADDR_LINE1 infoobject will
accept the whole 240-symbol long text, which will be truncated to 60 characters in update rules (hereinafter
referred to as URs).

Recall the data flow during the load:


TS (PSA table) -> Start routine in Transfer Rules (if any) -> Transfer rules -> CS -> Start routine in URs (if any) ->
URs of the Data Target.
Behold that in the Transfer Rules incoming from the source system fields values are transferred into CS fields as
1:1. But, our flat file has one column with 240-symbol description only. The following three columns are empty. It
doesnt matter because our start routine works out before the Transfer Rules. The routine will provide the
dissected texts for the last three fields (as if they came from the source system itself).
There are two options.
1. If you have a CSV-file with all four peaces (60-symbol each) of the description placed in the separate columns,
you may not increase the length of the ZGROUP_1 length to 240 symbols and not use the start routine.
2. Instead of start routine in transfer rules we may use routines for the three attributes. The code in them is the
following.
RESULT = TRAN_STRUCTURE-ADDR_LINE1+60(60). for 0 ADDR_LINE2.
RESULT = TRAN_STRUCTURE-ADDR_LINE1+120(60). - for 0 ADDR_LINE3.

RESULT = TRAN_STRUCTURE-ADDR_LINE1+180(60). - for 0 ADDR_LINE4.


Incoming into 0ADDR_LINE1 240-symbol text will be truncated automatically to 60 characters.
Since we use a flexible infosource for simultaneous load of texts and attributes, we need to insert our IOs as
data targets. We do it in Infoproviders area of RSA1.

Insert all four infoobjects.


Refresh the screen.
After that we see five data targets, four for texts and one for attributes.

Create URs for the attribute data target (ZGROUP_1 infoobject) based on the infosource weve been created.

We see that rules for the attributes are grayed out. Click on either of grayed out crosses.

Choose Overwrite as Update type, and Source Field as Update Method. Select ZGROUP_1 infoobject as the
source field.

Click on the Key Fields tab to make sure that the source field for the Key Field has an assignment as shown
below.

Repeat the same procedure for all attributes. Now all grayed out crosses should look like green triangles.
Activate the rules.

Create URs for the text data target of ZGROUP_1. Click on the grayed out cross.

Again, choose Overwrite and Source Field. Make sure that you choose 0ADDR_LINE1 infoobject as a source
field.

The Key Fields tab will have two infoobjects. Leave them as they are.

Repeat creation of URs for ZGROUP_2, choosing 0ADDR_LINE2 as a source field.

One of the rows in the Key Fields tab will have the blank assignment.

Choose ZGROUP_1 (not ZGROUP_2!) as a source.

Repeat the same for the rest of the text data targets, selecting appropriate infoobject for the source field of
Update Method and ZGROUP_1 as the source for the Key Field.
Create an infopackage. Make sure that you see in the Data Targets tab all five targets, four for texts, and one
for attributes.

Load data.
In the Infoobjects area of RSA1, from the context menu of ZGROUP_1 execute Manage Master Data option.
Youll see that the long text has been truncated, and all attributes have the same values as this infoobjects
characteristic value.

Master data for the ZGROUP_2 will show that its long text contains the second part of the long description. The
blank texts for some rows mean that the first part of the long description was less than 61 character long.

The similar is true for the 3rd and 4th peaces.


Create an infoprovider. Load into it some transaction data containing our ZGROUP_1 infoobject.
Now we are ready for a query creation and formatting a workbook. See the next blogs:
Long texts in SAP BW: Modeling Follow Up
Long Texts in SAP BW: Displaying in BEx Analyzer. Introduction to Excel Workbooks Formatting. Part I.
Long Texts in SAP BW: Displaying in BEx Analyzer. Introduction to Excel Workbooks Formatting. Part II.

Eugene Khusainov
Add to: del.icio.us | Digg | Reddit

Comment on this weblog


Showing messages 1 through 12 of 12.

Titles Only
Main Topics
Oldest First
Characteristic description is more then 300 Characters we want to report this in BEX., it will come
more then 600 and may be more then 1000 characters it is not fixed

2006-06-21 05:45:47 mohan ramavath Business Card [Reply]


Hi,

can you help me on this issue.


We receiving data from source (SAP CRM) systems to SAP BW, Characteristic description is more then 300
Characters we want to report this in BEX.
Description of a charactristic from source system to BW will come more then 600 and may be more then 1000
characters it is not fixed.
Our problem is how to pull data into BW?
How to take Report on this pulled data?
Please suggest or give me a solution for this kind issues how to resolve.
Regards
Mohan

Why 60 Characters in the first place?


2006-05-29 04:33:21 Arun Varadarajan Business Card [Reply]
This blog raises some questions ,
Why 60 characters in the first place ?

I too had to resolve to splitting the charaters into 60 each and then using the table modifier , displaying them
together , and also if you want to you can change the long text length to 240 by using an SAP access key and
then storing the same in the long text of the info object but alas , reporting will not let you display more than
60...
Arun

Why 60 Characters in the first place?


2006-06-21 05:44:29 mohan ramavath Business Card [Reply]
Hi,

can you help me on this issue.


We receiving data from source (SAP CRM) systems to SAP BW, Characteristic description is more then 300
Characters we want to report this in BEX.
Description of a charactristic from source system to BW will come more then 600 and may be more then 1000
characters it is not fixed.
Our problem is how to pull data into BW?
How to take Report on this pulled data?
Please suggest or give me a solution for this kind issues how to resolve.
Regards
Mohan

Why 60 Characters in the first place?


2006-05-29 05:15:45 Eugene Khusainov
Hi Arun,

Business Card [Reply]

I didn't completely understand your question: "Why 60 Characters in the first place?".
60 chars as a BW limitation. Something wrong with it?
When you talk about table modifier, I presume that you referred to web reporting, didn't you?
Meanwhile I emphasized the BEx Analyzer workbooks formatting.
So...?
Best regards,
Eugene

Why 60 Characters in the first place?


2006-05-30 04:56:17 Dirk Herzog

Business Card [Reply]

I guess that Arun raised the question that every second customer of mine asks. Why did SAP limit the long text
to 60 characters? I guess that nobody thought that the people needed more than 60 characters. If you do the
thing that BW was originally intended to do, namely reporting SAP data, 60 characters is always enough. But BI
has grown beyond this.

Arun,
can you describe the table exit in a blog? Then we would have the complete solution, data model, excel and web
in three blogs.
Best regards
Dirk

Finally BI again
2006-05-29 02:17:26 Dirk Herzog

Business Card [Reply]

Hello Eugene,
finally a good blog on a typical BI topic. I'm really looking forward to reading more of it.

Best regards
Dirk

Finally BI again
2006-05-29 03:54:55 Eugene Khusainov

Business Card [Reply]

Thank you, Dirk. Trying to find extra time to finish the 2nd part related to workbooks formatting.

Best regards,
Eugene

Finally BI again
2006-06-09 23:45:56 Karthik Sundaram Business Card [Reply]

Hi Eugene,

While this is a very interesting blog, Im quite keen to know a non-workbook based solution. As you would be
aware, BI delivery is heading towards a web based portal solution, away from the workbook / Bex /excel
environment it would be nice to know of options in this front. We`ve had some instances where we used crystal
reports as a mean of handling long texts out of BW. There seems to be a growing demand on being able to
represent long texts as part of the BI solution.
Regards

Finally BI again
2006-06-14 17:46:05 Surya Muvvala Business Card [Reply]
Web:
This can be achieved with the help of some java scripting in Web Templates. In one of the projects we did this. I
think, this is working fine.

Excel:
In our project we adopted the same method for displaying long texts in work books for CRM data. But, this type
of solution is OK, if the length of the text is predefined may be around 200-300. This solution cannot be used for
situations to display the system logs/scripts or e-mail contents since the length of text is not pre-defined and
also length may go beyond 3000.
Thanks
Surya Muvvala

Finally BI again
2006-06-11 01:24:54 Eugene Khusainov

Business Card [Reply]

Hi Karthik,

I guess that your comment should have gone to my other two blogs concerning workbooks formatting.
I was surprised that no comments was published to them. And I thought that was mistaken when proposed that
the issue would be interesting.
Regarding your question about long texts presentation in web reporting - one day I'll try to cover this issue also.
Best regards,
Eugene

Characteristic description is more then 300 Characters we want to


report this in BEX.
2006-06-21 05:43:27 mohan ramavath Business Card [Reply]
Hi,

can you help me on this issue.


We receiving data from source (SAP CRM) systems to SAP BW, Characteristic description is more then 300
Characters we want to report this in BEX.
Description of a charactristic from source system to BW will come more then 600 and may be more then 1000
characters it is not fixed.
Our problem is how to pull data into BW?
How to take Report on this pulled data?
Please suggest or give me a solution for this kind issues how to resolve.
Regards
Mohan

Characteristic description is more then 300 Characters we


want to report this in BEX.
2006-06-21 06:01:18 Eugene Khusainov
Hi Mohan,

Business Card [Reply]

Never worked with CRM yet. Is it true that incoming field length is not fixed?
In general, if the length is fixed, you can use the same technics I described. Though, the number of additional
infoobject will be much more.
Best regards,
Eugene

Showing messages 1 through 12 of 12.

Blogs

Long texts in SAP BW: Modeling Follow Up


Eugene Khusainov
Business Card
Posted on Jun. 03, 2006 07:12 PM in Beginner, Business Intelligence (BI)

Subscrib
e
Print
Permali
nk

Though, I have stated in my first blog that questions about long texts in SAP BW almost disappeared,
Long texts in SAP BW: Modeling
one more appeared just recently. This time the load of long text was conducted from R/3 system. How to deal
with this issue is explained here. What will be said is applied to all source systems (including DB Connect)
except flat files.
In case of loading long description with 240-character length we have four fields in the datasource of the source
system. The first one bears the whole long description (AAA, BBB, CCC and DDD abbreviations designate the
parts of the long description, 60-characters length each). The other three, with 60-character length, may contain
any information (shown as XXX, YYY and ZZZ). Content of these fields is not important, they are simply
placeholders. What is important is the length of the fields.

After uploading data from the datasource, in BW information goes to transfer structure. Physically, it is so called
PSA table. Information is copied without any changes, 1:1.

During further load from PSA table to data target, the start routine in transfer rules works out first. In our case it
cuts out the long description in peaces of 60-symbol each and places them into corresponding fields
(infoobjects) of the communication structure. Actually, incoming from PSA table XXX, YYY and ZZZ information is
replaced by BBB, CCC and DDD on the fly.

Update rules of data targets take these peaces of the long description and place them in their long texts.
So, in general, the datasource should supply a field with the original long text and several fields with 60
characters length (placeholders). If you have such a datasource, then dealing with it is obvious. If you have not,
create it. The easiest way to do it is to create a generic datasource with a table or view.

VIEW Creation (SE11 t-code)

For demonstration purposes I found a table AQGTQ with 255-symbol TEXT field. For a placeholder I used the 80symbol TEXT field of AQGTS table. It doesnt matter that the length of this field is not 60 characters. What
matters is the fact that this length is greater than 59 characters. For simplification I cut out the long description
in two peaces, not four.
I choose mentioned above two fields during a view creation and named them as TEXT1 and TEXT2 in the view
definition.

In order to decrease the number records to be extracted from R/3, I joined the tables with the common key
INDX.

Generic Datasource Creation (RSO2 t-code)


I chose an application component and created view.

The length of the field INDX is NUMC 5 and I set Selection option for this field in the datasource.

Since our ZGROUP_x infoobjects have NUMC 2 type, this selection will allow me to restrict the records to be
transferred to BW by their key.

Further Steps
I generated the datasource in R/3.
Replicated it in BW.
Found the infosource I used for load long description from flat files.
Assigned to it my R/3 system as a source system and chose the datasource I just created.

In transfer rules I copied ZGROUP_1, 0ADDR_LINE1 and 0ADDR_LINE2 names from the left frame into blank
fields corresponding to INDX, TEXT1 and TEXT2 fields.
Since my datasource didnt provide the value for language field 0LANGU, I placed in transfer rule for this field a
formula which returned the logon language.

Transfer rules for the last two fields remained unassigned. It doesnt matter.
In the start routine in transfer rules I placed the following code. Notice, that it is the same code that I used
before save that the number of modified fields is less and field names in transfer structure are different.

In the Data Selection tab of an infopackage I restricted transferred records by the INDX value form 1 to 99.

The list of data targets was changed.

The rest is absolutely the same as in case of load from a flat file and has been described in the first blog.
About workbooks formatting see the blogs:
Long Texts in SAP BW: Displaying in BEx Analyzer. Introduction to Excel Workbooks Formatting. Part I.
Long Texts in SAP BW: Displaying in BEx Analyzer. Introduction to Excel Workbooks Formatting. Part II.

Eugene Khusainov
Add to: del.icio.us | Digg | Reddit

Comment on this weblog

Showing messages 1 through 12 of 12.

Titles Only
Thanks !!!

Main Topics

Oldest First

2006-06-04 23:08:26 Sankar Kumar Business Card [Reply]


Hello :) Eugene Khusainov,
How r u ?

We are facing this issue, like in the MS SQL some fields are varchar(600) even varchar(2000). But the data is not
so long as the length assigned. Say, 79 Chars is the Max for the field Varchar(600), what do u suggest in this
scenario ?
Thanks and Regards....
Sankar Kumar
+91 98403 47141
ksankar@kaar.in
www.kaar.in

Thanks !!!
2006-06-04 23:24:48 Eugene Khusainov

Business Card [Reply]

Hi Sankar,

In your case the datasource to be brought to BW is to be based on a view. If you are certain about maximum

number N of characters used, in the srcipt file creating the view use a function like LEFT (depends on the
particular SQL version) to bring just the left N symbols.
Best regards,
Eugene

Thanks !!!
2006-06-05 04:20:50 Sankar Kumar Business Card [Reply]
Once again Thanks !!! for the idea, we could create multiple view fields for one table field. Say if its
varchar(240) then 1 st calculate the LENGTH of that field in the whole table and take the maximum. So we can
decide how many View fields to create in the view.

Generating Data Sources will have the maximum view fields for that particular long field. Using SUBSTRING
function we can split the data in MS SQL itlself. Need not write any routine in BW side.
Just create IOs and load the data....
How about this idea ? do you feel this is better ?

Thanks !!!
2006-06-05 06:07:01 Eugene Khusainov

Business Card [Reply]

Sankar,

Certainly, if you can cut out the long description directly in the source system, it's the best approach.
You'll don't need any routines in BW. Just load these peaces to long texts of infoobjects.
Best regards,
Eugene

Thanks !!!
2006-06-05 23:56:59 Sankar Kumar Business Card [Reply]
Hey Eugene,
Can i post a Technical Article if it works ? I started the job. What you would suggest ?

I require one more information from you. From which source systems we will face this problem ? coz we are
dealing with MS SQL only as for now.
Thanks & Regards....
Sankar
ksankar@kaar.in
www.kaar.in

Thanks !!!
2006-06-06 00:29:03 Eugene Khusainov

Business Card [Reply]

Hi Sankar,

I assumed that you are working with non-SAP system through DB Connect. Is it correct?
Do you want to write an article on how to create views in the source system? Or something else?

Anyway, you'd better contact the SDN Team: sdn@sap.com with this question.
Best regards,
Eugene
PS. I don't get your question: "From which source systems we will face this problem?".

Thanks !!!
2006-06-06 01:25:58 Sankar Kumar Business Card [Reply]
Hi Eugene,

Yes, you are correct. We are working on MS SQL with DB Connect.


Here it is.... what i have planned to do
creating an application using webdynpro to check the MS SQL table for the varchar fields and identify the field(s)
length exceeding 60 Chars. Then it will automatically create the view for the table or tables, splitting the fields
which are above 60 chars into view fields. So the View in MS SQL will match with BW requirement.
Hope i am clear.... any suggessions ?
Sankar

Thanks !!!
2006-06-06 04:40:15 Eugene Khusainov

Business Card [Reply]

Sankar,

In general, it looks OK except one clarification.


Are going to create views for ALL long fields or just for some selected ones?
Best regards,
Eugene

Thanks !!!
2006-06-08 23:22:10 Sankar Kumar Business Card [Reply]
Hello :) Eugene,
How r u ? Believe i am a bit late.

I have asked our webdynpro people to create an application which will automatically check the table and create
the views accordingly for all the fields.
Let me explain with an example,
If the MS SQL table contains and length as below
mat_no | mat_name | mat_desc | mat_usage
10 25 100 240

then the view generated will be like this


MAT_NO | MAT_NAME | MAT_DESC1 | MAT_DESC2 |
10 25 60 40
MAT_USAGE1 | MAT_USAGE2 | MAT_USAGE3 | MAT_USAGE4
60 60 60 60
Is this fine ?
Best Regards....
Sankar Kumar

Thanks !!!
2006-06-09 02:43:08 Eugene Khusainov

Business Card [Reply]

Hi Sankar,

It's OK with your late reply. It's not really late.


Your view is very good.
Just rememebr that you is to create two sets of infoobjects: for description and usage.
Modify a comm structure accordingly. I think as placeholders in the comm struc you can use 0ADDR_LINE0 0ADDR_LINE7.
Insert your infoobjects as data targets and in the update rules map the fields appropriately.
I don't see any problems with implementation.
Best regards,
Eugene

Thanks !!!
2006-06-29 08:30:23 jimi ogun Business Card [Reply]
Eugene

If you have the long description in the PSA (coming from SAP source), would there be an option to create start
routines that would supply the newly created infoObjects? Is this an easy way out instead of creating views in
the source system?

Thanks !!!
2006-06-29 20:34:04 Eugene Khusainov

Business Card [Reply]

Hi Jimi,

Actually, the long text in PSA was what I work with and mentioned in the 1st part:
https://www.sdn.sap.com/irj/sdn/weblogs?blog=/pub/wlg/3761
Depending on placeholders presence in the transfer structure (PSA) we have two options:
1. Placeholders (with 60 chars length) are present. -> Use either a start routine or routines in transfer rules.

2. Placeholders are absent or don't have the length required. -> You may use routines in TRs only.
Best regards,
Eugene

Showing messages 1 through 12 of 12.

Blogs

Long Texts in SAP BW: Displaying in BEx Analyzer.


Introduction to Excel Workbooks Formatting. Part I.
Eugene Khusainov
Business Card
Posted on Jun. 05, 2006 07:36 AM in Beginner, Business Intelligence (BI)

Subscrib
e
Print
Permali
nk

Suppose, we implemented the long texts scheme as has been shown in my blog:
Long Texts in SAP BW: Modeling
We created an infoprovider, loaded data into it and want to create our first report.
For this we need to create a query first.

Creating a query
Launch SAP BEx Analyzer. Using either menu or icons open a query.

Locate and expand your infoarea looking for your cube. Since the cube has no queries built on it yet, it has not
been shown in the infoarea. To see it click on a New icon.

The screen is refreshed and you see your cube.

Suppose, we want to see the simplified report showing my goods groups codes and their long descriptions in
rows and some key figures and formulas in columns.

The column structure contains selections with my sales key figure restricted by a reporting or previous month
(entered through the user entry variable and an offset for the previous month) and an export/import flag. There
also two formulas calculated as ratios.
In rows I placed my ZGROUP_1 infoobject and selected its three attributes containing the three parts of the long
description. The first peace of the description will be also shown as a long text of the infoobject itself. To see not
only groups description but also a groups code I chose Display As option as Key and Text in ZGROUP_1
properties.

The query output


After saving the query and running it, I got this ugly looking report with peaces of long description shown
separately and a header and colors that doesnt comply with my requirements (I decreased the columns width

for more vivid apparition):

If this report is to be a one of many in the reporting package I must submit to any government/controlling
bodies, I have to make some manual manipulations, such as removing navigation block, setting up proper
colors, redrawing header and footer etc.
I hate to do this manually. To avoid it I wrote a Visual Basic code formatting my report.

Modifying the workbook


I have 3 worksheets in my workbook. I renamed them as follows.

The first, BEx worksheet, contains output of BEx query, as shown earlier.
The second sheet contains the formatted report template. And the last one formatted report itself.

The formatted report template

Template consists of three areas: a header, a format row and footer.


Header starts from the first row. The last row of it is designated in the template. The footers start and end rows
are also specified. During creation of the formatted report, both, the header and the footer are copied into the
output worksheet without changes, with all formatting done. You can place in the header area all the features
you need (proper descriptions, borders, fonts, merged cells etc.). Signatures of a chief accountant and a
manager may be placed in the footer. Here you can add some comments, remarks etc.

The Format Row


The format row contains all the formatting we want to see in the reports result area (except header and footer).
Since a Goods Group Description is to have the long text, we set up the property of this cell in the format row
with Wrap text flag. It also has the Italic font style.

Also for demonstration purposes we set up the font for the Export reported month column with red color and the
next column for previous month with the shown below borders.

Adding a button
There is a special SAPBEXonRefresh subroutine in BEx workbooks. We can place our formatting code in there.
Though, I dont like this. I prefer the workbook doesnt get refreshed during the opening. For I may want to see
the results of the last run (for the previous reporting period). Its suitable for me to get the formatted report on
demand, i.e. by pressing a button.
So, well add a button (a CommandButton standard Excel/VB object). First of all, make sure that your Control
Toolbox toolbar is shown:

Find a CommandButton icon in the toolbar.

Click on it, position cursor in the BEx worksheet to the place we want the button be. Pressing the mouse key
draw a rectangular and then release the mouse.
Edit the appeared button

giving the meaningful description.

Click somewhere out of the button leaving the edit object mode, and then double click on the button.
Youll be brought to the Visual Basic editor screen.

Make sure that you see the SAPBEX module.


If you dont see it, follow the next section.
As a variant, one can access the Excel VBA code using the following menu path.

Setting up Excel security


From the Excel menu path: Tools -> Options

choose Security tab and press Macro Security button.

In the next screen, on the Security Level tab make sure that the security level is set no higher than to Medium
level.

On the Trusted Publishers tab make sure that the Trust access to Visual Basic Project flag is set.

We are ready to implement the code. See the part II:


Long Texts in SAP BW: Displaying in BEx Analyzer. Introduction to Excel Workbooks Formatting. Part II.

Eugene Khusainov

Blogs

Long Texts in SAP BW: Displaying in BEx Analyzer.


Introduction to Excel Workbooks Formatting. Part II.
Eugene Khusainov
Business Card
Posted on Jun. 05, 2006 07:36 AM in Beginner, Business Intelligence (BI)

Subscrib
e
Print
Permali
nk

At last, we arrived to the VBA code.


See the first part here:
Long Texts in SAP BW: Displaying in BEx Analyzer. Introduction to Excel Workbooks Formatting. Part I.

SAPBEXonRefresh subroutine code


Double click in VBA Project area on SAPBEX module. You see the SAPBEXonRefresh subroutine. Its empty.

Replace the code, so the whole subroutine looks like the following.

Public gResArea As Range

Sub SAPBEXonRefresh(queryID As String, resultArea As Range)


Dim Worksheet1 As Worksheet

Set Worksheet1 = ThisWorkbook.Worksheets("BEX")


Worksheet1.Cells(2, 1).Value = resultArea.Name
Worksheet1.Cells(2, 2) = resultArea.Cells(1).row
Worksheet1.Cells(2, 3) = resultArea.Cells(1).Column
numCells = resultArea.Cells.Count
Worksheet1.Cells(2, 4) = numCells
Worksheet1.Cells(2, 5) = resultArea.Cells(numCells).row
Worksheet1.Cells(2, 6) = resultArea.Cells(numCells).Column

Set gResArea = resultArea


Set gResArea.Parent = resultArea.Parent
End Sub

Formatting code
The following is a code I placed into the CommandButton1_Click subroutine.

Private Sub CommandButton1_Click()


' Last Update 03.06.2006
' Eugene Khusainov, SAP CIS

Dim ws As Worksheet, Range1 As Range, obj As Object


Dim iRAFirstRow As Integer, iRAFirstCol As Integer
Dim iRALastRow As Integer, iRALastCol As Integer
Dim Worksheet1 As Worksheet, Worksheet2 As Worksheet, Worksheet3 As Worksheet
Dim DestRange As String, SrcRange As String

Dim iFooterFirstRow As Integer, iFooterLastRow As Integer, iFormatRow As Integer


Dim iLongText1 As Integer, iLongText2 As Integer
Dim sLongText As String

Dim iRptFirstDataRow As Integer, iRptLastDataRow As Integer

'number of columns with long description to be concatenated - 1


'the output columns will be less on this amount
Dim iColsToSkip As Integer

'***************************************************
' PARAMETERS TO BE CHANGED
iHeaderLastRow = 4

' Header Last Row

RptHeaderRowsToIgnore = 1 'Number of rows in the BEx output to ignore


iFooterFirstRow = 8
iFooterLastRow = 13

' Footer First Row


' Footer Last Row

iFormatRow = 6

' Format Row Number

iLongText1 = 2 ' First Column of Long Text


iLongText2 = 5 ' Last Column of Long Text
'***************************************************

Set Worksheet1 = ThisWorkbook.Worksheets("BEX")


Set Worksheet2 = ThisWorkbook.Worksheets("TEMPLATE")
Set Worksheet3 = ThisWorkbook.Worksheets("OUTPUT")

On Error Resume Next


Set ws = gResArea.Parent
If Err.Number > 0 Then
iRAFirstRow = Worksheet1.Cells(2, 2)
iRAFirstCol = Worksheet1.Cells(2, 3)
numCells = Worksheet1.Cells(2, 4)
iRALastRow = Worksheet1.Cells(2, 5)
iRALastCol = Worksheet1.Cells(2, 6)
Else
iRAFirstRow = gResArea.Cells(1).row
iRAFirstCol = gResArea.Cells(1).Column
numCells = gResArea.Cells.Count
iRALastRow = gResArea.Cells(numCells).row
iRALastCol = gResArea.Cells(numCells).Column
End If

On Error GoTo 0

' Determine the first resultArea row to copy


' skeeping number of rows in the BEx output header
iRAFirstRow = iRAFirstRow + RptHeaderRowsToIgnore

iRptFirstDataRow = iHeaderLastRow + 1
iRptLastDataRow = iHeaderLastRow + iRALastRow - iRAFirstRow + 1

' Clear the formatted report's output area


SrcRange = GetRange(1, 1) + ":" + GetRange(iRALastCol + 4, iRptLastDataRow + iFooterLastRow iFooterFirstRow + 1)
Worksheet3.Range(SrcRange).Clear

' Delete shapes


While Worksheet3.Shapes.Count > 0
Worksheet3.Shapes(1).Delete
Wend

' Copy Columns width


For J = 1 To iRALastCol
SrcRange = GetRange(J, 1)
Worksheet3.Range(SrcRange).ColumnWidth = Worksheet2.Range(SrcRange).ColumnWidth
Next

' Copy Header rows height


For J = 1 To iHeaderLastRow
SrcRange = GetRange(1, J)
Worksheet3.Range(SrcRange).RowHeight = Worksheet2.Range(SrcRange).RowHeight
Next

iColsToSkip = iLongText2 - iLongText1


' Copy Header
SrcRange = GetRange(1, 1) + ":" + GetRange(iRALastCol - iColsToSkip, iHeaderLastRow)
Worksheet2.Range(SrcRange).Copy Destination:=Worksheet3.Range(SrcRange)
Call CopyFontBorderRange(Worksheet2, Worksheet3, 1, iRALastCol - iColsToSkip, 1, iHeaderLastRow, 0)

' Footer
SrcRange = GetRange(1, iFooterFirstRow) + ":" + GetRange(iRALastCol - iColsToSkip, iFooterLastRow)
DestRange = GetRange(1, iRptLastDataRow + 1) + ":" + GetRange(iRALastCol - iColsToSkip, iRptLastDataRow iFooterFirstRow + iFooterLastRow + 1)
Worksheet2.Range(SrcRange).Copy Destination:=Worksheet3.Range(DestRange)

Call CopyFontBorderRange(Worksheet2, Worksheet3, 1, iRALastCol, iFooterFirstRow, iFooterLastRow,


iRptLastDataRow - iFooterFirstRow + 1)

' Copy entire result area (without header & fixed header columns)
If iLongText1 = 0 Then
' Texts without peaces of long description
Call CopyArea(iRAFirstRow, iRALastRow, 1, iRALastCol, 1, iRptFirstDataRow)
Else
' Texts with peaces of long description
Call CopyArea(iRAFirstRow, iRALastRow, 1, iLongText1 - 1, 1, iRptFirstDataRow)
Call CopyArea(iRAFirstRow, iRALastRow, iLongText2 + 1, iRALastCol, iLongText1 + 1, iRptFirstDataRow)
' Concatenate peaces of long description
I = iRptFirstDataRow
For J = iRAFirstRow To iRALastRow
sLongText = Worksheet1.Cells(J, iLongText1)
For k = iLongText1 + 1 To iLongText2
sLongText = sLongText + Worksheet1.Cells(J, k)
Next k
Worksheet3.Cells(I, iLongText1) = sLongText
I=I+1
Next J
End If
Call CopyFormatRow(iFormatRow, iRptFirstDataRow, iRptLastDataRow, iRALastCol - iColsToSkip, iLongText1)
End Sub

There are also several routines and a function.

Sub CopyArea(srcFirstRow As Integer, srcLastRow As Integer, srcFirstCol As Integer, srcLastCol As Integer,


dstFirstCol As Integer, dstFirstRow As Integer)
Dim SrcRange As String, DestRange As String, Sheet1 As Worksheet, Sheet3 As Worksheet

Set Sheet1 = ThisWorkbook.Worksheets("BEx")


Set Sheet3 = ThisWorkbook.Worksheets("OUTPUT")

SrcRange = GetRange(srcFirstCol, srcFirstRow) + ":" + GetRange(srcLastCol, srcLastRow)


DestRange = GetRange(dstFirstCol, dstFirstRow) + ":" + GetRange(dstFirstCol + srcLastCol - srcFirstCol + 1,
dstFirstRow + srcLastRow - srcLastRow + 1)
Sheet1.Range(SrcRange).Copy Destination:=Sheet3.Range(DestRange)
End Sub

Function GetRange(ByVal col As Integer, ByVal row As Integer) As String


Dim RR As String
RR = Chr(col + Asc("A") - 1)
GetRange = Trim(RR) + Trim(Str(row))
End Function

Sub CopyFontBorderRange(ByRef Sheet2 As Worksheet, ByRef Sheet3 As Worksheet, ByVal SrcCol1 As Integer,
ByVal SrcCol2 As Integer, ByVal SrcRow1 As Integer, ByVal SrcRow2 As Integer, RowShift As Integer)
Dim SrcRange As String, DestRange As String
Dim I As Integer, J As Integer

For I = SrcRow1 To SrcRow2


For J = SrcCol1 To SrcCol2
SrcRange = GetRange(J, I)
DestRange = GetRange(J, I + RowShift)
Sheet3.Range(DestRange).Font.FontStyle = Sheet2.Range(SrcRange).Font.FontStyle
Sheet3.Range(DestRange).Font.Size = Sheet2.Range(SrcRange).Font.Size
Sheet3.Range(DestRange).Font.Color = Sheet2.Range(SrcRange).Font.Color
Sheet3.Range(DestRange).Font.Background = Sheet2.Range(SrcRange).Font.Background

Sheet3.Range(DestRange).Borders.LineStyle = Sheet2.Range(SrcRange).Borders.LineStyle
Sheet3.Range(DestRange).Borders(xlEdgeTop).LineStyle =
Sheet2.Range(SrcRange).Borders(xlEdgeTop).LineStyle
Sheet3.Range(DestRange).Borders(xlEdgeBottom).LineStyle =
Sheet2.Range(SrcRange).Borders(xlEdgeBottom).LineStyle
Sheet3.Range(DestRange).Borders(xlEdgeLeft).LineStyle =
Sheet2.Range(SrcRange).Borders(xlEdgeLeft).LineStyle
Sheet3.Range(DestRange).Borders(xlEdgeRight).LineStyle =
Sheet2.Range(SrcRange).Borders(xlEdgeRight).LineStyle

Sheet3.Range(DestRange).WrapText = Sheet2.Range(SrcRange).WrapText

Sheet3.Range(DestRange).Interior.Pattern = Sheet2.Range(SrcRange).Interior.Pattern
Sheet3.Range(DestRange).Interior.Color = Sheet2.Range(SrcRange).Interior.Color
Next
Next

End Sub

Sub CopyFormatRow(ByVal FormatRow As Integer, ByVal DestRow1 As Integer, ByVal DestRow2 As Integer, ByVal
LastColumn As Integer, ByVal ConcutCol As Integer)
Dim SrcRange As String, DestRange As String, Sheet2 As Worksheet, Sheet3 As Worksheet, rng As Range
Dim I As Integer, J As Integer

Set Sheet2 = ThisWorkbook.Worksheets("TEMPLATE")


Set Sheet3 = ThisWorkbook.Worksheets("OUTPUT")

SrcRange = GetRange(1, FormatRow) + ":" + GetRange(LastColumn, FormatRow)


Set rng = Range(SrcRange)

For I = 1 To rng.Columns.Count
SrcRange = GetRange(I, FormatRow)
DestRange = GetRange(I, DestRow1) + ":" + GetRange(I, DestRow2)
With Sheet2.Range(SrcRange).Font
Sheet3.Range(DestRange).Font.FontStyle = .FontStyle
Sheet3.Range(DestRange).Font.Size = .Size
Sheet3.Range(DestRange).Font.Color = .Color
Sheet3.Range(DestRange).Font.Background = .Background
Sheet3.Range(DestRange).Font.Bold = .Bold
Sheet3.Range(DestRange).Font.Italic = .Italic
Sheet3.Range(DestRange).Font.Strikethrough = .Strikethrough
Sheet3.Range(DestRange).Font.Subscript = .Subscript
Sheet3.Range(DestRange).Font.Superscript = .Superscript

Sheet3.Range(DestRange).Font.Underline = .Underline
End With
With Sheet2.Range(SrcRange)
Sheet3.Range(DestRange).Interior.Pattern = .Interior.Pattern
Sheet3.Range(DestRange).Interior.PatternColor = .Interior.PatternColor

If I = ConcutCol Then
Sheet3.Range(DestRange).Borders.LineStyle = .Borders.LineStyle
Sheet3.Range(DestRange).Borders.Weight = .Borders.Weight
Sheet3.Range(DestRange).Borders.ColorIndex = .Borders.ColorIndex
Else
Sheet3.Range(DestRange).Borders(xlEdgeBottom).LineStyle = .Borders(xlEdgeBottom).LineStyle
Sheet3.Range(DestRange).Borders(xlEdgeBottom).Weight = .Borders(xlEdgeBottom).Weight
Sheet3.Range(DestRange).Borders(xlEdgeBottom).ColorIndex = .Borders(xlEdgeBottom).ColorIndex
Sheet3.Range(DestRange).Borders(xlEdgeLeft).LineStyle = .Borders(xlEdgeLeft).LineStyle
Sheet3.Range(DestRange).Borders(xlEdgeLeft).Weight = .Borders(xlEdgeLeft).Weight
Sheet3.Range(DestRange).Borders(xlEdgeLeft).ColorIndex = .Borders(xlEdgeLeft).ColorIndex
Sheet3.Range(DestRange).Borders(xlEdgeRight).LineStyle = .Borders(xlEdgeRight).LineStyle
Sheet3.Range(DestRange).Borders(xlEdgeRight).Weight = .Borders(xlEdgeRight).Weight
Sheet3.Range(DestRange).Borders(xlEdgeRight).ColorIndex = .Borders(xlEdgeRight).ColorIndex
Sheet3.Range(DestRange).Borders(xlEdgeTop).LineStyle = .Borders(xlEdgeTop).LineStyle
Sheet3.Range(DestRange).Borders(xlEdgeTop).Weight = .Borders(xlEdgeTop).Weight
Sheet3.Range(DestRange).Borders(xlEdgeTop).ColorIndex = .Borders(xlEdgeTop).ColorIndex
End If

Sheet3.Range(DestRange).WrapText = .WrapText
End With
Next I
End Sub

The code copies the reports header and footer without changes (with appropriate column width and row
height). Then rows of the report are copied with applying of the format in the format row.
In the beginning of the routine the code tries to determine the numbers of start and end rows and columns by
using global variable gResArea that was filled out during the workbook refreshing. If this variable is not set (for
example, during the 2nd run of the program while debugging), the numbers saved in the 2nd row of BEx

worksheet are used.


The whole code, I believe, is rather universal. It might be not perfect but it works.
If your reports output is not complex (similar to that shown here) you can use the code. All you have to do is to
change the reports header and footer in Template worksheet and change parameters enclosed by asterisks
and with the comment PARAMETERS TO BE CHANGED (in CommandButton1_Click subroutine).
There are some notes regarding these parameters.
iHeaderLastRow (Header Last Row), iFooterFirstRow (Footer First Row), iFooterLastRow ( Footer Last Row),
iFormatRow (Format Row Number) are self-explaining.
iLongText1 (First Column of Long Text) and iLongText2 (Last Column of Long Text) designate the first and last
columns between which the peaces of long description are located. If you set both of them to zero, there will not
be any concatenation.
RptHeaderRowsToIgnore (Number of rows in the BEx output to ignore) is a number of rows of the BExs
output header (not navigation block), with the names of columns. We replace these rows by formatted header
(in Template worksheet).
I believe that proposed here solution will allow formatting the most of reports very quickly. Moreover, this will
make such a job unprecedently cheap.

More complex reports


I used to format much more complex reports. For example:
With hierarchies, where I needed instead of BEx hierarchy with indents to show each level of the hierarchy in
a separate column.
With fixed formatted columns.
With complex column names replaced during the query run (for example, names of periods).
Reports which I had to show in two sets of columns.
Reports with Top N (or Bottom N) calculation along with total amounts and Total Top N.
With replacement of values (for example, replacement of blank or zero values with -).
With using custom fonts or colors.

Last preparations
To return from Visual Basic editor to Excel you can either click on the appropriate window or use the Excels
menu path: View -> Microsoft Excel.
To run the formatting, click on the Exit Design Mode icon.

Now clicking on the button will execute the code.


After youve done everything described here, you can save a new workbook giving it the description and
technical name.

Formatted output
The output of our formatted report is nicely looking. The header a little differs from the template since I had to
decrease the columns width in the template after report formatting for better visualization in the blog.

Pay attention to the fact that this is a static report, as needed for print. Drilldown of the BEx output and the
appropriate changes of the formatted report are not supported. For this you must write much more
sophisticated code.
In the output we have both, lowercase and uppercase letters, though we didnt set any Lowercase Letters flag
in any of our infoobjects for long texts. Its another advantage in using the long texts modeling scheme
described in the first blog.
There is a very common delusion that if the text to be loaded contains lowercase letters, one either should use
uppercase letters only or apply this lowercase letters flag in infoobject maintenance. Thats not true. Texts of
infoobjects may be shown in lowercase letters regardless of any settings. Though, that might be a theme for
another blog.
Eugene Khusainov
Add to: del.icio.us | Digg | Reddit

Comment on this weblog

Showing messages 1 through 8 of 8.

Titles Only
Main Topics
Multiple pages and long texts inputs

Oldest First

2006-11-15 11:55:38 Victor Figueroa Business Card [Reply]


Hi, Eugene!

i am use VBA code for making the formated reports, now i have big problems.

Need Capture the 3 extense long texts related to zcostcenter value.


So and insert that long texts in workbook when filter is using zcostcenter value.
Long text have media 255 a 300 Characters, using any values ASCII.
Any idea for my problem ?
Thank you for you time.

Multiple pages and long texts inputs


2006-11-15 12:47:20 Victor Figueroa Business Card [Reply]
Eugene, i not know how edit my post, i am lost say you.
i need capture the 3 big texts from BPS web planning folder for the zcostcenter value.

Thank you.

Bex macros
2006-06-12 08:29:24 Kaspars Osis Business Card [Reply]
Hi, Eugene!
All in all this is very helpful info.

However I have a very simple issue - I just don't see this "SAPBEX" module you are mentioning at the very
begining of your post. Not even thinking about SAPBEXonRefresh subroutine I wanna use.
I have gone through posts by Peter Knoer, too...
We have Excel 2003; BI 2004s.
"Module1" module is created when I add a module to my workbook. In this Module1 I'm adding then
SAPBEXonRefresh subroutine. When I restart RRMX or Refresh the workbook, then the test code within the
SAPBEXonRefresh is not being executed.
Do you have any idea what it might be that I'm missing.
Thanks in advance!
With regards,
--- Kaspars

Bex macros
2006-06-12 20:58:53 Eugene Khusainov

Business Card [Reply]

Hi Caspars,

Have you set an Excel security, as mentioned in the 1st part of the blog?
Best regards,
Eugene

Bex macros
2006-06-13 04:06:04 Kaspars Osis Business Card [Reply]
Hi Eugene,
yes sure - I have even set the security level to Low. Also 'Trust access to Visual Basic Project flag has been set ...

With regards,
--- Kaspars

Bex macros
2006-06-13 22:26:42 Eugene Khusainov

Business Card [Reply]

Hi Kaspars,

Didn't work with BEx 2004s yet.


Try to insert SAPBEXRefresh sub and see if it works during refresh.
See also some additional info gere:
https://www.sdn.sap.com/irj/sdn/thread?forumID=154&threadID=153194&messageID=1718729
https://www.sdn.sap.com/irj/sdn/thread?forumID=134&threadID=152995&messageID=1713514
Come back with feedback.
Best regards,
Eugene

Bex macros
2006-06-14 02:08:42 Kaspars Osis Business Card [Reply]
Hi Eugene,
SAPBEXRefresh didn't do any difference either;

However your first reference had the solution (part of it)! It seems that the issue was that I had to switch to
Design Mode; -> then select Workbook Settings; and then in the tab Exits had to enter a name of the macros
(i.e. SAPBEXonRefresh).
Second part was that in the same Workbook Settings windows in the tab General had to check "Refresh
Workbook on Open" flag. Once done that, then it indeed showed the result of test code on open (otherwise only
on refresh).
So, thanks a lot for your help!
With regards,
--- Kaspars
P.S. I've never have given points in SDN yet; didn't seem to be very obvious how to do it. Maybe you could give
me a hint ... thx!

Bex macros
2006-06-14 20:34:54 Eugene Khusainov

Business Card [Reply]

Hi Kaspars,

I'm glad that was of a somewhat help to you.

You can reward points to the answers to your questions posted in forums. Blogs are somewhat different.
Good luck in your work!
Best regards,
Eugene

Showing messages 1 through 8 of 8.

You might also like