Diskussion dynamische SELECT-Statments

Alles Rund um SAP®.
8 Beiträge • Seite 1 von 1
8 Beiträge Seite 1 von 1

Diskussion dynamische SELECT-Statments

Beitrag von black_adept (Top Expert / 4080 / 125 / 934 ) »
Moin allerseits,

heute mal keine Knobelaufgabe sondern ein Diskussionsanregung zu dynamischen SELECT-Statements.
Ich habe ein simples Programm geschrieben, welches auf 2 verschiedene Arten Daten sammelt. Es wird je nach Schalterstellung des Programms ein SELECT ausgeführt und in beiden Fällen der gleiche SELECT an die Datenbank übermittelt.

Ich hoffe auf eine rege Diskussion und hoffe Antworten zu bekommen auf einige der folgenden Punkte.
  1. Lesbarkeit
  2. Wartbarkeit
  3. Erweiterbarkeit
  4. Performance
  5. Fehleranalyse
  6. Was, wenn einige der SELECT-Komponenten oder beteiligten Tabellen drastisch größer sind - ändert das etwas an den anderen Anmerkungen
  7. Was muss gegeben sein um die (evtl. nicht in allen SELECT-Komponenten) dynamische Version zu präferieren

Code: Alles auswählen.

REPORT.


CLASS lcl_demo DEFINITION FINAL.
  PUBLIC SECTION.
    TYPES: BEGIN OF mts_data,
             msehi TYPE t006-msehi,
             msehl TYPE t006a-msehl,
             zaehl TYPE t006-zaehl,
             nennr TYPE t006-nennr,
             txdim TYPE t006t-txdim,
             dimid TYPE t006-dimid,
           END OF mts_data.
    CLASS-METHODS:
      method1,
      method2.
    CLASS-DATA:
    mt_data TYPE STANDARD TABLE OF mts_data WITH EMPTY KEY.
ENDCLASS.
SELECTION-SCREEN BEGIN OF BLOCK choose_method WITH FRAME.
  PARAMETERS: method1 RADIOBUTTON GROUP rb1,
              method2 RADIOBUTTON GROUP rb1.
SELECTION-SCREEN END OF BLOCK choose_method.

PARAMETERS: rb_all RADIOBUTTON GROUP rb2,
            rb_yes RADIOBUTTON GROUP rb2,
            rb_no  RADIOBUTTON GROUP rb2.

END-OF-SELECTION.
  CASE 'X'.
    WHEN method1. lcl_demo=>method1( ).
    WHEN method2. lcl_demo=>method2( ).
  ENDCASE.
* Ausgabe
  cl_salv_table=>factory( IMPORTING r_salv_table   = DATA(go_salv)
                          CHANGING  t_table        = lcl_demo=>mt_data ).
  go_salv->get_functions( )->set_all( ).
  go_salv->display( ).




CLASS lcl_demo IMPLEMENTATION.
  METHOD method1.
    CASE 'X'.
      WHEN rb_all. " Alles - keine DIMID und DIMID-Text
        SELECT tab1~msehi, tab1~zaehl, tab1~nennr, texttab~msehl
          FROM t006 AS tab1 JOIN t006a AS texttab ON tab1~msehi = texttab~msehi AND 'D' = texttab~spras
          ORDER BY tab1~msehi
          INTO CORRESPONDING FIELDS OF TABLE @mt_data.

      WHEN rb_yes. " nur, wenn es MIND. EINE andere Mengeneinheit mit gleicher Dimension gibt.  Dann mit DIMID und DIMID-Text und nach DIMID sortieren
        SELECT tab1~msehi, tab1~dimid, tab1~zaehl, tab1~nennr, texttab~msehl, textdim~txdim
          FROM t006 AS tab1 JOIN t006a AS texttab ON tab1~msehi = texttab~msehi AND 'D' = texttab~spras
                            JOIN t006t AS textdim ON tab1~dimid = textdim~dimid AND 'D' = textdim~spras
          WHERE EXISTS ( SELECT * FROM t006 WHERE dimid = tab1~dimid AND msehi <> tab1~msehi )
          ORDER BY tab1~dimid, tab1~msehi
          INTO CORRESPONDING FIELDS OF TABLE @mt_data.

      WHEN rb_no.  " nur, wenn es KEINE      andere Mengeneinheit mit gleicher Dimension gibt.  Dann nur mit DIMID ohne text
        SELECT tab1~msehi,
               tab1~dimid,
               tab1~zaehl,
               tab1~nennr ,
               texttab~msehl
          FROM t006 AS tab1 JOIN t006a AS texttab ON tab1~msehi = texttab~msehi AND 'D' = texttab~spras
          WHERE NOT EXISTS ( SELECT * FROM t006 WHERE dimid = tab1~dimid AND msehi <> tab1~msehi )
          ORDER BY tab1~dimid, tab1~msehi
          INTO CORRESPONDING FIELDS OF TABLE @mt_data.

    ENDCASE.

  ENDMETHOD.

  METHOD method2.
