Der vorige Beitrag hat gezeigt, aus welchen vier Quellen man ein fremdes SAP-System liest, und alle vier sind Tabellen. Im Projekt von 2020 waren das 127 Blätter in einer Excel-Mappe, jedes ein SE16N-Export von Hand und jeder davon Klickkram: Selektion eingeben, auf den Download warten, Blatt einfügen, und am Ende steht das Datum als Text in der Spalte. Einige Wochen später weiß niemand mehr, welche Selektion zu welchem Blatt gehörte, denn festgehalten ist sie nirgends. Heute schreibe ich die Abzüge in eine Ladedatei, eine Zeile je Tabelle, und ein Aufruf zieht sie alle per RFC, typisiert, in einen Ordner. Die Datei hält fest, was gezogen wird, und zum nächsten Stichtag startet man sie noch einmal.

Der Weg braucht nur, was jedes SAP-System mitbringt

RFC_READ_TABLE ist ein Funktionsbaustein, den jedes SAP-System mitbringt: er liest eine Tabelle mit Feldauswahl und WHERE-Bedingung und gibt die Zeilen über RFC zurück, die Schnittstelle, über die SAP-Systeme und externe Programme miteinander sprechen. Auf der anderen Seite steht der SAP .NET Connector, die Bibliothek, mit der SAP den RFC-Zugriff aus .NET-Programmen vorsieht. Dazwischen liegt ein PowerShell-Skript.

Im Kundensystem wird nichts installiert, kein Transport, kein Z-Programm, kein Add-on. Auf dem Rechner, an dem man arbeitet, auch nicht: das Werkzeug ist ein Ordner mit Skripten und den Bibliotheken des Connectors, kopiert, ohne Adminrechte und ohne Registrierung, und es läuft unter der Windows PowerShell, die jeder Windows-Rechner mitbringt. Auf dem Rechner, den ein Kunde einem externen Berater gibt, darf man meist nichts installieren, und genau dort muss der Abzug laufen.

Was man braucht, ist ein SAP-Benutzer mit RFC-Berechtigung: das Berechtigungsobjekt S_RFC auf die Funktionsgruppen SDTX für RFC_READ_TABLE, SYST für die Anmeldung und RFC_METADATA, dazu die Tabellenanzeige über S_TABU_DIS oder S_TABU_NAM. Ein Analysebenutzer hat das selten von allein, also steht die Liste bei mir in der ersten Mail an die Basis.

Die Ladedatei sagt, was gezogen wird und warum

Eine Ladedatei ist eine Textdatei mit einer Zeile je Tabelle. Die Kurzform ist der Tabellenname, optional mit einer WHERE-Bedingung dahinter. Die Pipe-Form TABELLE | FELDER | WHERE nennt die Felder als Kommaliste, leer heißt alle. Eine Zeile, die mit # beginnt, ist Kommentar, und dort steht, was in keinem SE16N-Screenshot steht: wofür die Tabelle gebraucht wird und warum sie so geschnitten ist.

So sieht der Kern einer Customizing-Aufnahme aus, die IMG-Aktivitäten, ihre Pflegeobjekte und die Tabellen darunter:

# Customizing-Aufnahme: IMG-Aktivitaeten, Pflegeobjekte, Tabellen darunter.
# Aus dem Entwicklungssystem, dort ist das Customizing vollstaendig.

# Alle Aktivitaeten des Systems und ihre Texte. Den Ast waehlen wir
# lokal, nicht im Abzug: ein neuer Ast kostet dann keinen Nachzug.
CUS_IMGACH | ACTIVITY,DOCU_ID,ATTRIBUTES,C_ACTIVITY,TCODE |
CUS_IMGACT | SPRAS,ACTIVITY,TEXT | SPRAS = 'D'

# Pflegeobjekte je Aktivitaet, meist Views.
CUS_ACTOBJ | ACT_ID,OBJECTTYPE,OBJECTNAME,TCODE,SUBOBJNAME,IMG_POS |

# Tabellen unter den Views, nur die aktive Version.
DD26S | VIEWNAME,TABNAME,TABPOS | AS4LOCAL = 'A'

CUS_IMGACH führt die Aktivitäten des Einführungsleitfadens, CUS_ACTOBJ ihre Pflegeobjekte, und DD26S löst jede View in ihre Tabellen auf. Für die Eigenentwicklungen kommt eine Zeile TADIR auf den Z-Namensraum dazu. Wie aus diesen Tabellen der Baum und das Konzept werden, zeigen die nächsten Beiträge.

Die Kommentare sind der Teil, den man sonst verliert. Warum der Ast nicht im Abzug gefiltert wird, warum DD26S nur die aktive Version trägt: das steht neben der Zeile, die es betrifft, und die Datei liegt im selben Ordner wie die Auswertung. Vor dem Lauf ist sie die Spezifikation, nach dem Lauf die Dokumentation.

Die Feldlisten stehen hier, weil diese Tabellen das ganze System beschreiben und nur ein Teil ihrer Spalten gebraucht wird. Die Customizingtabellen selbst, also die Werte hinter den Views, ziehe ich danach ohne Feldliste. Eine schmale Feldliste spart bei kleinen Tabellen nichts und kostet einen Nachabzug, sobald die Analyse ein Feld braucht, an das vorher niemand gedacht hat.

