Folgende Benutzer bedankten sich beim Autor black_adept für den Beitrag:
user2008
Danke für die schnelle Antwort. Bei mir Matnr und Merkmal nummerisch, wie weiß das System, wann man addieren soll?black_adept hat geschrieben:Schau dir mal den Befehl "COLLECT" an.
Alternativ könntest du auch "SUM" verwenden - aber wenn man mit Gruppenwechsel arbeiten will muss man vorher das Konzept dahinter und die Vorbedingungen verstanden haben.
Code: Alles auswählen.
*&---------------------------------------------------------------------*
*& Report ZTEST4
*&---------------------------------------------------------------------*
REPORT ZTEST4.
TYPES: BEGIN OF TYPE_T,
MATNR TYPE C,
MERKM TYPE C,
MENGE TYPE I,
END OF TYPE_T.
DATA: T TYPE STANDARD TABLE OF TYPE_T WITH HEADER LINE,
RESULT TYPE SORTED TABLE OF TYPE_T WITH UNIQUE KEY MATNR MERKM WITH HEADER LINE.
*** START-OF-SELECTION ***
START-OF-SELECTION.
APPEND VALUE #( MATNR = 'a' MERKM = 'x' MENGE = 30 ) TO T.
APPEND VALUE #( MATNR = 'b' MERKM = 'x' MENGE = 40 ) TO T.
APPEND VALUE #( MATNR = 'a' MERKM = 'y' MENGE = 50 ) TO T.
APPEND VALUE #( MATNR = 'b' MERKM = 'x' MENGE = 20 ) TO T.
APPEND VALUE #( MATNR = 'a' MERKM = 'x' MENGE = 10 ) TO T.
LOOP AT T.
READ TABLE RESULT WITH KEY MATNR = T-MATNR MERKM = T-MERKM. " automatischer BINARY SEARCH da SORTED TABLE
CASE SY-SUBRC.
WHEN 0. " Gibt bereits ein Ergebnis zu dieser Kombination
ADD T-MENGE TO RESULT-MENGE.
MODIFY RESULT INDEX SY-TABIX. " SY-TABIX gesetzt durch den READ TABLE
WHEN OTHERS. " Gibe noch kein Ergebnis zu dieser Kombination; Ergebniszeile erzeugen
RESULT = T. " Kopfzeilen
INSERT RESULT INDEX SY-TABIX. " SY-TABIX gesetzt durch den READ TABLE für sortierte Einfügung in die SORTED TABLE
ENDCASE.
ENDLOOP.
* Hier steht das Ergebnis in der Tabelle RESULT. Der untenstehende LOOP verletzt insofern nicht die Aufgabenbedingung;
* er gibt nur die Tabelle auf dem Bildschirm aus.
LOOP AT RESULT.
WRITE: / RESULT-MATNR, RESULT-MERKM, RESULT-MENGE.
ENDLOOP.
Na hoffentlich numerisch im Sinne von NUMC und nicht im Sinne von INT (das wäre sonst Pfusch, IMHO). Da NUMC technisch ein Charactertyp ist, wird er bei COLLECT nicht addiert.Bei mir Matnr und Merkmal nummerisch, wie weiß das System, wann man addieren soll?
Folgende Benutzer bedankten sich beim Autor DeathAndPain für den Beitrag:
user2008
Herzlichen Dank!DeathAndPain hat geschrieben:Ich habe es ohne COLLECT gemacht - obwohl richtig ist, dass COLLECT auch ein guter Weg wäre.
Code: Alles auswählen.
*&---------------------------------------------------------------------* *& Report ZTEST4 *&---------------------------------------------------------------------* REPORT ZTEST4. TYPES: BEGIN OF TYPE_T, MATNR TYPE C, MERKM TYPE C, MENGE TYPE I, END OF TYPE_T. DATA: T TYPE STANDARD TABLE OF TYPE_T WITH HEADER LINE, RESULT TYPE SORTED TABLE OF TYPE_T WITH UNIQUE KEY MATNR MERKM WITH HEADER LINE. *** START-OF-SELECTION *** START-OF-SELECTION. APPEND VALUE #( MATNR = 'a' MERKM = 'x' MENGE = 30 ) TO T. APPEND VALUE #( MATNR = 'b' MERKM = 'x' MENGE = 40 ) TO T. APPEND VALUE #( MATNR = 'a' MERKM = 'y' MENGE = 50 ) TO T. APPEND VALUE #( MATNR = 'b' MERKM = 'x' MENGE = 20 ) TO T. APPEND VALUE #( MATNR = 'a' MERKM = 'x' MENGE = 10 ) TO T. LOOP AT T. READ TABLE RESULT WITH KEY MATNR = T-MATNR MERKM = T-MERKM. " automatischer BINARY SEARCH da SORTED TABLE CASE SY-SUBRC. WHEN 0. " Gibt bereits ein Ergebnis zu dieser Kombination ADD T-MENGE TO RESULT-MENGE. MODIFY RESULT INDEX SY-TABIX. " SY-TABIX gesetzt durch den READ TABLE WHEN OTHERS. " Gibe noch kein Ergebnis zu dieser Kombination; Ergebniszeile erzeugen RESULT = T. " Kopfzeilen INSERT RESULT INDEX SY-TABIX. " SY-TABIX gesetzt durch den READ TABLE für sortierte Einfügung in die SORTED TABLE ENDCASE. ENDLOOP. * Hier steht das Ergebnis in der Tabelle RESULT. Der untenstehende LOOP verletzt insofern nicht die Aufgabenbedingung; * er gibt nur die Tabelle auf dem Bildschirm aus. LOOP AT RESULT. WRITE: / RESULT-MATNR, RESULT-MERKM, RESULT-MENGE. ENDLOOP.
Folgende Benutzer bedankten sich beim Autor DeathAndPain für den Beitrag:
user2008
Danke Dir! Es freut mich sehr, dass hier so gute Mitglieder wie Du sind!DeathAndPain hat geschrieben:Wie gesagt, Du kannst es auch mit COLLECT bauen. Aber glaub mir, bei meinem obenstehenden Code lacht sich das System auch noch tot, wenn es 10.000 Einträge sind. Ich habe ja extra auf eine sortierte Tabelle gesetzt, damit der READ TABLE binäroptimiert sucht. Wahrscheinlich könnte man sogar eine HASHED TABLE nehmen (müsste dann aber den Code etwas umbauen, da man dann nicht mehr mit SY-TABIX arbeiten kann).
Die meisten Berater würden das aus Faulheit oder Nachlässigkeit mit einer Standardtabelle ohne Suchoptimierung coden und würde im praktischen Betrieb in aller Regel trotzdem keiner merken (auch wenn mir sowas sehr unsympathisch ist).
Gern geschehen. Solch Aufgabe macht mir auch Spaß, besonders weil ich halt versuche, sie nicht nur zu erfüllen, sondern noch eine Goldkante dranzuschneidern.Danke Dir! Es freut mich sehr, dass hier so gute Mitglieder wie Du sind!
Nein. Kopfzeilen gelten als veraltet, aber ich finde sie extrem nützlich. Das ist ein Glaubenskrieg, der auch mit der EInführung von ABAP Objects zu tun hat. Ohne Kopfzeile wird der Code halt länger, weil man die Arbeitszeile explizit hinschreiben muss. Die offizielle Begründung ist, dass so besser verständlich sei, was eine Tabelle und was eine Feldleiste ist, aber ich persönlich halte dieses Argument für vorgeschoben, da ich Kopfzeilen vom Kontext her wunderbar verständlich finde und ABAP Objects dem Programmierer an anderer Stelle abstraktes Denken in einer Größenordnung abverlangt, an die zu den Glanzzeiten der Kopfzeilen (Release 3.x) nicht zu denken war.Meine Tabelle ist ohne Kopfzeile, ist das auch entscheidend?
Tatsächlich muss ich einräumen, dass COLLECT der wesentlich einfacherer Ansatz ist. Ich habe halt nicht dran gedacht, da ich ewig nicht mehr damit gearbeitet habe, aber letztlich muss ich zugeben, dass mein Code nur nachprogrammiert, was COLLECT von Hause aus macht.Es wäre vielleicht Frechheit von mir bei Dir zu fragen, aber wenn Du Zeit hättest, könntest Du mir noch Coding von Collect schreiben? Damit ich noch was dazu lernen kann.
Code: Alles auswählen.
*&---------------------------------------------------------------------*
*& Report ZTEST4
*&---------------------------------------------------------------------*
REPORT ZTEST4.
TYPES: BEGIN OF TYPE_T,
MATNR TYPE C,
MERKM TYPE C,
MENGE TYPE I,
END OF TYPE_T.
DATA: T TYPE STANDARD TABLE OF TYPE_T WITH HEADER LINE,
RESULT TYPE HASHED TABLE OF TYPE_T WITH UNIQUE KEY MATNR MERKM WITH HEADER LINE.
*** START-OF-SELECTION ***
START-OF-SELECTION.
APPEND VALUE #( MATNR = 'a' MERKM = 'x' MENGE = 30 ) TO T.
APPEND VALUE #( MATNR = 'b' MERKM = 'x' MENGE = 40 ) TO T.
APPEND VALUE #( MATNR = 'a' MERKM = 'y' MENGE = 50 ) TO T.
APPEND VALUE #( MATNR = 'b' MERKM = 'x' MENGE = 20 ) TO T.
APPEND VALUE #( MATNR = 'a' MERKM = 'x' MENGE = 10 ) TO T.
LOOP AT T.
COLLECT T INTO RESULT.
ENDLOOP.
* Hier steht das Ergebnis in der Tabelle RESULT. Der untenstehende LOOP verletzt insofern nicht die Aufgabenbedingung;
* er gibt nur die Tabelle auf dem Bildschirm aus.
LOOP AT RESULT.
WRITE: / RESULT-MATNR, RESULT-MERKM, RESULT-MENGE.
ENDLOOP.
Folgende Benutzer bedankten sich beim Autor DeathAndPain für den Beitrag:
user2008
DeathAndPain hat geschrieben:Gern geschehen. Solch Aufgabe macht mir auch Spaß, besonders weil ich halt versuche, sie nicht nur zu erfüllen, sondern noch eine Goldkante dranzuschneidern.Danke Dir! Es freut mich sehr, dass hier so gute Mitglieder wie Du sind!
Nein. Kopfzeilen gelten als veraltet, aber ich finde sie extrem nützlich. Das ist ein Glaubenskrieg, der auch mit der EInführung von ABAP Objects zu tun hat. Ohne Kopfzeile wird der Code halt länger, weil man die Arbeitszeile explizit hinschreiben muss. Die offizielle Begründung ist, dass so besser verständlich sei, was eine Tabelle und was eine Feldleiste ist, aber ich persönlich halte dieses Argument für vorgeschoben, da ich Kopfzeilen vom Kontext her wunderbar verständlich finde und ABAP Objects dem Programmierer an anderer Stelle abstraktes Denken in einer Größenordnung abverlangt, an die zu den Glanzzeiten der Kopfzeilen (Release 3.x) nicht zu denken war.Meine Tabelle ist ohne Kopfzeile, ist das auch entscheidend?
Für die Performance ist es egal.
Tatsächlich muss ich einräumen, dass COLLECT der wesentlich einfacherer Ansatz ist. Ich habe halt nicht dran gedacht, da ich ewig nicht mehr damit gearbeitet habe, aber letztlich muss ich zugeben, dass mein Code nur nachprogrammiert, was COLLECT von Hause aus macht.Es wäre vielleicht Frechheit von mir bei Dir zu fragen, aber wenn Du Zeit hättest, könntest Du mir noch Coding von Collect schreiben? Damit ich noch was dazu lernen kann.
An Deine Adresse muss hier allerdings auch ein Faulheitsvorwurf gehen, denn ich habe mir gerade mal die F1-Hilfe von COLLECT durchgelesen. Das Beispielprogrämmchen, das da unten drin steht, ist im Prinzip schon die Lösung Deiner Programmieraufgabe.
Aber so sei es denn, hier mein Code, umgebaut auf COLLECT. Und aus der F1-Hilfe habe ich mir die Idee geklaut, für das Ergebnis auch gleich eine HASHED TABLE zu nehmen. Macht vermutlich auch den COLLECT effizienter.
Code: Alles auswählen.
*&---------------------------------------------------------------------* *& Report ZTEST4 *&---------------------------------------------------------------------* REPORT ZTEST4. TYPES: BEGIN OF TYPE_T, MATNR TYPE C, MERKM TYPE C, MENGE TYPE I, END OF TYPE_T. DATA: T TYPE STANDARD TABLE OF TYPE_T WITH HEADER LINE, RESULT TYPE HASHED TABLE OF TYPE_T WITH UNIQUE KEY MATNR MERKM WITH HEADER LINE. *** START-OF-SELECTION *** START-OF-SELECTION. APPEND VALUE #( MATNR = 'a' MERKM = 'x' MENGE = 30 ) TO T. APPEND VALUE #( MATNR = 'b' MERKM = 'x' MENGE = 40 ) TO T. APPEND VALUE #( MATNR = 'a' MERKM = 'y' MENGE = 50 ) TO T. APPEND VALUE #( MATNR = 'b' MERKM = 'x' MENGE = 20 ) TO T. APPEND VALUE #( MATNR = 'a' MERKM = 'x' MENGE = 10 ) TO T. LOOP AT T. COLLECT T INTO RESULT. ENDLOOP. * Hier steht das Ergebnis in der Tabelle RESULT. Der untenstehende LOOP verletzt insofern nicht die Aufgabenbedingung; * er gibt nur die Tabelle auf dem Bildschirm aus. LOOP AT RESULT. WRITE: / RESULT-MATNR, RESULT-MERKM, RESULT-MENGE. ENDLOOP.
Code: Alles auswählen.
REPORT ztest.
TYPES: BEGIN OF type_t,
matnr TYPE c,
merkm TYPE c,
menge TYPE i,
END OF type_t.
DATA: t TYPE STANDARD TABLE OF type_t.
DATA: wa_t TYPE type_t.
START-OF-SELECTION.
APPEND VALUE #( matnr = 'a' merkm = 'x' menge = 30 ) TO t.
APPEND VALUE #( matnr = 'b' merkm = 'x' menge = 40 ) TO t.
APPEND VALUE #( matnr = 'a' merkm = 'y' menge = 50 ) TO t.
APPEND VALUE #( matnr = 'b' merkm = 'x' menge = 20 ) TO t.
APPEND VALUE #( matnr = 'a' merkm = 'x' menge = 10 ) TO t.
SORT t.
LOOP AT t INTO wa_t.
FORMAT INTENSIFIED OFF.
WRITE: / wa_t-matnr, wa_t-merkm, wa_t-menge.
AT END OF merkm.
"Gruppenwechsel:
"hier geht er rein, wenn sich der Inhalt des angegeben Feldes ODER(!)
"eines Felds links davon (also im vorliegenden Fall MATNR) ändert
"heisst hier konkret: ändert sich MATNR und/oder MERKM liegt ein Gruppenwechsel vor.
SUM.
"SUM stellt die Gruppensumme aller (echt) numerisch deklarierten
"Felder in den Feldern selbst bereit...
"d.h. in WA_T-MENGE steht nun die Gruppensumme aller MENGEn.
FORMAT INTENSIFIED ON.
WRITE: / 'SUM', wa_t-menge UNDER wa_t-menge.
ENDAT.
ENDLOOP.
Code: Alles auswählen.
Programm ZTEST
-----------------------------
a x 30
a x 10
SUM 40
a y 50
SUM 50
b x 40
b x 20
SUM 60
Folgende Benutzer bedankten sich beim Autor MrBojangles für den Beitrag:
user2008
MrBojangles hat geschrieben:Hallo zusammen,
vielleicht noch der Vollständigkeit halber das Ganze mit den Gruppenwechsel-Funktionen, die ABAP bietet. Dann hast Du ein Füllhorn an Lösungen...;.)
Ausgabe:Code: Alles auswählen.
REPORT ztest. TYPES: BEGIN OF type_t, matnr TYPE c, merkm TYPE c, menge TYPE i, END OF type_t. DATA: t TYPE STANDARD TABLE OF type_t. DATA: wa_t TYPE type_t. START-OF-SELECTION. APPEND VALUE #( matnr = 'a' merkm = 'x' menge = 30 ) TO t. APPEND VALUE #( matnr = 'b' merkm = 'x' menge = 40 ) TO t. APPEND VALUE #( matnr = 'a' merkm = 'y' menge = 50 ) TO t. APPEND VALUE #( matnr = 'b' merkm = 'x' menge = 20 ) TO t. APPEND VALUE #( matnr = 'a' merkm = 'x' menge = 10 ) TO t. SORT t. LOOP AT t INTO wa_t. FORMAT INTENSIFIED OFF. WRITE: / wa_t-matnr, wa_t-merkm, wa_t-menge. AT END OF merkm. "Gruppenwechsel: "hier geht er rein, wenn sich der Inhalt des angegeben Feldes ODER(!) "eines Felds links davon (also im vorliegenden Fall MATNR) ändert "heisst hier konkret: ändert sich MATNR und/oder MERKM liegt ein Gruppenwechsel vor. SUM. "SUM stellt die Gruppensumme aller (echt) numerisch deklarierten "Felder in den Feldern selbst bereit... "d.h. in WA_T-MENGE steht nun die Gruppensumme aller MENGEn. FORMAT INTENSIFIED ON. WRITE: / 'SUM', wa_t-menge UNDER wa_t-menge. ENDAT. ENDLOOP.
Code: Alles auswählen.
Programm ZTEST ----------------------------- a x 30 a x 10 SUM 40 a y 50 SUM 50 b x 40 b x 20 SUM 60
Sorry, aber vorallem den letzten Satz kann ich so nicht unkommentiert stehen lassen:DeathAndPain hat geschrieben:Kopfzeilen gelten als veraltet, aber ich finde sie extrem nützlich. Das ist ein Glaubenskrieg, der auch mit der EInführung von ABAP Objects zu tun hat. Ohne Kopfzeile wird der Code halt länger, weil man die Arbeitszeile explizit hinschreiben muss. Die offizielle Begründung ist, dass so besser verständlich sei, was eine Tabelle und was eine Feldleiste ist, aber ich persönlich halte dieses Argument für vorgeschoben, da ich Kopfzeilen vom Kontext her wunderbar verständlich finde und ABAP Objects dem Programmierer an anderer Stelle abstraktes Denken in einer Größenordnung abverlangt, an die zu den Glanzzeiten der Kopfzeilen (Release 3.x) nicht zu denken war.
Für die Performance ist es egal.
@adt: Wie viele Programme mit Laufzeitproblemen hast du denn schon gesehen, bei denen ein Wechsel zu Feldsymbolen oder Referenzen die Laufzeit auf erträgliche Zeiten gedrückt hätte?a-dead-trousers hat geschrieben:Sorry, aber vorallem den letzten Satz kann ich so nicht unkommentiert stehen lassen:DeathAndPain hat geschrieben:...
Für die Performance ist es egal.
Beim Arbeiten mit Kopfzeilen, werden die Inhalte von der Tabelle in die Kopzeile KOPIERT. Genau gleich wie bei einer WORKAREA (Feldleiste). Diese Art des Zugriffs hat somit die SCHLECHTESTE Performance. Das beste Ergebnis erreicht man mit FIELD-SYMBOLS und das sowohl bei einem rein lesenden Zugriff als auch bei einem schreibenden. Von der Theorie her sollten REFERENZEN gleich schnell arbeiten, sind aber um eine Tick langsamer als die Field-Symbols.
lg ADT
Folgende Benutzer bedankten sich beim Autor black_adept für den Beitrag:
DeathAndPain
@black_adept: Denke global, handle lokal.Wie viele Programme mit Laufzeitproblemen hast du denn schon gesehen, bei denen ein Wechsel zu Feldsymbolen oder Referenzen die Laufzeit auf erträgliche Zeiten gedrückt hätte?
Naja, die gibt es schon, allerdings sind das dann Programme, bei denen die Tabelle via Feldsymbol geändert wird. Da ist der Vorteil gegenüber einer Feldleiste und MODIFY erheblich.black_adept hat geschrieben:@adt: Wie viele Programme mit Laufzeitproblemen hast du denn schon gesehen, bei denen ein Wechsel zu Feldsymbolen oder Referenzen die Laufzeit auf erträgliche Zeiten gedrückt hätte?a-dead-trousers hat geschrieben:Sorry, aber vorallem den letzten Satz kann ich so nicht unkommentiert stehen lassen:DeathAndPain hat geschrieben:...
Für die Performance ist es egal.
Beim Arbeiten mit Kopfzeilen, werden die Inhalte von der Tabelle in die Kopzeile KOPIERT. Genau gleich wie bei einer WORKAREA (Feldleiste). Diese Art des Zugriffs hat somit die SCHLECHTESTE Performance. Das beste Ergebnis erreicht man mit FIELD-SYMBOLS und das sowohl bei einem rein lesenden Zugriff als auch bei einem schreibenden. Von der Theorie her sollten REFERENZEN gleich schnell arbeiten, sind aber um eine Tick langsamer als die Field-Symbols.
lg ADT
Code: Alles auswählen.
REPORT.
PARAMETERS:
p_times TYPE i.
DATA:
gt_test TYPE TABLE OF i.
START-OF-SELECTION.
DO p_times TIMES.
APPEND sy-index TO gt_test.
ENDDO.
GET RUN TIME FIELD DATA(i1).
LOOP AT gt_test ASSIGNING FIELD-SYMBOL(<gs_test>).
ENDLOOP.
GET RUN TIME FIELD DATA(i2).
i2 = i2 - i1.
WRITE: / 'FS:', i2.
GET RUN TIME FIELD i1.
LOOP AT gt_test INTO DATA(gs_test).
ENDLOOP.
GET RUN TIME FIELD i2.
i2 = i2 - i1.
WRITE: / 'Struc:', i2.