* Allgemein gültig
    data(lv_fieldlist)  = 'tab1~msehi,tab1~zaehl,tab1~nennr,texttab~msehl'.
    data(lv_datasource) = |t006 AS tab1 JOIN t006a AS texttab ON tab1~msehi = texttab~msehi AND 'D' = texttab~spras|.
    data(lv_where)      = ''.
    data(lv_order)      = 'tab1~msehi'.
    CASE 'X'.
      WHEN rb_all. " Alles - keine DIMID und DIMID-Text

      WHEN rb_yes. " nur, wenn es MIND. EINE andere Mengeneinheit mit gleicher Dimension gibt.  Dann mit DIMID und DIMID-Text und nach DIMID sortieren
        lv_fieldlist &&= ',tab1~dimid, textdim~txdim'.
        lv_datasource &&= | JOIN t006t AS textdim ON tab1~dimid = textdim~dimid AND 'D' = textdim~spras|.
        lv_where = 'EXISTS ( SELECT * FROM t006 WHERE dimid  = tab1~dimid AND msehi <> tab1~msehi )'.
        lv_order = |tab1~dimid,{ lv_order }|.

      WHEN rb_no.  " nur, wenn es KEINE      andere Mengeneinheit mit gleicher Dimension gibt.  Dann nur mit DIMID ohne text
        lv_fieldlist &&= ',tab1~dimid'.
        lv_where = 'NOT EXISTS ( SELECT * FROM t006 WHERE dimid  = tab1~dimid AND msehi <> tab1~msehi )'.
        lv_order = |tab1~dimid,{ lv_order }|.

    ENDCASE.

    SELECT (lv_fieldlist)
      FROM (lv_datasource)
      WHERE (lv_where)
      ORDER BY (lv_order)
      INTO CORRESPONDING FIELDS OF TABLE @mt_data.

  ENDMETHOD.

ENDCLASS.
live long and prosper
Stefan Schmöcker

email: stefan@schmoecker.de

gesponsert
Stellenangebote auf ABAPforum.com schalten
kostenfrei für Ausbildungsberufe und Werksstudenten


Re: Diskussion dynamische SELECT-Statments

Beitrag von jocoder (Specialist / 343 / 3 / 102 ) »
Die erste Variante mit statischen SELECT-Statements war besser nachvollziehbar. Dynamische SELECT-Statements sind meiner Meinung nach nur sinnvoll, wenn ein oder mehrere Tokens (Selektionsliste, WHERE-Bedingung) erst zur Laufzeit vorliegen. Bei deinem Programm sind alle Tokens statisch. Wenn die SELECT-Statements wachsen, könnten Sie noch in eigene Methoden ausgelagert werden:

Code: Alles auswählen.

