Datenbanktabellen angeben 

Die FROM-Klausel bestimmt die Datenbanktabellen, von denen die Daten in die Selektion der SELECT-Klausel gelesen werden. Es kann entweder eine einzelne Tabelle angegeben werden oder es können mehrere Tabellen über innere und äußere Joins verknüpft werden. Einzelne Datenbanktabellen können statisch oder dynamisch angegeben werden und ihre Namen können durch Alternativnamen ersetzt werden. In der FROM-Klausel kann weiterhin die SAP-Pufferung umgangen und die Anzahl der zu lesenden Zeilen eingeschränkt werden.

Der Ausdruck Datenbanktabelle steht hier auch immer stellvertretend für einen View im ABAP Dictionary. Ein View ist eine im Dictionary vordefinierte Verknüpfung mehrerer Datenbanktabellen und stellt somit einen programmübergreifenden statischen Join dar. Überall, wo in der FROM-Klausel eine Datenbanktabelle angeben werden kann, kann auch der Name eines Views stehen.

Die FROM-Klausel läßt sich in zwei Teile für die Angabe von Datenbanktabellen und weitere Zusätze unterteilen:

SELECT... FROM <tables> <options>...

In <tables> werden die Namen der Datenbanktabellen angegeben und Joins definiert. In <options> kann der Datenbankzugriff durch weitere Zusätze gesteuert werden.

Einzelne Datenbanktabelle statisch angeben

Um den Namen einer einzelnen Datenbanktabelle statisch anzugeben, schreibt man für <tables>:

SELECT... FROM <dbtab> [AS <alias>] <options> . ..

Die Datenbanktabelle <dbtab> muß im ABAP Dictionary bekannt sein. Mit dem AS-Zusatz kann man die Datenbanktabelle für den Gebrauch in der SELECT-, FROM-, WHERE-, und GROUP BY-Klausel in den Alternativnamen <alias> umbenennen. Dadurch können Doppeldeutigkeiten bei der Verwendung mehrerer Datenbanktabellen ausgeschlossen werden, insbesondere wenn eine Datenbanktabelle mehrmals in einem Join-Ausdruck verwendet wird. Wenn ein Alternativnamen definiert wird, darf nur dieser und nicht mehr der Name der Datenbanktabelle in den Klauseln der SELECT-Anweisung verwendet werden.

Einzelne Datenbanktabelle dynamisch angeben

Um den Namen einer einzelnen Datenbanktabelle dynamisch anzugeben, schreibt man für <tables>:

SELECT... FROM (<name>) <options> . ..

Das Feld <name> muß den Namen einer Datenbanktabelle, die im ABAP Dictionary bekannt ist, in Großbuchstaben enthalten. Bei der dynamischen Angabe der Datenbanktabelle kann die leere INTO-Klausel, die alle Spalten einer Zeile in den Arbeitsbereich <dbtab> stellt, nicht verwendet werden. Es kann auch kein alternativer Tabellennamen angegeben werden.

Mehrere Datenbanktabellen als Inner Join angeben

Beim Zugriff auf relationale Datenbanktabellen müssen in der Regel Daten aus mehreren Tabellen auf einmal in ein Anwendungsprogramm geladen werden. Um mehrere Datenbanktabellen in einer einzigen SELECT-Anweisung so zu verknüpfen, daß die Daten der beteiligten Tabellen eine gemeinsame Bedingung erfüllen, schreibt man für <tables> folgenden Join-Ausdruck:

SELECT...
...
  FROM
<tab> [INNER] JOIN <dbtab> [AS <alias>] ON <cond> <options>
...

Hierbei ist <dbtab> eine einzelne Datenbanktabelle und <tab> ist entweder auch eine einzelne Datenbanktabelle oder selbst ein Join-Ausdruck. Die einzelnen Datenbanktabellen müssen wie oben statisch angegeben werden, wobei auch alternative Tabellennamen vergeben werden können. Jeder Join-Ausdruck kann mit runden Klammern abgegrenzt werden. Der Zusatz INNER ist optional.

Ein Join-Ausdruck verknüpft jede selektierte Zeile von <tab> mit den Zeilen in <dbtab>, welche die Bedingung <cond> erfüllen. Es werden also immer von rechts eine bis mehrere Zeilen einer Datenbanktabelle mit jeweils einer Zeile der linken Datenbanktabelle bzw. des dort definierten Joins verknüpft. Falls es in <dbtab> keine Zeilen gibt, welche die Bedingung <cond> erfüllen, wird auch die Zeile aus <tab> nicht in die Selektion aufgenommen.

