Änderungsbelege (change documents) protokollieren in SAP die Änderung von Objekten auf Feldebene. Viele SAP-Transaktionen bieten die Auswertung der Änderungen direkt über das Menü an.
Änderungsbelege sind auch für Z-Felder in Standardtabellen und auch für selbstdefinierte Tabellen möglich.
Mit Hilfe der Änderungsbelege kannst du sehen,
- welcher Benutzer
- welches Feld
- wann
- mit welcher Transaktion geändert hat und
- was der alte und was der neue Feldwert ist.
Wir schauen uns nun an, in welchen Tabellen die Änderungsbelege abgespeichert werden und wie du sie dort auswerten kannst.
Anschließend zeige ich Dir, wie Du Änderungsbelege auch für selbstdefinierte Felder in Standardtabellen, z.B. am Debitor, einrichten kannst. Hierzu sind lediglich die Feldeigenschaften des neuen Z-Felds richtig zu setzen.
Als letztes schauen wir uns Änderungsbelege für selbst definierte Z-Tabellen an. Auch dort kannst Du Änderungsbelege erzeugen. Allerdings musst Du dafür etwas mehr tun: Du musst das Erzeugen des Change Documents selbst anstoßen und den alten und den neuen Wert übergeben.
Beispiele für Änderungbelege
Die Änderungsbelege kannst du in vielen SAP-Standardtransaktionen direkt über das Menü aufrufen. Hier ist mein Testkunde auf einem Entwicklungssystem, auf dem ich schon eine Reihe von Änderungen gemacht habe. Die Änderungen finden sich im Menü „Umfeld“. Dort finden sie sich typischerweise auch in anderen Standardtransaktionen.
Du gelangst dann in eine Liste von geänderten Attributen, die du auch weiter aufklicken kannst.
Wenn du auf den Button „Alle Änderungen“ klickst, dann bekommst du eine Liste über alle Details zu allen Änderungen.
Man kann sich über „Umfeld/Feldänderungen“ also die Änderungen direkt ansehen. Aus Entwicklersicht ist es aber interessanter zu schauen, wie du diese Änderungen automatisch auswerten kannst. Dazu müssen wir wissen, wo die Änderungsbelege abgelegt werden.
Die Tabellen hinter den Änderungsbelegen
Rückgrat der Änderungsbelege sind die beiden Tabellen
- CDHDR: change document header, also Kopfdaten
- CDPOS: die einzelnen Felddaten („Positionen“)
Wenn Du z.B. einen Debitor änderst, dann änderst du meist mehrere Felder auf einmal. All diese Feldänderungen teilen sich dann einen Header/Kopfsatz.
Hier sind Kopfsätze (CDHDR) für meinen Testkunden
Die OBJECTCLASS ist hier DEBI. Wir schauen uns weiter unten noch an, wo das definiert wird. Es handelt sich hier um einen quasi beliebigen Text, den ein Entwickler bei SAP einmal festgelegt hat, und der Feldänderungen für mehrere Tabellen der Debitoren bündelt.
OBJECTID ist die Nummer des Debitors. Bei anderen Tabellen kann der Schlüssel auch anders aufgebaut sein, z.B. eine Belegnummer plus den Buchungskreis oder die VKORG. Auch das ist eine Entwicklerentscheidung, und bei SAP-Standardobjekten war es die Entscheidung der Entwickler bei SAP.
CHANGENR ist die Nummer der Änderung. Diese werden quer über alle Änderungsbelege aus einem Nummernkreis gezogen. Zu dieser Nummer im Kopfsatz können dann eine oder mehrere CDPOS-Sätze gehören.
Hier habe ich mir zu einem der Kopfsätze die einzelnen Änderungen aus CDPOS selektiert:
Der Zusammenhalt mit CDHDR erfolgt über OBJECTCLAS, OJECTID und CHANGENR.
Hier wurden also zwei Felder gleichzeitig geändert, beide aus der Tabelle KNA1 (Kunden-Kopfdaten). Einmal die Straße und zum zweiten ein Z-Feld mit einer Versionsnummer.
Zu beiden Feldänderungen sind der alte und der neue Wert aufgeführt.
Die Schlüsselwerte des Kopfsatzes finden sich auch im Tabellenschlüssel der Positionsdaten.
Mit diesem Wissen kannst Du dir dann eigene Datenbankabfragen schreiben, die speziell nach Änderungen eines bestimmten Felds im Kunden suchen.
CDPOS ist eine Clustertabelle!
Achtung: die Tabelle CDPOS ist eine Clustertabelle. Clustertabellen sind darauf optimiert, große Datenmengen zu speichern, die aber nur selten gelesen werden. Die Daten werden hierzu komprimiert in der Datenbank abgelegt.
Clustertabellen haben gewisse technische Einschränkungen. Insbesondere kannst du sie nicht in einem Join verwenden.
Das ist schade, denn wenn du Änderungen in einem bestimmten Zeitbereich suchst (CDHDR), die bestimmte Felder betreffen (Feldname aus CDPOS), dann wäre ein Join von CDHDR auf CDPOS ja die erste Idee.
Meist wirst du deine Suche über einen Zeitbereich einschränken wollen. In diesem Fall geht es leider nicht anders: die erste Abfrage geht über alle Änderungen in CDPOS zur gewünschten OBJECTCLAS (hier „DEBI“) im Zeitbereich. Mit diesem großen Sack von Daten kannst du dann in CDPOS nach Änderungen deines Lieblingsfelds suchen.
Änderungsbelege für neue Felder an SAP-Standardobjekten einrichten: Datenelement fitmachen
Für viele Standardbelege hat SAP die Änderungsbelege schon für dich eingerichtet. Wenn du daran etwas ändern willst, dann lautet deine Aufgabe wahrscheinlich, ein neues Z-Feld anzuschließen.
Als Beispiel betrachte ich ein neues Feld auf der Tabelle KNVV, es soll ZZEMAIL_SPERRE heißen. Es hält fest, dass der Debitor nicht per E-Mail beworben werden will.
Hier ist die Definition des zugehörigen Datenelements ZEMAIL_SPERRE:
Wichtig ist an dieser Stelle die Checkbox „Änderungsbeleg“, sie findet sich auf dem Karteireiter „Zusatzeigenschaften“. Änderungsbelege zu einem Feld lassen sich nur dann erzeugen, wenn im zugrundeliegenden Datenelement diese Feldeigenschaft angekreuzt ist.
Nach dem Ändern ist das Aktivieren der Änderung besonders wichtig. Bitte prüfe das nach. Es wurde schon mehrfach berichtet, dass ein einfaches Aktivieren des Datenelements nach Ankreuzen dieser Checkbox nicht ausgereicht hatte. Das Datenelement verblieb auf „inaktiv“, und dann funktionieren die Änderungsbelege nicht. Also: so lange aktivieren, bis diese Änderung tatsächlich aktiv ist.
Konfiguration der Änderungsbelege
Wenn du eigene Z-Tabellen mit Änderungsbelegen ausstatten willst, oder wenn du wissen willst, die die OBJECTCLAS zu einer SAP-Standardtabelle lautet, dann brauchst du
- die Transaktion SCDO, in der dies festgelegt wird und
- die Tabelle TCDOB, in der SCDO seine Daten ablegt.
Die Transaktion SCDO ist unhandlich, denn sie verlangt in Eingangsdialog schon den Namen der OBJECTCLAS. Schauen wir lieber in die Tabelle TCDOB und suchen wir den TABNAME KNVV, das ist eine Tabelle, in der VKORG-spezifische Daten eines Debitors abgelegt werden. (KNA1, den Stammsatz gibt es nur einmal. Aber in der KNVV hat der Debitor/Kunde für jede VKORG einen Datensatz, in der er angelegt wurde.)
Wir finden heraus: KNVV wird nur von der OBJECTCLAS „DEBI“ verwendet. Und wenn wir erneut in SE16 suchen, diesmal für die OBJECTCLAS DEBI, dann finden wir diesen Zoo:
All diese Tabellen gehören also aus Sicht der Änderungsbelege zusammen. Jetzt wissen wir, wie wir uns das in SCDO ansehen können und geben DEBI im Selektionsschirm an:
Und die Details sehen so aus:
Änderungsbelege für Z-Tabellen
Jetzt haben wir alles beisammen, um Änderungsbelege für eine eigene Z-Tabellen einzurichten.
Du hast also eine Z-Tabelle, sagen wir mal ZSOMETHING. Dann könnte die OBJECTCLAS dazu vielleicht ZFOOBAR heißen. Du hast sicherlich auch daran gedacht, die Datenelemente hinter den Feldern aus ZSOMETHING mit dem Flag auszustatten, dass hierzu Änderungsbelege gewünscht sind?
Dann gehtst du in die Transaktion SCDO und legst eine OBJECTCLAS ZFOOBAR an. Du definierst, dass die Tabelle ZSOMETHING von ZFOOBAR protokolliert wird. Anschließend drückst du in diesem Dialog auf „generieren“. Du wirst nach einer Funktionsgruppe gefragt, denn SAP möchte einen Funktionsbaustein für dich anlegen.
Anschließend kannst du dich per SE11 in der Tabelle TCDOB davon überzeugen, dass es dort einen neuen Eintrag gibt.
Jetzt ist nur noch die Frage, wie du die Änderungsbelege tatsächlich erzeugst. Dazu kannst du den generierten Funktionsbaustein verwenden. Ich selbst mache es aber lieber „zu Fuß“. Es läuft am Ende auf dasselbe Dreigestirn von drei Funktionsbausteinen hinaus.
Da ich ABAP-OO mag, habe ich mir eine Klasse ZCL_CHANGEDOCUMENT geschrieben. Wenn ich dort eine manuelle Änderung an der MARA protokollieren will, dann verwende ich die Methode
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
Wichtig ist hier die Angabe der Objectclass und des Tabellennamens. Der Tabellenname ist immer eine Pflichtangabe. Es ginge bei MARA auch gar nicht anders, weil die Änderungsbelege der Objectclass MATERIAL zu mehreren Tabellen möglich sind.
Außerdem gibt es ein struct mit den neuen und eines mit den alten Daten. Beide muss ich mitliefern, dann kann SAP mit seinen Standardbausteinen ermitteln, welche Felder sich tatsächlich geändert haben.
Und log_generic sieht dann so aus.
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 'Fehler beim Schreiben Änderungshistorie (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 'Fehler beim Schreiben Änderungshistorie (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 'Fehler beim Schreiben Änderungshistorie (Close)' TYPE 'E'. ENDIF. ENDMETHOD. "LOG_MARA
Die drei Methoden gehören zusammen. Wenn sie nicht in dieser Reihenfolge aufgerufen werden, dann gibt es hässliche Sequenzfehler.
CHANGEDOCUMENT_OPEN: Dies öffnet für eine Objectclass und eine Object-ID (z.B. die Materialnummer oder einen von dir definierten Tabellenschlüssel in der Tabelle ZSOMETHING) einen Änderungsbelegskopfsatz.
Es folgen ein oder mehrere Aufrufe von CHANGEDOCUMENT_SINGLE_CASE, der eine Zeile wegschreibt. Es gibt auch den Baustein CHANGEDOCUMENT_MULTIPLE_CASE, der theoretisch Listen vergleichen kann. Den habe ich aber bisher nicht zum Leben erwecken können.) Hier ist die Tabelle anzugeben und die Daten (als strukturierten Datentyp, z.B. vom Typ MARA oder vielleicht von ZSOMETHING.
Als letztes schließt CHANGEDOCUMENT_CLOSE den Block ab.
Anschließend kannst du die Änderung dann in CDHDR und CDPOS nachschlagen.
Ein Wort zum Schluss
Bei Standard-Objectclasses werden die Standardtabellen von SAP automatisch verarbeitet. Dort ist in den jeweiligen Dialogen in der SAP-GUI schon hinterlegt, dass die Änderungsbelege erzeugt werden sollen.
Bei manuellen Updates auf SAP-Standardtabellen oder immer bei Z-Tabellen musst du das selbst machen. Nur da, wo du explizit selbst die Änderungsbelege erzeugst, wird es diese am Ende geben. Du müsstest also überall da, wo du ein update auf die Datenbank machst, dafür Sorge tragen, dass auch Änderungsbelege geschrieben werden.
Aber mit dem Wissen aus diesem Artikel funktioniert das dann auch.
Viel Spaß mit deinen eigenen Änderungsbelegen.
Mehr SAP-Tipps gibt es hier.