CLASS lcl_demo IMPLEMENTATION.
  METHOD method1.
    CASE abap_true.
      WHEN rb_all.
           read_all_units( ).
      WHEN rb_yes.
          read_units_multiple_dimensions( ).
      WHEN rb_no.
         read_units_unique_dimensions( ).
    ENDCASE.

  ENDMETHOD.

  METHOD read_all_units.

        " Alles - keine DIMID und DIMID-Text
        SELECT tab1~msehi, tab1~zaehl, tab1~nennr, texttab~msehl
          FROM t006 AS tab1 JOIN t006a AS texttab ON tab1~msehi = texttab~msehi AND 'D' = texttab~spras
          ORDER BY tab1~msehi
          INTO CORRESPONDING FIELDS OF TABLE @mt_data.

  ENDMETHOD.

  METHOD read_units_multiple_dimension.

        " nur, wenn es MIND. EINE andere Mengeneinheit mit gleicher Dimension gibt.  Dann mit DIMID und DIMID-Text und nach DIMID sortieren
        SELECT tab1~msehi, tab1~dimid, tab1~zaehl, tab1~nennr, texttab~msehl, textdim~txdim
          FROM t006 AS tab1 JOIN t006a AS texttab ON tab1~msehi = texttab~msehi AND 'D' = texttab~spras
                            JOIN t006t AS textdim ON tab1~dimid = textdim~dimid AND 'D' = textdim~spras
          WHERE EXISTS ( SELECT * FROM t006 WHERE dimid = tab1~dimid AND msehi <> tab1~msehi )
          ORDER BY tab1~dimid, tab1~msehi
          INTO CORRESPONDING FIELDS OF TABLE @mt_data.

  ENDMETHOD.

  METHOD read_units_unique_dimension.

        " nur, wenn es KEINE andere Mengeneinheit mit gleicher Dimension gibt.  Dann nur mit DIMID ohne text
        SELECT tab1~msehi,
               tab1~dimid,
               tab1~zaehl,
               tab1~nennr ,
               texttab~msehl
          FROM t006 AS tab1 JOIN t006a AS texttab ON tab1~msehi = texttab~msehi AND 'D' = texttab~spras
          WHERE NOT EXISTS ( SELECT * FROM t006 WHERE dimid = tab1~dimid AND msehi <> tab1~msehi )
          ORDER BY tab1~dimid, tab1~msehi
          INTO CORRESPONDING FIELDS OF TABLE @mt_data.

  ENDMETHOD.

ENDCLASS.

Re: Diskussion dynamische SELECT-Statments

Beitrag von a-dead-trousers (Top Expert / 4394 / 223 / 1182 ) »
ad 1) Lesbarkeit
Ich finde man tut sich dank der Syntaxhervorhebung bei statischen SELECTs schon leichter sie zu lesen. Auch wirkt das Statement nicht so "zerrissen" wie mit den einzelnen dynamischen Teilen die zuvor in Strings angegeben werden müssen. Grundsätzlich versuche ich aus diesen Gründen auch JOINs oder ähnliche Konstrukte aus meinen SELECTs möglichst zu verbannen indem ich dafür (CDS-)Views anlege, die zudem dann auch wiederverwendbar sind.
ad 2+3) Wartbarkeit und Erweiterbarkeit
Die beiden Punkte sind für mich ein- und dasselbe. Denn, wenn man sich schwer mit der Wartung des Codes tut wird auch die Erweiterbarkeit darunter leiden. Daher läuft alles darauf hinaus, wie man mit der Entwicklung begonnen hat, um beides nach bestem Wissen und Gewissen zu unterstützen.
Grundsätzlich finde ich aber auch hier, dass die Wartbarkeit bei statischen SELECTs um ein vielfaches leichter ist, auch weil einem die Syntaxprüfung hier unterstützt. Wenn man sich ein eingermaßen zugängliches Konzept (z.B.: DAO) zurechtlegt, kann man auch die Erweiterbarkeit mit statischen SELECTs relativ mühelos umsetzen. Ich verwende hier je Tabelle oder View (generierte) Klassen, welche die SELECT Statements kappseln und je nachdem welche Felder ich haben möchte, werden mehrere Methoden mit dem jeweiligen statischen RETURNING Typ angeboten. Die Felder für die WHERE Klausel sind in einem eigenen Filter-Objekt gekapselt und können so für jede Methode wiederverwendet werden. Die Filter selbst bestehen aus einer Liste von Range-Tabellen die beim SELECT mittels AND-Verknüpfung kombiniert werden (ähnlich wie in der SE16).
4) Performance
Ich denke nicht, dass die Performance zwischen einem identen statischen und dynamischen SELECT Statement viel variieren wird.
5) Fehleranalyse
siehe 1) und 2)
6) Größe (?)
Ich verstehe hier die Frage nicht so ganz. Zielt das irgendwie in die Richtung "Größenbeschränkung eines (dyn.) SELECT"?
Grundsätzlich sollte das aber auch bei einem statischen SELECT auftreten und ist für mich somit kein entscheidender Faktor.
7) Vorrausstzungen für dyn. SELECT
Die ist für mich nur gegeben, wenn die Grundmenge der selektierten Tabellen statisch nicht definiert ist. Also z.B. wenn man so etwas ähnliches wie die SE16 baut um in mehreren Tabellen zu suchen.
In allen anderen Fällen lassen sich die SELECT Statements auf handhabbare statische Statements herunterbrechen (zur Not auch über mehrmalige Aufrufe)