Ein Aufruf zieht alles und hakt ab

Der Stapellauf liest die Ladedatei und ruft je Zeile den Abzug auf:

.\Get-SAPTables.ps1 -List .\customizing.saptab.txt `
    -AppServerHost sap-dev -SystemNumber 00 -Client 100 -User TFRANZ

Das Passwort wird einmal abgefragt, ein Fehler bei einer Tabelle bricht den Stapel nicht ab, am Ende steht eine Übersicht.

Jede erledigte Zeile hakt der Lauf in der Ladedatei selbst ab, mit Zeitpunkt und Dauer:

# [OK 2026-07-10 13:52, 00:00:24] CUS_IMGACH | ACTIVITY,DOCU_ID,ATTRIBUTES,C_ACTIVITY,TCODE |
# [OK 2026-07-10 13:52, 00:00:17] CUS_IMGACT | SPRAS,ACTIVITY,TEXT | SPRAS = 'D'
# [OK 2026-07-10 13:53, 00:00:21] CUS_ACTOBJ | ACT_ID,OBJECTTYPE,OBJECTNAME,TCODE,SUBOBJNAME,IMG_POS |
# [OK 2026-07-10 13:54, 00:00:48] DD26S      | VIEWNAME,TABNAME,TABPOS | AS4LOCAL = 'A'

Die vier Tabellen brauchten zusammen keine zwei Minuten, alle 127 sind in unter zwanzig Minuten durch. Bricht ein Lauf ab, startet man denselben Aufruf noch einmal, und er macht bei der ersten Zeile ohne Haken weiter. Einen Zustand außerhalb der Datei gibt es nicht.

Für Customizing-Tabellen reicht das. Belegtabellen mit Millionen Zeilen zieht das Werkzeug in Scheiben, und wie man am Ende beweist, dass keine Zeile fehlt, ist ein eigener Beitrag.

Jede Datei kennt ihre Typen und ihre Herkunft

RFC_READ_TABLE liefert jeden Wert als Zeichenkette im internen SAP-Format, das Datum als 20260710, den Betrag mit nachgestelltem Minus. Das Werkzeug liest deshalb vor der ersten Zeile im Data Dictionary des Systems nach, welchen Typ jedes Feld hat. Das Data Dictionary ist SAPs eigene Beschreibung aller Tabellen und Felder, und es liegt selbst in Tabellen, die derselbe Baustein liest.

Je Tabelle entsteht eine TSV, eine Textdatei mit dem Tabulator als Trenner zwischen den Spalten, und daneben eine Beilage .meta.tsv, eine Zeile je Feld. Für CUS_ACTOBJ:

FELD        SAP_TYP  LAENGE  PQ_TYP
ACT_ID      C             20  text
OBJECTTYPE  C              1  text
OBJECTNAME  C             30  text
TCODE       C             20  text
SUBOBJNAME  C             10  text
IMG_POS     N              2  text

PQ_TYP ist der Typ, mit dem Power Query die Spalte lesen soll. IMG_POS ist ein NUMC-Feld, also Ziffern als Text, und bleibt deshalb Text: als Zahl gelesen verlöre 03 die führende Null und passte nicht mehr zum Schlüssel im System. Ein Datumsfeld trägt dort date und kommt in Power Query als Datum an.

Daneben schreibt jeder Abzug eine Zeile in _Katalog.tsv: Quellsystem, Mandant, Tabelle, Zeitpunkt, Zeilenzahl, WHERE-Bedingung, Dauer. Fragt jemand drei Monate später, aus welchem System, mit welcher Bedingung und zu welchem Zeitpunkt eine Zahl stammt, steht die Antwort in einer Datei. Das ist der Unterschied zwischen einem Abzug und einem auditierbaren Abzug.

Ab hier ist es Power Query

Mit den TSVs und ihren Beilagen in einem Ordner liest Power Query jede Tabelle mit den richtigen Typen, ohne dass jemand eine Spalte von Hand umstellt. Dort geht die Arbeit weiter: Aktivitäten mit ihren Pflegeobjekten verbinden, die Views in ihre Tabellen auflösen, den Ast wählen. Wer lieber mit SQL arbeitet, nimmt -Output SQLite -Database und bekommt alle Tabellen in einer Datenbank, mit Typen und Katalog als eigenen Tabellen.

Dafür gibt es doch Produkte

Für SAP-Extraktion gibt es kommerzielle Werkzeuge mit Oberfläche, Zeitplanung und Delta-Logik, und für einen dauerhaften Datenfluss in ein Data Warehouse sind sie richtig. Mindestens eines davon liest selbst über RFC_READ_TABLE, der Zugriff ist derselbe.

Für eine Projektanalyse, die einen Stichtag braucht, nehme ich sie trotzdem selten: lästig ist nicht die Lizenz, sondern die Installation auf einem abgeriegelten Kundenrechner. Die Ladedatei braucht einen Ordner, einen Benutzer und ein paar Minuten.

Die Datei bleibt

Ein SE16N-Abzug ist eine Excel-Datei ohne Herkunft. Eine Ladedatei ist der Abzug selbst. Die Arbeit steckt einmal in der Datei, nicht bei jedem Stichtag wieder in 127 Selektionsbildern.

Vorher: Ein fremdes SAP-System liest man aus seinen Tabellen, nicht aus Workshops.