FILTER

FILTER ist eigentlich super. Ehrlich!
Endlich ein Ausdruck, der einem das lästige Schleifenbauen erspart. Kein LOOP, kein APPEND, kein „IF type = ‘E’“. Stattdessen einfach schön funktional. Eigentlich… Denn natürlich gibt’s da einen Haken. Oder zwei.

Zunächst klingt alles prima und man denkt, man könnte FILTER wie folgt verwenden:

data = FILTER #( itab WHERE type = 'E' ).

Leider funktioniert das nicht so einfach, denn die zu filternde Tabelle braucht einen Sorted Key (entweder als primären oder sekundären Schlüssel). Und den hat man praktisch nie, weil natürlich niemand beim Anlegen seiner internen Tabellen großzügig an künftige FILTER-Spielereien denkt. Häufig ist es auch gar nicht möglich, die Definition der Tabelle zu ändern, denn es kann viele Abhängigkeiten geben, die dann syntaktisch nicht mehr korrekt sind oder man verwendet eine Standard-Tabellendefinition, wie z.B. BAPIRET2_T.

Variante 1: Filtertabelle

Also geht man den anderen Weg mit einer Filtertabelle. Man benötigt hierfür eine Tabelle, die die zu filternden Werte aufnehmen kann. In einem Beispiel, in dem ich nur die Fehlermeldungen aus einer internen Tabelle mit Meldungen haben möchte, sieht dann so aus:

TYPES: BEGIN OF _message,
         type   TYPE msgty,
         number TYPE msgno,
         id     TYPE msgid,
         text   TYPE c LENGTH 100,
       END OF _message,
       _messages TYPE STANDARD TABLE OF _message WITH DEFAULT KEY.

DATA(messages) = VALUE _messages(
  ( type = 'I' number = '004' text = 'start processing' )
  ( type = 'W' number = '103' text = 'full load' )
  ( type = 'E' number = '223' text = 'process already active' )
  ( type = 'E' number = '963' text = 'process cancelled' )
).

TYPES ty TYPE SORTED TABLE OF msgty WITH UNIQUE KEY table_line.
DATA(error_messages) = FILTER #( messages IN VALUE ty( ( 'E' ) ) WHERE type = table_line ).

cl_demo_output=>display( error_messages ).

Das funktioniert, klar. Aber mal ehrlich: bis man den VALUE-Ausdruck für die Filtertabelle gebaut hat, ist der Erkenntnisgewinn überschaubar.
Und an der Stelle fragt man sich: Warum nicht gleich ein LOOP mit IF? Nur um den Filter als funktionalen Ausdruck verwenden zu können?

Diese Variante kannst du jedoch verwenden, ohne dass sie Auswirkungen auf andere Teile der Programmierung hat.

Im Gegensatz zu

Variante 2: Secondary Key

Bei dieser Variante musst du die zu filternde Tabelle so definieren, dass sie einen Sekundärschlüssel besitzt:

DATA messages TYPE STANDARD TABLE OF bapiret2 
              WITH DEFAULT KEY
              WITH NON-UNIQUE SORTED KEY by_type COMPONENTS type.

DATA(error_messages) = FILTER #( messages USING KEY by_type WHERE type = 'E' ).
cl_demo_output=>display( error_messages ).

Die Verwendung ist dann fast so, wie man es erwarten würde: Allerdings musst du den Schlüssel angeben. Du kannst dann aber einfach mit WHERE filtern.

In dem Beispiel habe ich die Standardtabelle für BAPI-Meldungen BAPIRET2 mit dem im Dictionary definierten Tabellentyp BAPIRET2_T.

Um die Tabelle mit Filter nutzen zu können, musste ich der internen Tabelle einen Sekundärschlüssel spendieren. Hierdurch ist der Typ nicht mehr gleich zu BAPIRET2_T, verursacht also eine Inkompatibilität. Möchtest du diese Variante verwenden, dann musst du hier über einen Umweg gehen, zum Beispiel mit CORRESPONDING:

class=>set( it_messages = CORRESPONDING #( error_messages ) ).

Fazit

FILTER ist wie ein teures Schweizer Taschenmesser: beeindruckend gebaut, aber manchmal will man einfach nur schnell eine Schraube festdrehen.

Einen Umfangreichen Performancevergleich unterschiedlicher Varianten findest du bei Software-Heroes: Datenfilterung.

Enno Wulff
Letzte Artikel von Enno Wulff (Alle anzeigen)