EDIT:
Ich merke gerade, dass ich in den letzten Jahren immer weniger Komplexität in meine SELECTs haben möchte. 😅
Theory is when you know something, but it doesn't work.
Practice is when something works, but you don't know why.
Programmers combine theory and practice: Nothing works and they don't know why.

ECC: 6.18
Basis: 7.50

Re: Diskussion dynamische SELECT-Statments

Beitrag von jocoder (Specialist / 343 / 3 / 102 ) »
@a-dead-trousers Bei CDS-Views muss man dann nur auf die Namenskonvention aufpassen, sodass man die Views später auch auseinander halten kann. Es ist schnell passiert, dass zumselben Schlagwort ein dutzend ähnlicher Views existieren. Mir ist es mal beim Thema Warenausgang passiert (ein View, der MSEG, MKPF und LIKP joint, der nächste View, der dann den View mit Daten aus dem Kundenauftrag anreichert usw.). Bei einigen Views hilft sicherlich ein Applikationspräfix im Namen, bei Views, die Applikationsübergreifend sind, ist es schwer eine sinnvolle Namenskonvention einzuführen.

Re: Diskussion dynamische SELECT-Statments

Beitrag von black_adept (Top Expert / 4080 / 125 / 934 ) »
Moin a-d-t und JoCoder,

vielen Dank für die ersten Antworten.

@JoCoder: Ja - ich würde das normalerweise auch in mehrere Methoden refactoren. Aber das Demoprogramm sollte halt möglichst schlank sein.

@both: Ihr beide schlagt vor statt des (einen) dynamischen SELECTs wegen der Lesbarkeit/Wartbarkeit lieber 3 statische SELECTs zu verwenden.
Und hier kommt jetzt meine explizite Nachfrage ( geboren aus einem aktuellen Programm welches ich gerade entwickele ):

Erweiterbarkeit: Ich bin mir sicher, dass über die nächsten Jahre weitere Felder zur SELECT-Feldliste hinzukommen werden, die für ALLE SELECTs notwendig sind. Diese müssen dann in allen statischen SELECTs nachgezogen werden und das birgt eine Fehleranfälligkeit, dass jemand das einfach in einem der Teile vergisst.
Und im Code heißt es immer "gleiche Programmcodes sollten in eine Methode refactored werden" - Warum nicht bei SELECTs?

Wartbarkeit: In meinem Beispiel ist es die WHERE-Bedingung mit einem EXISTS Subselect , welche bei statischer Verwendung die Ursache ist, mehrere Pfade einzuschlagen zu müssen. Was ist, wenn es mehrere solcher Nebenbedingungen gibt ( in einem aktuellen Programm sind es 2 --> es müssten quasi 3*3 = 9 statische SELECTs verwendet werden )?

Was haltet ihr von Mischformenen: wie etwa

Code: Alles auswählen.

SELECT...
FROM MARA
WHERE MATNR in S_MATNR
  AND ( lv_where_1 )
  AND ( lv_where_2 )
...
a-dead-trousers hat geschrieben:
05.10.2021 08:23
Ich merke gerade, dass ich in den letzten Jahren immer weniger Komplexität in meinen SELECTs haben möchte. 😅
Geht mir in der Theorie ähnlich. Aber auf HANA-Systemen stelle ich fest, dass es in der Praxis in die andere Richtung bei mir geht.
live long and prosper
Stefan Schmöcker

