Eine Subquery ist eine spezielle SELECT-Anweisung, die innerhalb bestimmter Bedingungen der WHERE- oder HAVING-Klauseln für eine Unterabfrage verwendet werden kann. Subqueries können aber nicht in der ON-Bedingung der FROM-Klausel verwendet werden. Die Syntax für eine Subquery ist:
(
SELECT result
FROM source
[WHERE condition]
[GROUP BY fields]
[HAVING
cond] )
Es steht also eine etwas eingeschränkte Funktionalität der vollständigen SELECT-Anweisung zu Verfügung, da es keine INTO- oder ORDER-BY-Klauseln gibt.
Subqueries sind schachtelbar, d.h. in den WHERE- und HAVING-Klauseln einer Subquery kann wieder eine Subquery verwendet werden. Wenn eine geschachtelte Subquery in ihrer WHERE-Klausel dabei Felder der darüberliegenden Abfrage verwendet, spricht man von einer korrelierten Subquery. Dann wird die Subquery einzeln für jede Zeile der Datenbanktabelle ausgewertet, welche die darüberliegende Abfrage erfüllt.
Bei einer skalaren Subquery ist die Selektion der SELECT-Klausel auf eine Spalte oder einen Aggregatausdruck beschränkt. Der Ausdruck result der SELECT-Klausel ist also
... line [agg] s
Bei der Spaltenangabe der SELECT-Klausel ist nur ein einziger Feldbezeichner möglich.
Eine nicht skalare Subquery kann nur in der Bedingung
... [NOT] EXISTS subquery...
einer WHERE- oder HAVING-Klausel verwendet werden. Die Bedingung ist wahr, wenn die Selektion der Subquery mindestens eine [keine] Zeile enthält.
Neben der Verwendung in obiger Bedingung kann eine skalare Subquery in weiteren Bedingungen verwendet werden.
Eine mögliche Bedingung mit skalaren Subqueries ist:
... s [NOT] IN subquery...
Diese Bedingung ist wahr, falls der Wert von s [nicht] in der Ergebnismenge der skalaren Subquery subquery enthalten ist.
Die anderen Bedingungen können alle Vergleiche sein, deren Operatoren in der Tabelle für Vergleiche mit allen Typen in der WHERE-Klausel stehen. Dabei ist zu unterscheiden, ob die Selektion der Subquery eine oder mehrere Zeilen enthält.
Enthält die Selektion der Subquery nur eine Zeile, schreibt man für den Vergleich:
... s operator subquery...
Es wird der Wert von s mit dem Wert in der Selektion der Subquery verglichen und die Bedingung ist entsprechend wahr oder falsch.
Die Subquery muss einzeilig sein, ansonsten kommt es zu einem Laufzeitfehler. Eine einzeilige Subquery kann durch die vollständige Angabe des Schlüssels in der WHERE-Klausel erzeugt werden.
Enthält die Selektion der Subquery mehrere Zeilen, muss man den Vergleich wie folgt schreiben:
... s operator ALL|ANY|SOME subquery...
Mit dem Vorsatz ALL vor der Subquery ist die Bedingung nur wahr, falls der Vergleich für alle Zeilen der Subquery wahr ist. Mit dem Zusatz ANY oder SOME vor der Subquery ist die Bedingung wahr, falls der Vergleich für mindestens eine der Zeilen der Subquery wahr ist. Der Gleichheitsoperator (= oder EQ) in Verbindung mit ANY oder SOME wirkt also wie obiger Operator INzu Überprüfung eines Werts.
Falls die Selektion einer Subquery mehrere Zeilen enthält und es ist keiner der Ausdrücke ALL, ANY oder SOME aufgeführt, kommt es zu einem Laufzeitfehler.
Korrelierte nicht skalare Subquery.
REPORT demo_select_subquery_1.
DATA: name_tab TYPE TABLE OF scarr-carrname,
name LIKE LINE OF
name_tab.
SELECT carrname
INTO TABLE name_tab
FROM scarr
WHERE EXISTS ( select *
FROM spfli
WHERE carrid = scarr~carrid AND
cityfrom = 'NEW YORK' ).
LOOP AT name_tab INTO name.
WRITE: /
name.
ENDLOOP.
Es werden alle Zeilen der Datenbanktabelle SCARR selektiert, deren Fluggesellschaften von NEW YORK aus fliegen.
Skalare Subquery.
REPORT demo_select_subquery_2.
DATA: carr_id TYPE spfli-carrid VALUE 'LH',
conn_id TYPE spfli-connid VALUE
'0400'.
DATA: city TYPE sgeocity-city,
lati TYPE p DECIMALS 2,
longi TYPE p DECIMALS 2.
SELECT SINGLE city latitude longitude
INTO (city, lati, longi)
FROM sgeocity
WHERE city IN ( select cityfrom
FROM spfli
WHERE
carrid = carr_id AND
connid
= conn_id ).
WRITE: city, lati, longi.
Es werden die geographische Breite und Länge der Abflugstadt des Flugs LH 402 aus der Datenbanktabelle SGEOCITY selektiert.
Skalare Subquery.
REPORT demo_select_subquery_3.
DATA: wa TYPE sflight,
plane LIKE wa-planetype,
seats LIKE wa-seatsmax.
SELECT carrid connid planetype seatsmax MAX( seatsocc
)
INTO (wa-carrid, wa-connid,
wa-planetype,
wa-seatsmax,
wa-seatsocc)
FROM sflight
GROUP BY carrid connid planetype seatsmax
ORDER BY carrid connid.
WRITE: / wa-carrid,
wa-connid,
wa-planetype,
wa-seatsmax,
wa-seatsocc.
HIDE: wa-carrid, wa-connid, wa-seatsmax.
ENDSELECT.
AT LINE-SELECTION.
WINDOW STARTING AT 45 3 ENDING AT 85 13.
WRITE: 'Alternative Plane Types',
'for', wa-carrid,
wa-connid.
ULINE.
SELECT planetype seatsmax
INTO (plane, seats)
FROM saplane AS plane
WHERE seatsmax < wa-seatsmax AND
seatsmax >= ALL
( select seatsocc
FROM sflight
WHERE
carrid = wa-carrid AND
connid
= wa-connid )
ORDER BY seatsmax.
WRITE: / plane, seats.
ENDSELECT.
Die Listenausgabe ist nach einem Doppelklick auf eine Zeile:
Auf der Verzeigungsliste werden alle Flugzeugtypen angezeigt, die für eine Verbindung beim derzeitigen Buchungsstand für alle Flüge genügend aber weniger Sitzplätze haben als der aktuelle Flugzeugtyp.