Die Bedingung <cond> wird syntaktisch wie eine Bedingung der WHERE-Klausel definiert, wobei einzelne Vergleiche nur mit AND verknüpft werden dürfen. Weiterhin muß jeder Vergleichsausdruck eine Spalte der rechten Tabelle <dbtab> enthalten, wobei es unerheblich ist, auf welcher Seite des Vergleichsoperators die Spalte steht. Als Spaltennamen können in den Vergleichen die gleichen Feldbezeichner wie in der SELECT-Klausel verwendet werden, um gleichnamige Spalten verschiedener Datenbanktabellen zu unterscheiden.

Die einzelnen Vergleiche der Bedingung <cond> könnten beim Inner Join statt in der ON-Bedingung auch in der WHERE-Klausel stehen, da beide gleichermaßen auf eine temporäre Tabelle aller Zeilen der Verknüpfung zugreifen. Es muß aber in jedem Join-Ausdruck syntaktisch mindestens ein Vergleich in der Bedingung <cond> stehen.

Mehrere Datenbanktabellen als Left Outer Join angeben

Beim Inner Join wird eine Zeile aus der linken Datenbanktabelle bzw. Join nur dann in die Selektion aufgenommen, falls es in der rechten Datenbanktabelle eine oder mehrere Zeilen gibt, welche die ON-Bedingung <cond> erfüllen. Der Left Outer Join liest Zeilen der linken Datenbanktabelle bzw. Join auch dann, wenn es keine passenden Zeilen in der rechten Tabelle gibt:

SELECT...
...
  FROM
<tab> LEFT [OUTER] JOIN <dbtab> [AS <alias>] ON <cond>
      
<options>
...

Für <tab> und <dbtab> gilt das gleiche wie beim Inner Join. Der Zusatz OUTER ist optional. Die Verknüpfung erfolgt ebenso wie beim Inner Join, mit dem Unterschied, daß alle selektierten Zeilen aus <tab> in die Selektion aufgenommen werden. In den Fällen, in denen <dbtab> keine Zeilen enthält, welche die Bedingung <cond> erfüllen, wird genau eine Zeile in die Selektion übernommen, deren Spalten aus der Tabelle <dbtab> mit Null-Werten gefüllt sind.

Beim Left Outer Join ist die Bedingung <cond> noch weiter eingeschränkt als beim Inner Join. Zusätzlich zu obigen Einschränkungen

Mandantenbehandlung

Wie Anfangs schon erwähnt, kann die automatische Mandantenbehandlung der Open SQL-Anweisungen durch einen Zusatz direkt hinter der Angabe der Datenbanktabellen ausgeschaltet werden. In der SELECT-Anweisung gehört der Zusatz demnach zu den Optionen <options> der FROM-Klausel:

SELECT... FROM <tables> CLIENT SPECIFIED. ..

Mit diesem Zusatz ist die Angabe von Mandatenfeldern in den einzelnen Klauseln erlaubt.

Datenpufferung ausschalten

Falls eine Tabelle im ABAP Dictionary für die Pufferung vorgesehen ist, liest die SELECT-Anweisung ihre Daten immer aus dem Puffe der Datenbankschnittstelle auf dem Applikationsserver. Um die Daten direkt von der Datenbanktabelleaus dem Puffer zu lesen, schreibt man für <options>:

SELECT... FROM <tables> BYPASSING BUFFER. ..

Dieser Zusatz garantiert, daß die gelesenen Daten den aktuellsten Stand haben. Normalerweise sollten aber nur wenig veränderliche Datenbanktabellen gepuffert sein und die standardmäßige Verwendung des Puffers sorgt für Performancegewinne. Deshalb sollte die Option nur eingesetzt werden, falls sie auch wirklich erforderlich ist.

Zeilenanzahl begrenzen

Um die absolute Anzahl von Zeilen in der Selektion zu begrenzen, schreibt man für <options>:

SELECT... FROM <tables> UP TO <n> ROWS. ..