email: stefan@schmoecker.de

Re: Diskussion dynamische SELECT-Statments

Beitrag von a-dead-trousers (Top Expert / 4394 / 223 / 1182 ) »
@jocoder
Ja, die Bennenung bei Views ist ein Knackpunkt (um nicht zu sagen Kackpunkt), weil man nur 16 Zeichen hat. Wenn dann noch bis zu 7 für einen Namensraum wegfallen wird es richtig eng.

@black_adept
In deinem Beispielfall würde ich einen CDS-View für die Grundmenge ("READ_UNITS") anlegen und je einen mit EXIST und NOT EXISTS der auf der Grundmenge aufbaut.
Kommen später mal neue Felder dazu müssen sowieso alle drei Views angepasst werden, sonst geht es ja (syntaktisch) im Programm nicht weiter und ein "vergessen" ist faktisch ausgeschlossen. Wenn du dann noch die jeweiligen DDIC Views als Grundlage für diverse (interne) Strukturen und Tabellentypen nimmst, arbeiten auch alle Verwender der Views immer auf dem aktuellsten Stand.
Theory is when you know something, but it doesn't work.
Practice is when something works, but you don't know why.
Programmers combine theory and practice: Nothing works and they don't know why.

ECC: 6.18
Basis: 7.50

Re: Diskussion dynamische SELECT-Statments

Beitrag von black_adept (Top Expert / 4080 / 125 / 934 ) »
a-dead-trousers hat geschrieben:
05.10.2021 11:37
In deinem Beispielfall würde ich einen CDS-View für die Grundmenge ("READ_UNITS") anlegen und je einen mit EXIST und NOT EXISTS der auf der Grundmenge aufbaut.
Und bei 2 "EXIST/NOT EXISTS/EGAL" Bedingungen würdest du dann 9 CDS-Views bauen?
live long and prosper
Stefan Schmöcker

email: stefan@schmoecker.de

Re: Diskussion dynamische SELECT-Statments

Beitrag von a-dead-trousers (Top Expert / 4394 / 223 / 1182 ) »
black_adept hat geschrieben:
05.10.2021 11:42
Und bei 2 "EXIST/NOT EXISTS/EGAL" Bedingungen würdest du dann 9 CDS-Views bauen
Dann würde ich mal anfangen mich zu fragen, ob man das nicht irgendwie weniger kompliziert lösen kann. 😉
z.B.: die Query so auftrennen, dass zwei View-Blöcke mit EXIST/NOT EXISTS/EGAL entstehen, die dann im SELECT vom Programm ja nach Anforderung zusammengefügt werden (JOIN).
Theory is when you know something, but it doesn't work.
Practice is when something works, but you don't know why.
Programmers combine theory and practice: Nothing works and they don't know why.

ECC: 6.18
Basis: 7.50

Seite 1 von 1

Vergleichbare Themen

7
Antw.
2882
Views
Dynamische Select-Anweisung
von bliP! » 06.02.2006 13:54 • Verfasst in ABAP® für Anfänger
1
Antw.
1738
Views
Dynamische Select mit Where und Variablen
von c0lt.seavers » 11.04.2008 14:17 • Verfasst in ABAP® Core
2
Antw.
985
Views
Dynamische SELECT-Anweisung
von mareikemei92 » 17.07.2019 19:16 • Verfasst in ABAP® Core
8
Antw.
12353
Views
dynamische Where -Bedingung mit Select-Option
von BesenWesen » 21.08.2006 12:12 • Verfasst in ABAP® für Anfänger
2
Antw.
541
Views
Dynamische Select Abfrage mit String Variabel
von frankoline » 27.04.2023 10:56 • Verfasst in ABAP® für Anfänger

Newsletter Anmeldung

Keine Beiträge verpassen! Wöchentlich versenden wir lesenwerte Beiträge aus unserer Community.
Die letzte Ausgabe findest du hier.
Details zum Versandverfahren und zu Ihren Widerrufsmöglichkeiten findest du in unserer Datenschutzerklärung.