Code: Alles auswählen.
READ TABLE auslößer INDEX 1 ASSIGNING FIELD-SYMBOL(<auslößer>).
IF sy-subrc EQ 0.
READ TABLE <auslößer>-tarif ASSIGNING FIELD-SYMBOL(<tarif>)
WITH KEY nummer = var1 tarif = var2.
IF sy-subrc EQ 0.
<tarif>-Betrag = ...
ENDIF.
ENDIF.
Code: Alles auswählen.
REPORT ZTEST4.
TYPES: BEGIN OF TARIFZEILE,
NUMMER TYPE NUMC4,
TARIF TYPE NUMC2,
BETRAG(6) TYPE P DECIMALS 2,
END OF TARIFZEILE,
T_TARIF TYPE HASHED TABLE OF TARIFZEILE WITH UNIQUE KEY NUMMER TARIF, " schön brav Index auf die Spalten, nach denen wir nachher suchen wollen
BEGIN OF AUSLOESERZEILE,
TARIF TYPE T_TARIF,
END OF AUSLOESERZEILE,
T_AUSLOESER TYPE STANDARD TABLE OF AUSLOESERZEILE WITH EMPTY KEY.
DATA: AUSLOESER TYPE T_AUSLOESER.
START-OF-SELECTION.
* Tabelle Auslöser mit einer Zeile vorfüllen, deren Untertabelle auch eine Zeile hat, die aber noch keinen Betrag enthält
AUSLOESER = VALUE #( ( TARIF = VALUE #( ( NUMMER = '0001' TARIF = '01' ) ) ) ).
* Der Zeile dieser Untertabelle den Betrag 15 geben
ASSIGN AUSLOESER[ 1 ]-TARIF[ NUMMER = '0001' TARIF = '01' ]-BETRAG TO FIELD-SYMBOL(<BETRAG>).
IF SY-SUBRC <> 0.
" hier irgendwas machen, falls entweder AUSLOESER überhaupt keine erste Zeile hat oder deren
" Untertabelle keine Zeile mit NUMMER = '0001' und TARIF = '01' hat
ELSE.
<BETRAG> = 15.
ENDIF.
Folgende Benutzer bedankten sich beim Autor DeathAndPain für den Beitrag:
a-dead-trousers
Nein, muss man nicht.a-dead-trousers hat geschrieben: ↑07.06.2023 18:08In der neuen Sytax müsste man, wenn man sich nicht 100% sicher ist, dass z.B. die Tabelle Tarif einen Eintrag mit dem gesuchten Schüssel hat, einen TRY ... CATCH herumbauen oder mit line_exists erst wieder zweimal auf die Daten zugreifen um Fehler zu vermeiden.
Code: Alles auswählen.
DATA(eintrag) = VALUE #( ausloeser[ feld = abc ] optional ).
Folgende Benutzer bedankten sich beim Autor ewx für den Beitrag:
a-dead-trousers
Diese Variante hatte ich auch im Auge, aber sie bietet keine Reaktionsmöglichkeit auf den Fall, dass die Zeile nicht da ist, sondern man bekommt dann einfach einen initialen Wert. Häufig ist das gut genug, aber in Micha_Elas Beispiel hatte ich schon den Eindruck, dass solch Fall konkret mit abgedeckt werden sollte. Und spätestens wenn der initiale Wert auch ein tatsächlicher Rückgabewert sein könnte, ist anhand dessen auch mit nachgeschaltetem IF nicht mehr erkennbar, ob die Zeile gefunden wurde oder nicht.ewx hat geschrieben: ↑07.06.2023 19:36Nein, muss man nicht.Code: Alles auswählen.
DATA(eintrag) = VALUE #( ausloeser[ feld = abc ] optional ).
Das mag so sein, aber in meinen Augen ist ein LINE_EXISTS und dann ein nachfolgender READ mit genau derselben Suchbedingung ein extrem unbeholfen und anfängerhaft wirkender Programmierstil, als ob der Programmierer halt nicht gewusst hätte, wie er es besser machen kann, als zweimal dasselbe zu suchen. Vermutlich war der SAP klar, dass viele Entwickler nicht gut programmieren können, und deshalb werden sie dann als Unterstützungskrücke diese Pufferung eingebaut haben.ewx hat geschrieben: ↑07.06.2023 19:36zum doppelten READ mit prüfen LINE_EXISTS und dann tatsächlichem READ:
Ja, es wird zweimal gelesen. Allerdings sind die neuen Befehle sehr gut optimiert, so dass nicht wirklich zweimal gelesen wird. Ich meine gelesen zu haben, dass eine interne Pufferung eingebaut ist, um genau so einen Fall abzudecken.
Vor langer Zeit habe ich das mal gemessen. Der Zugriff mit TRY-CATCH ist vor allem dann langsamer, wenn es die gesuchte Zeile tatsächlich nicht gibt. Nach meiner (zugegebenermaßen dunklen) Erinnerung kam ich da auf die siebenfache Laufzeit (d.h. +600%!!) verglichen mit eleganteren Ansätzen. Das hängt damit zusammen, dass ABAP dann extra ein Exceptionobjekt erzeugen muss, und das kostet richtig.ewx hat geschrieben: ↑07.06.2023 19:36Zusätzlich möchte ich mal mit der Mär aufräumen, dass die TRY-CATCHES langsam sind. Ja, sie sind langsamer, als das Abfragen des SUBRC nach dem READ, aber nicht so langsam, als dass man es auf Teufel komm raus vermeiden müsste. Bei Tests, die ich gemacht habe, ist der Try-Catch im Zusammenhang mit Tabellenzugriffen ca. 50% langsamer.
auf jeden Fall. Die Try Catch-Variante ist fast immer "hässlich". Sehr viel Code-Noise um einen einzelnen Befehl herum.DeathAndPain hat geschrieben: ↑08.06.2023 15:56So oder so sehe ich aber nicht viel, was an dieser Stelle für TRY-CATCH spricht, weil die Variante mit dem ASSIGN auf der ganzen Linie besser ist, auch hinsichtlich der Lesbarkeit.
Code: Alles auswählen.
1000x READ TABLE 280.776
1000x TRY-CATCH w/o INTO 287.318
1000x TRY-CATCH with INTO 575.574
1000x VALUE OPTIONAL 829.144
Code: Alles auswählen.
DATA items TYPE STANDARD TABLE OF vbap WITH DEFAULT KEY.
DATA(vbeln) = CONV numc10( 0 ).
DO 1000 TIMES.
ADD 1 TO vbeln.
DO 10 TIMES.
APPEND VALUE #( vbeln = vbeln posnr = sy-index matnr = 'ABC' kwmeng = 10 vrkme = 'ST' ) TO items.
ENDDO.
ENDDO.
GET RUN TIME FIELD DATA(start).
DO 1000 TIMES.
READ TABLE items INTO DATA(item) WITH KEY vbeln = CONV #( sy-index ) posnr = 99.
ENDDO.
GET RUN TIME FIELD DATA(stopp).
DATA(diff) = stopp - start.
WRITE : / '1000x READ TABLE', AT 50 diff.
GET RUN TIME FIELD start.
DO 1000 TIMES.
TRY.
DATA(item2) = items[ vbeln = CONV #( sy-index ) posnr = 99 ].
CATCH cx_sy_itab_line_not_found.
ENDTRY.
ENDDO.
GET RUN TIME FIELD stopp.
diff = stopp - start.
WRITE : / '1000x TRY-CATCH w/o INTO', AT 50 diff.
DO 1000 TIMES.
TRY.
DATA(item3) = items[ vbeln = CONV #( sy-index ) posnr = 99 ].
CATCH cx_sy_itab_line_not_found INTO DATA(error).
ENDTRY.
ENDDO.
GET RUN TIME FIELD stopp.
diff = stopp - start.
WRITE : / '1000x TRY-CATCH with INTO', AT 50 diff.
DO 1000 TIMES.
DATA(item4) = VALUE #( items[ vbeln = CONV #( sy-index ) posnr = 99 ] OPTIONAL ).
ENDDO.
GET RUN TIME FIELD stopp.
diff = stopp - start.
WRITE : / '1000x VALUE OPTIONAL', AT 50 diff.
Folgende Benutzer bedankten sich beim Autor a-dead-trousers für den Beitrag:
ewx
Wenn der initiale Wert gefunden werden könnte, gibt es sehr häufig trotzdem Werte, von denen man weiß, dass sie nicht vorkommen können. In solchen Fällen definiere ich eine Konstante mit einem Wert der nicht vorkommen kann und verwende statt des OPTIONAL Zusatzes den DEFAULT Zusatz und vergleiche danach ob die Konstante getroffen wurde oder nicht.DeathAndPain hat geschrieben: ↑08.06.2023 15:56Und spätestens wenn der initiale Wert auch ein tatsächlicher Rückgabewert sein könnte, ist anhand dessen auch mit nachgeschaltetem IF nicht mehr erkennbar, ob die Zeile gefunden wurde oder nicht.
Folgende Benutzer bedankten sich beim Autor black_adept für den Beitrag:
DeathAndPain
In der Tat. Da fehlen so einige GET RUN TIME FIELD start. Da misst Du also bei jedem Durchgang die Laufzeiten der vorherigen Durchgänge mit.
Dass da auch DEFAULT geht, hatte ich gar nicht auf dem Schirm. Vielen Dank; wieder was gelernt.black_adept hat geschrieben:Wenn der initiale Wert gefunden werden könnte, gibt es sehr häufig trotzdem Werte, von denen man weiß, dass sie nicht vorkommen können. In solchen Fällen definiere ich eine Konstante mit einem Wert der nicht vorkommen kann und verwende statt des OPTIONAL Zusatzes den DEFAULT Zusatz und vergleiche danach ob die Konstante getroffen wurde oder nicht.
boah, wie peinlich... 😬DeathAndPain hat geschrieben: ↑09.06.2023 15:53In der Tat. Da fehlen so einige GET RUN TIME FIELD start. Da misst Du also bei jedem Durchgang die Laufzeiten der vorherigen Durchgänge mit.
Code: Alles auswählen.
1000x READ TABLE 273.292
1000x TRY-CATCH w/o INTO 279.639
1000x TRY-CATCH with INTO 274.695
1000x VALUE OPTIONAL 266.569
Na ja, Du machst jeweils 1000x exakt den gleichen Zugriff. Wenn da wirklich irgendwelche Pufferungsalgorithmen im Compiler verbaut sind, dann kann das ganze Ergebnis locker für die Tonne sein.
Ihr habt beide irgendwie recht. Und SAP hat das auch so gesehen und uns die Möglichkeit gegeben Tabellen mit weiteren Schlüsseln zu versehen [https://help.sap.com/doc/abapdocu_752_i ... ondary.htm], so dass es man wie bei Hannah Montana "Best of Both Worlds" bekommt.DeathAndPain hat geschrieben: ↑09.06.2023 17:28Zudem suchst Du in einer Standardtabelle, was hoffentlich nicht praxisrelevant ist.
Stimmt, da habe ich den Code nicht genau genug gelesen und den geschachtelten LOOP am Anfang nicht gesehen.