Ist <n> eine positive ganze Zahl, werden maximal soviele Zeilen gelesen. Ist <n> gleich Null, werden alle selektierten Zeilen gelesen. In Kombination mit der ORDER BY-Klausel werden alle selektierten Zeilen gelesen, sortiert und dann die ersten <n> Zeilen in die Selektion gestellt.

Beispiele

Statische Angabe einer Datenbanktabelle.

REPORT demo_select_static_database.

DATA wa TYPE scarr.

SELECT *
  INTO wa
  FROM scarr UP TO 4 ROWS.

  WRITE: / wa-carrid, wa-carrname.

ENDSELECT.

Die Listenausgabe ist:

Es werden vier Zeilen aus der Datenbanktabelle SCARR gelesen.

Dynamische Angabe einer Datenbanktabelle.

REPORT demo_select_dynamic_database.

DATA wa TYPE scarr.

DATA name(10) TYPE c VALUE 'SCARR'.

SELECT  *
  INTO  wa
  FROM  (name) CLIENT SPECIFIED
  WHERE mandt = '000'.

  WRITE: / wa-carrid, wa-carrname.

ENDSELECT.

Da die Option CLIENT SPECIFIED verwendet wird, ist die Bedingung für die Spalte MANDT sinnvoll. Falls der Inhalt von NAME 'scarr' statt 'SCARR' wäre, käme es zum Laufzeitfehler, da die Tabelle 'scarr' nicht vorhanden ist.

Inner Join.

REPORT demo_select_inner_join.

DATA: BEGIN OF wa,
        carrid TYPE spfli-carrid,
        connid TYPE spfli-connid,
        fldate TYPE sflight-fldate,
        bookid TYPE sbook-bookid,
      END OF wa,
      itab LIKE SORTED TABLE OF wa
                WITH UNIQUE KEY carrid connid fldate bookid.

SELECT  p~carrid p~connid f~fldate b~bookid
  INTO  CORRESPONDING FIELDS OF TABLE itab
  FROM  ( ( spfli AS p
            INNER JOIN sflight AS f ON p~carrid = f~carrid AND
                                       p~connid = f~connid    )
            INNER JOIN sbook   AS b ON b~carrid = f~carrid AND
                                       b~connid = f~connid AND
                                       b~fldate = f~fldate     )
  WHERE p~cityfrom = 'FRANKFURT' AND
        p~cityto   = 'NEW YORK'  AND
        f~seatsmax > f~seatsocc.

LOOP AT itab INTO wa.
  AT NEW fldate.
    WRITE: / wa-carrid, wa-connid, wa-fldate.
  ENDAT.
  WRITE / wa-bookid.
ENDLOOP.

Es werden die Spalten CARRID, CONNID, FLDATE und BOOKID der Tabellen SPFLI, SFLIGHT und SBOOK miteinander verknüpft und eine Liste der Buchungsnummern für sämtliche nicht ausgebuchten Flüge von Frankfurt nach New York erstellt. Für jede Tabelle werden Alternativnamen verwendet.

Left Outer Join.

REPORT demo_select_left_outer_join.

DATA: BEGIN OF wa,
        carrid   TYPE scarr-carrid,
        carrname TYPE scarr-carrname,
        connid   TYPE spfli-connid,
      END OF wa,
      itab LIKE SORTED TABLE OF wa
                WITH NON-UNIQUE KEY carrid.

SELECT s~carrid s~carrname p~connid
  INTO CORRESPONDING FIELDS OF TABLE itab
  FROM scarr AS s
       LEFT OUTER JOIN spfli AS p ON s~carrid   =  p~carrid AND
                                     p~cityfrom = 'FRANKFURT'.

LOOP AT itab INTO wa.
  WRITE: / wa-carrid, wa-carrname, wa-connid.
ENDLOOP.

Die Listenausgabe könnte z.B. so aussehen:

Es werden die Spalten CARRID, CARRNAME und CONNID der Tabellen SCARR und SPFLI unter der Bedingung mit einem Left Outer Join miteinander verknüpft, daß die Fluggesellschaft von Frankfurt aus fliegt. Alle übrigen Fluggesellschaften haben den Wert Null in der Spalte CONNID der Selektion..

Falls der Left Outer Join durch einen Inner Join ersetzt wird, sieht die Liste so aus:

Nur solche Zeilen, welche die ON-Bedingung erfüllen, werden in die Selektion aufgenommen.