Change documents in SAP log the modification of objects at the field level. Many SAP transactions provide a direct link to a list of the corresponding change lists directly via the SAP menu.
You can also write change documents for Z-fields in SAP standard tables or even vor custom-defined Z-tables.
Using change documents, you can see:
- which user
- modified which field
- using which transaction, and
- what the old and new field values are.
First, let’s explore which tables store the change documents and how you can analyze them there.
Next, I will show you how you can set up change documents for custom fields in standard tables, for example, on the customer master record. To achieve this, you only need to configure the field properties of the new custom field correctly.
Lastly, we will explore change documents for user-defined Z-tables. You can also create change documents there. However, you’ll need to do a bit more for this: you need to trigger the creation of the change documents yourself and pass the old and new values.
Examples for Change Documents
You can access the change documents in many SAP standard transactions directly through the menu. Here is my test customer in a development system, where I have already made a number of changes. The changes can be found in the “Environment” menu. They are typically located there in other standard transactions as well.
You then get to a list of changes that you can also click to get more details.
If you click the “All Changes” button, you will receive a list of all the details regarding every change.
Through “Environment/Field Changes,” you can directly view the modifications. However, from a developer’s perspective, it’s more intriguing to explore how you can automatically analyze these changes. To achieve this, we need to understand where the change documents are stored.
The tables where the change documents are stored
The backbone of the change documents consists of two tables:
- CDHDR: Change Document Header, also known as header data.
- CDPOS: Individual field data (“items” or “positions”).
For instance, when you modify a customer (debitor), you often change multiple fields simultaneously. All these field changes then share a common header record.
Here are some header records (CDHDR) for my test customer.
The OBJECTCLASS here is DEBI. We will explore further below where this is defined. It is a sort of arbitrary name that a developer at SAP decidec to use for the customers. It bundles field changes for various debtor tables.
OBJECTID is the debtor’s number. For other tables, the key might be structured differently, such as a document number plus the company code or sales organization (VKORG). This too is a developer decision, and for SAP standard objects, it was the choice made by SAP developers.
CHANGENR is the change number. These numbers are drawn from a number range across all change documents. To this number in the header, one or more CDPOS records can be linked.
Here, I have selected the individual changes from CDPOS for one of the header records.
The link with CDHDR is established through OBJECTCLAS, OBJECTID, and CHANGENR.
Here, two fields were altered simultaneously, both from the KNA1 table (Customer Master Data). One is the street address, and the second is a Z-field with a version number.
Both the old and new values are provided for both field changes.
The same key values of the header record are also found in the table key of the item data.
With this knowledge, you can then create your own database queries that specifically search for changes to a particular field in the customer data.
Attention: CDPOS is a cluster table!
Attention: The table CDPOS is a cluster table. Cluster tables are optimized for storing large amounts of data that are infrequently read. The data is stored in the database in a compressed format.
Cluster tables have certain technical limitations. Specifically, you cannot use them in a join operation.
This is unfortunate because if you are looking for changes within a specific time range (CDHDR) that concern particular fields (field name from CDPOS), the first idea would be to join CDHDR with CDPOS.
Most often, you’ll want to narrow down your search by a time range. In this case, there’s no other way but this: the initial query covers all changes in CDPOS for the desired OBJECTCLAS (here, “DEBI”) within the specified time frame. With this substantial set of data, you can then search for changes to your favorite field within CDPOS.
How to prepare data elements for change documents
For many standard documents, SAP has already set up the change documents for you. If you wish to make any modifications, your task is likely to involve adding a new Z-field.
As an example, let’s consider a new field in the table KNVV, which is intended to be named ZZEMAIL_SPERRE (lock advertising E-mails). This field is used to indicate whether the debtor does not want to be contacted via email for promotions.
Here is the definition of the associated data element, ZEMAIL_SPERRE:
The important aspect here is the checkbox labeled “Change Document.” It can be found on the “Further Characteristics” tab. Change documents for a field can only be generated if this field property is checked in the underlying data element.
After making the changes, activating the modification is particularly crucial. Please check that the data element is actually activated. There have been multiple reports stating that simply activating the data element after checking this checkbox was not sufficient. The data element remained “inactive,” and as a result, the change documents didn’t work. Therefore, continue to activate it until this modification is actually active.
How to configure change documents for Z-tables
If you want to equip your own Z-tables with change documents or if you want to know what the OBJECTCLAS is for a SAP standard table, you will need:
- The transaction SCDO, where this is configured, and
- The table TCDOB, in which SCDO stores its data.
The SCDO transaction is cumbersome since it requires you to input the OBJECTCLAS name in the initial dialog. Let’s take a look at table TCDOB and search for TABNAME KNVV instead. This is a table where VKORG-specific data for a debtor is stored. (KNA1, the master record, exists only once. However, in KNVV, the debtor/customer has a record for each VKORG in which they are created.)
We discover: KNVV is only used by the OBJECTCLAS “DEBI.” And if we search again in SE16, this time for the OBJECTCLAS DEBI, we find this list:
So, from the perspective of change documents, all these tables are connected. Now we know how we can view this in SCDO and input DEBI in the selection screen:
The details look like this:
Change documents for Z-Tabellen
Now we have everything we need to set up change documents for our own Z-tables.
So, let’s say you have a Z-table, for instance, ZSOMETHING. Then the OBJECTCLAS for it might be ZFOOBAR. You’ve certainly also made sure to provide the data elements behind the fields in ZSOMETHING with the flag indicating that change documents are desired for these?
Next, you proceed to the transaction SCDO and create an OBJECTCLAS named ZFOOBAR. You define that the ZSOMETHING table is to be tracked by ZFOOBAR. Afterward, in this dialog, you press “Generate.” You will be prompted for a function group, as SAP wants to create a function module for you.
Afterward, you can verify through SE11 that there is a new entry in the TCDOB table.
Now, the only remaining question is how to actually generate the change documents. For this, you can utilize the generated function module. However, I personally prefer to do it “manually.” In the end, it leads to the same trio of three function modules.
Since I’m fond of ABAP-OO, I’ve created a class ZCL_CHANGEDOCUMENT. If I want to log a manual change to MARA, for instance, I use this method:
CLASS-METHODS log_mara IMPORTING !is_mara_old TYPE mara !is_mara_new TYPE mara . METHOD log_mara. DATA: lf_objectclass TYPE cdobjectcl, lf_objectid TYPE cdobjectv, lf_tablename TYPE tabname. lf_objectid = is_mara_new-matnr. lf_objectclass = 'MATERIAL'. lf_tablename = 'MARA'. log_generic( if_objectclass = lf_objectclass if_objectid = lf_objectid if_tablename = lf_tablename is_data_new = is_mara_new is_data_old = is_mara_old ). ENDMETHOD. "LOG_MARA
Here, it’s important to provide the Objectclass and the table name. The table name is always a mandatory entry. For MARA, there’s no other way because change documents for the MATERIAL Objectclass can involve multiple tables.
Additionally, there are two structs: one for the new data and another for the old data. I need to provide both of them so that SAP can use its standard modules to determine which fields have actually changed.
And the log_generic function then appears as follows.
CLASS-METHODS log_generic IMPORTING !if_objectclass TYPE cdobjectcl !if_objectid TYPE cdobjectv !if_tablename TYPE tabname !is_data_old TYPE any !is_data_new TYPE any . METHOD log_generic. CALL FUNCTION 'CHANGEDOCUMENT_OPEN' EXPORTING objectclass = if_objectclass objectid = if_objectid * PLANNED_CHANGE_NUMBER = ' ' * PLANNED_OR_REAL_CHANGES = ' ' EXCEPTIONS sequence_invalid = 1 OTHERS = 2. IF sy-subrc <> 0. MESSAGE 'Error writing change document (Open)' TYPE 'E'. ENDIF. CALL FUNCTION 'CHANGEDOCUMENT_SINGLE_CASE' EXPORTING * CHANGE_INDICATOR = 'U' * DOCU_DELETE = ' ' * DOCU_INSERT = ' ' * REFAREA_NEW = ' ' * REFAREA_OLD = ' ' * REFTABLENAME = ' ' tablename = if_tablename workarea_new = is_data_new workarea_old = is_data_old EXCEPTIONS nametab_error = 1 open_missing = 2 position_insert_failed = 3 OTHERS = 4. IF sy-subrc <> 0. MESSAGE 'Error writing change document (SingleCase)' TYPE 'E'. ENDIF. CALL FUNCTION 'CHANGEDOCUMENT_CLOSE' EXPORTING date_of_change = sy-datum objectclass = if_objectclass objectid = if_objectid tcode = sy-tcode time_of_change = sy-uzeit username = sy-uname * OBJECT_CHANGE_INDICATOR = 'U' * PLANNED_OR_REAL_CHANGES = ' ' * NO_CHANGE_POINTERS = ' ' * IMPORTING * CHANGENUMBER = EXCEPTIONS header_insert_failed = 1 no_position_inserted = 2 object_invalid = 3 open_missing = 4 position_insert_failed = 5 OTHERS = 6. IF sy-subrc <> 0 AND sy-subrc <> 2. MESSAGE 'Error writing change document (Close)' TYPE 'E'. ENDIF. ENDMETHOD. "LOG_MARA
These three methods belong together. If they’re not called in this order, it can result in messy sequence errors.
CHANGEDOCUMENT_OPEN: This opens a change document header record for an Objectclass and an Object ID (for example, the material number or a table key defined by you in the ZSOMETHING table).
Subsequently, one or more calls to CHANGEDOCUMENT_SINGLE_CASE follow, which records one line. There’s also the CHANGEDOCUMENT_MULTIPLE_CASE function module, which theoretically can handle comparing lists. However, I haven’t been able to bring it to life yet. You need to provide the table and the data (as a structured data type, like the MARA type or perhaps from ZSOMETHING).
Finally, CHANGEDOCUMENT_CLOSE concludes the block.
Afterward, you can look up the change in CDHDR and CDPOS.
For standard object classes, SAP’s standard tables are automatically processed. In the respective dialogs within the SAP GUI, it’s already configured that change documents should be generated.
For manual updates to SAP standard tables or always with Z-tables, you have to do this yourself. Only when you explicitly generate the change documents yourself will they be created in the end. So, wherever you perform an insert or update or delete to the database, you need to ensure that change documents are also written.
However, with the knowledge from this article, you will certainly manage.
And now have fun with change documents for your own Z-tables.
You can find more SAP tips here.