7.1 Grundform der SELECT-Anweisung
7.2.2 Die Operatoren IN und BETWEEN
7.3.1 Unterabfrage und
Vergleichsoperatoren
7.3.2 Unterabfragen und IN-Operator
7.3.3 Die Operatoren ANY und ALL
7.5.1 Die Funktionen MIN und MAX
In den nächsten beiden Kapiteln
werden wir die wichtigste
SQL-Anweisung, nämlich
SELECT vorstellen. Dieses
Kapitel
dient der Einführung der
SELECT-Anweisung und der Erläuterung
einfacher Abfragen. Jede Klausel
der SELECT-Anweisung
wird
separat erklärt und mit Hilfe
der Beispieldatenbank
dargestellt. In dem
zweiten Teil des Kapitels werden
die
Aggregatfunktionen und der Operator
UNION beschrieben.
Mit
der SELECT-Anweisung werden
Datenwerte aus einer
Datenbank ausgewählt. Sie können aus
einer oder aus mehreren,
miteinander verbundenen
Tabellen ausgewählt werden.
Das
Ergebnis einer solchen Auswahl ist
erneut eine Tabelle, die
keine, eine oder mehrere Reihen und
eine oder mehrere Spalten
hat.
Die SELECT-Anweisung hat folgende
allgemeine Form:
SELECT [ALL|DISTINCT] *|{ausdr_1 AS alias_name1 },...
FROM tab1 [tab_alias1]
[,tab_2 [tab_alias2],...]
[WHERE bedingung_1]
[GROUP BY ausdr_3,...]
[HAVING bedingung_2]
[ORDER BY ausdr_5
[ASC|DESC],...];
Die
einzelnen Klauseln werden wir im
Verlauf dieses Kapitels
vorstellen und anhand von Beispielen
praktisch erläutern.
Wie
aus der allgemeinen Form ersichtlich, beinhaltet
die
einfachste
SELECT-Anweisung, neben SELECT,
noch die
FROM-Klausel:
SELECT [ALL|DISTINCT]
*|{ausdr_1 AS alias_name1} ,...
FROM tab1 [tab_alias1]
[,tab_2 [tab_alias2],...];
tab_1 kennzeichnet
den Namen der Tabelle,
aus der Daten
ausgewählt werden. tab_alias1 stellt
den Aliasnamen der
Tabelle tab1 dar. In
einer SELECT-Anweisung können
mehrere
Tabellen angegeben werden. In
diesem Kapitel wird
nur
die Auswahl der Daten aus
einer Tabelle behandelt.
Die
Verknüpfung mehrerer Tabellen in einer SELECT-Anweisung wird
Thema von Kapitel 8 sein.
Falls die SELECT-Anweisung nur
den Namen einer
Tabelle
beinhaltet, werden mit ihr
alle Reihen und
eine oder
mehrere Spalten dieser Tabelle
ausgewählt. Das Zeichen
"*" kennzeichnet alle Spalten aller in
der FROM-Klausel
angegebenen Tabellen, während die
explizite Auswahl einzelner
Spaltennamen durch die
Angabe ausdr_1, ...
erfolgt. Die
Auswahl der Spalten in einer
SELECT-Anweisung wird Projektion
und die Auswahl der Reihen Selektion
genannt.
Die Angabe AS alias_name1
kann jedem Ausdruck, der
Bezug
zu
einer einzelnen Tabellenspalte
hat, zugewiesen werden.
In diesem Fall wird alias_name1
als Spaltenüberschrift des
Auswahlergebnisses verwendet.
Beispiel 7.1
Wählen Sie alle Reihen der Tabelle abteilung
aus.
SELECT * FROM abteilung;
Das Ergebnis ist:
abt_nr |
abt_name |
stadt |
a1 |
Beratung
|
Muenchen |
a2
|
Diagnose |
Muenchen |
a3 |
Freigabe
|
Stuttgart |
(3 rows)
Mit
dieser Anweisung werden alle Reihen und alle Spalten der
Tabelle abteilung ausgewählt.
Hinweis.
SELECT * liefert die Spalten einer
Tabelle in der Reihenfolge
wie sie in der CREATE TABLE-Anweisung
definiert wurden. Die
Spaltennamen bilden die _berschrift.
Beispiel 7.2
SELECT
abt_nr, abt_name, stadt
FROM abteilung;
Das Ergebnis ist:
abt_nr |
abt_name |
stadt |
a1 |
Beratung
|
Muenchen |
a2
|
Diagnose |
Muenchen |
a3 |
Freigabe
|
Stuttgart |
(3 rows)
Das
Beispiel 7.2 liefert
dasselbe Ergebnis wie
die
SELECT-Anweisung in Beispiel 7.1.
Die einfachste Form
der SELECT-Anweisung wird in der Praxis
nicht so oft benutzt, wie die Form, in der eine oder mehrere
Bedingungen existieren. Die
Bedingungen werden mit
Hilfe
der WHERE-Klausel definiert, die die auszuwählenden Reihen
bestimmt.
Beispiel 7.3
Finden Sie die Namen und Nummern aller Abteilungen, die in
München ihren Sitz haben.
SELECT abt_name, abt_nr
FROM
abteilung
WHERE stadt = 'Muenchen';
Das Ergebnis ist:
abt_name |
abt_nr |
Beratung
|
a1 |
Diagnose |
a2
|
(2 rows)
Die Bedingung in einer
WHERE-Klausel muß nicht
unbedingt
auf
Gleichheit geprüft werden.
SQL kennt folgende
Vergleichsoperatoren:
Operator |
Funktion |
= |
gleich |
<>
oder != oder ^= |
nicht
gleich |
> |
groesser
als |
< |
kleiner
als |
>= |
groesser
gleich |
kleiner
gleich |
Beispiel 7.4
Nennen Sie die Namen und Vornamen aller Mitarbeiter, deren
Personalnummer größer oder gleich
15000 ist.
SELECT m_name, m_vorname
FROM mitarbeiter
WHERE m_nr >= 15000;
Das
Ergebnis ist:
m_name |
m_name |
Keller |
Hans |
Mueller |
Gabriele |
Probst |
Andreas |
Mozer |
Sibille |
(4 rows)
In der WHERE-Klausel können auch
Ausdrücke erscheinen.
Beispiel 7.5
Finden Sie alle Projekte, deren Finanzmittel mehr als 60000$
betragen. Der augenblickliche Kurs
soll bei 0,55 Dollar für 1
DM liegen.
SELECT pr_name
FROM projekt
WHERE mittel * 0.55 > 60000;
Das Ergebnis ist:
pr_name |
Apollo |
Merkur |
(2 rows)
Beim
Vergleich von CHAR- bzw.
VARCHAR-Ausdrücken werden die
einzelnen Zeichen auf Grund
der ASCII-Tabelle verglichen.
Ein Zeichen ist kleiner als ein anderes, falls es in der
ASCII-Tabelle vor diesem
Zeichen steht.
Gleichermaßen ist
ein Zeichen größer als ein
anderes, falls es hinter diesem
Zeichen in der ASCII-Tabelle steht.
Die numerischen Werte
werden in der üblichen mathematischen Weise verglichen. Beim
Vergleich von Ausdrücken vom Typ DATE ist ein Datum kleiner
als ein anderes, wenn es älter als
dieses ist.
Kommen in einer Spalte NULL-Werte
vor und beinhaltet die
WHERE-Klausel eine Bedingung mit dieser Spalte, werden alle
NULL-Werte beim Vergleich außer acht
gelassen. (Im weiteren
Verlauf dieses Kapitels werden
wir zeigen, wie man explizit
die NULL-Werte auswählen kann.)
Boolesche Funktionen sind:
Konjunktion ("logisches UND"),
Disjunktion ("logisches
ODER") und Negation. Diese Funktionen
werden durch die Symbole
AND, OR und NOT dargestellt. Das
Verhalten der Operatoren AND, OR und NOT haben wir schon
mit
Hilfe der Wahrheitstabellen in
Kapitel 2 gezeigt.
Beispiel 7.6
Gesucht werden Personalnummer, Projektnummer und Aufgabe der
Mitarbeiter, die im Projekt p2
Sachbearbeiter sind.
SELECT m_nr, pr_nr, aufgabe
FROM arbeiten
WHERE pr_nr = 'p2'
AND aufgabe = 'Sachbearbeiter';
Das Ergebnis ist:
m_nr |
pr_nr |
aufgabe |
25348 |
p2
|
Sachbearbeiter |
28559 |
p2
|
Sachbearbeiter |
(2 rows)
Beim AND-Operator werden nur die
Reihen ausgewählt, bei denen
die beiden Bedingungen, die AND
verbindet, erfüllt sind.
Beispiel 7.7
Gesucht wird die Personalnummer der
Mitarbeiter, die entweder
im Projekt p1 oder p2
oder in beiden arbeiten.
SELECT m_nr
FROM arbeiten
WHERE pr_nr =
'p1'
OR pr_nr =
'p2';
Das Ergebnis lautet:
m_nr |
10102 |
25348 |
18316 |
29346 |
9031 |
28559 |
28559 |
29346 |
(8 rows)
Im Ergebnis des Beispiels 7.7 sind
einige Datenwerte der
Spalte m_nr mehrfach vorhanden. Falls jeder Datenwert
dieser
Spalte nur einmal im Ergebnis vorkommen
sollte, muß die
DISTINCT-Angabe benutzt werden:
SELECT DISTINCT m_nr
FROM arbeiten
WHERE pr_nr =
'p1'
OR pr_nr = 'p2';
Das Ergebnis lautet dann:
m_nr |
9031 |
10102 |
18316 |
25348 |
28559 |
29346 |
(6 rows)
Im Gegensatz
zu AND werden bei dem Operator
OR alle Reihen
ausgewählt, bei denen wenigstens eine
der Bedingungen erfüllt
ist.
Die
WHERE-Klausel kann mehrere gleiche oder unterschiedliche
Boolesche Operatoren beinhalten. Dabei ist zu beachten, daß
AND eine größere Priorität als OR
hat. Die Nichtbeachtung
dieser Regel kann zu
falschen Ergebnissen führen, wie wir am
nächsten Beispiel sehen werden.
Beispiel 7.8
SELECT *
FROM mitarbeiter
WHERE m_nr = 25348 AND m_name = 'Keller'
OR m_vorname = 'Hans'
AND abt_nr = 'a1';
SELECT *
FROM mitarbeiter
WHERE ((m_nr = 25348
AND m_name = 'Keller')
OR m_vorname = 'Hans')
AND abt_nr = 'a1';
Das
Ergebnis ist:
m_nr |
m_name |
m_vorname |
abt_nr |
25348 |
Keller |
Hans |
a3 |
(1 row)
m_nr |
m_name |
m_vorname |
abt_nr |
|
|
|
|
(0 rows)
Wie aus dem Ergebnis ersichtlich,
haben die
SELECT-Anweisungen in
Beispiel 7.8 unterschiedliche
Ergebnisse. In der ersten
SELECT-Anweisung werden zunächst
die
beiden Operationen mit AND ausgewertet (zuerst die linke
und dann die rechte); die
Operation mit OR wird erst danach
durchgeführt. In der zweiten SELECT-Anweisung werden, unter
Benutzung von Klammern, die
Operationen von links nach rechts
abgearbeitet.
Bei
Verwendung mehrerer Boolescher
Operatoren innerhalb
einer WHERE-Klausel, ist diese
in den meisten Fällen
schwer verständlich. In solchen
Fällen empfiehlt sich daher
grundsätzlich die Benutzung von Klammern, auch in
Fällen
wo
sie nicht unbedingt
notwendig sind. Dadurch wird
eine
SELECT-Anweisung lesbarer.
Die erste SELECT-Anweisung in
Beispiel 7.8 hat durch
die Benutzung von Klammern
folgende
Form:
SELECT *
FROM mitarbeiter
WHERE (m_nr = 25348 AND
m_name = 'Keller')
OR (m_vorname = 'Hans'
AND abt_nr = 'a1');
Der
dritte Boolesche Operator, NOT, ändert den logischen Wert
einer Bedingung. Wie man
aus der Wahrheitstabelle
für NOT
in
Kapitel 2 sehen kann, ist die
Negation eines richtigen
logischen Wertes falsch, eines
falschen richtig und eines
unbekannten Wertes wieder unbekannt.
Die Negation hat von
allen drei Booleschen Operatoren die höchste Priorität. Wenn
in
einem logischen Ausdruck alle drei Operatoren existieren,
wird
also zuerst die Negation, danach das logische UND und
erst am Ende das logische ODER
abgearbeitet.
Beispiel 7.9
Nennen Sie Personalnummer und Nachnamen der Mitarbeiter, die
nicht in der Abteilung a2 arbeiten.
SELECT m_nr, m_name
FROM mitarbeiter
WHERE NOT abt_nr =
'a2';
Das
Ergebnis ist:
m_nr |
m_name |
25348 |
Keller |
10102 |
Huber |
18316 |
Mueller |
28559 |
Mozer |
(4 rows)
Der
Boolesche Operator NOT kann durch den Vergleichsoperator
"<>" (ungleich)
ersetzt werden. Beispiel
7.10 ist mit
Beispiel 7.9 identisch.
Beispiel 7.10
SELECT m_nr, m_name
FROM mitarbeiter
WHERE
abt_nr <> 'a2';
Mit
dem IN-Operator können
mehrere Konstanten angegeben
werden, auf die dann die Suche beschränkt wird. Es werden
lediglich die Reihen ausgewählt, bei denen der Datenwert
der
Spalte in der WHERE-Klausel einer der angegebenen Konstanten
entspricht.
Beispiel 7.11
Finden Sie alle Mitarbeiter,
deren Personalnummer entweder
29346, 28559 oder 25348 ist.
SELECT *
FROM mitarbeiter
WHERE m_nr IN (29346, 28559, 25348);
Das Ergebnis ist:
m_nr |
m_name |
m_vorname |
abt_nr |
25348 |
Keller |
Hans |
a3 |
29346 |
Probst |
Andreas |
a2 |
28559 |
Mozer |
Sibille |
a1 |
(3 rows)
Der IN-Operator kann
durch eine Reihe
von OR-Operatoren
ersetzt werden. Beispiel 7.12
ist mit Beispiel
7.11
identisch.
Beispiel 7.12
SELECT *
FROM mitarbeiter
WHERE m_nr = 29346
OR m_nr = 28559
OR m_nr = 25348;
Der IN-Operator
kann auch gemeinsam
mit dem Booleschen
Operator NOT verwendet werden.
In diesem Fall werden
nur
die Reihen ausgewählt, für die der
Datenwert der Spalte
in
der WHERE-Klausel keine von den angegebenen Konstanten
beinhaltet.
Beispiel 7.13
Nennen Sie alle Mitarbeiter, deren
Personalnummer weder 10102
noch 9031 ist.
SELECT *
FROM mitarbeiter
WHERE m_nr NOT IN
(10102, 9031);
Das
Ergebnis ist:
m_nr |
m_name |
m_vorname |
abt_nr |
25348 |
Keller |
Hans |
a3 |
18316 |
Mueller |
Gabriele |
a1 |
29346 |
Probst |
Andreas |
a2 |
2581 |
Kaufmann |
Brigitte |
a2
|
28559 |
Mozer |
Sibille |
a1 |
(5 rows)
Der IN-Operator kann auch für
Unterabfragen verwendet werden.
Diese Form des IN-Operators
werden wir später
in diesem
Kapitel erörtern.
Im
Unterschied zum IN-Operator, der einzelne Werte festlegt,
definiert der Operator BETWEEN immer
einen Bereich, in
dem
dann die Werte gesucht werden, die
die Bedingung erfüllen.
Beispiel 7.14
Nennen Sie Namen und Mittel aller
Projekte, deren finanzielle
Mittel zwischen 95.000 DM und 120.000
DM liegen.
SELECT pr_name, mittel
FROM projekt
WHERE mittel
BETWEEN 95000 AND 120000;
Das
Ergebnis ist:
pr_name |
mittel |
Apollo |
120000.000 |
Gemini |
95000.000 |
(2 rows)
Wie
aus Beispiel 7.14
ersichtlich ist, beinhaltet
der
Bereich auch die beiden Grenzwerte,
die beim BETWEEN-Operator
angegeben sind.
Der
BETWEEN-Operator kann auch durch
Vergleichsoperatoren
ersetzt werden. Beispiel 7.15
entspricht dem Beispiel 7.14.
Beispiel 7.15
SELECT pr_name, mittel
FROM projekt
WHERE mittel <= 120000
AND
mittel >= 95000;
Obwohl die beiden SELECT-Anweisungen in den Beispielen
7.14
und 7.15 identisch
sind, ist die
Form mit dem
BETWEEN-Operator
vorzuziehen. Die Anweisung
in 7.14 ist
transparenter und deswegen leichter
lesbar.
Der
BETWEEN-Operator kann, in
gleichem Maße wie
der
IN-Operator, mit
dem Booleschen Operator
NOT gemeinsam
verwendet werden. In diesem
Fall werden die
Reihen
ausgewählt, für die der
Datenwert der Spalte
in der
WHERE-Klausel außerhalb des
angegebenen Bereichs liegt.
Beispiel 7.16
Nennen Sie die Personalnummer aller Mitarbeiter, die
Projektleiter sind und vor oder nach
1988 eingestellt wurden.
SELECT m_nr
FROM arbeiten
WHERE aufgabe = 'Projektleiter'
AND einst_dat NOT BETWEEN '01-jan-1988' AND '31-dec-1988';
Das
Ergebnis ist:
m_nr |
2581 |
(1 row)
Wie schon in Kapitel 2 erwähnt,
werden NULL-Werte einer
Spalte außer acht gelassen,
falls in der
WHERE-Klausel
ausschließlich Vergleichsoperatoren verwendet worden
sind.
Damit auch Datenwerte, die
NULL-Werte beinhalten, in
einer SELECT-Anweisung
ausgewählt werden können,
wurde
der
NULL-Operator eingeführt.
Die allgemeine Form
dieses
Operators
ist:
spalte_1 IS [NOT] NULL
Beispiel
7.17
Finden Sie die Personal- und Projektnummer aller Mitarbeiter,
die im Projekt p1
arbeiten und deren Aufgabe
noch nicht
festgelegt ist.
SELECT m_nr, pr_nr
FROM arbeiten
WHERE pr_nr = 'p1'
AND aufgabe IS NULL;
Das Ergebnis ist:
m_nr |
pr_nr |
28559 |
p1 |
(1 row)
In
der Syntax des
NULL-Operators befindet sich
eine
potentielle Fehlerquelle beim
Programmieren mit SQL.
Der
Vergleich auf NULL bzw.
NOT NULL wird nicht, wie in allen
anderen Fällen mit dem
Vergleichsoperator "=" durchgeführt.
Das liegt an der Logik des NULL-Wertes. Dieser Wert
kann
nicht mit einem beliebigen Wert
verglichen werden, oder
ihm entsprechen. Deswegen
wurde bei der
Syntaxdefinition
absichtlich das Verb IS eingeführt.
Die Bedingung
spalte_1 IS NOT
NULL
ist mit der Bedingung
NOT (spalte_1 IS NULL)
identisch.
Hinweis.
Die Bedingung mit dem Vergleich auf
NULL bzw. NOT NULL kann
richtig oder falsch, aber auf keinen
Fall NULL sein!
Der LIKE-Operator ist ein Vergleichsoperator,
der Datenwerte
einer Spalte mit einem vorgegebenen Muster
vergleicht. Die
allgemeine Form des LIKE-Operators
ist
spalte_2 [NOT] LIKE 'muster'
wobei muster eine Zeichenkette darstellt, die das
Vergleichsmuster definiert.
Diese Zeichenkette enthält
alphanumerische Zeichen, wobei zwei
Zeichen eine besondere
Bedeutung haben. Dies sind:
% (Prozentzeichen) und
_ (Unterstrich)
Das Zeichen "%" kennzeichnet eine beliebige Zeichenfolge von
n Zeichen, wobei n eine
nichtnegative ganze Zahl ist, also
auch 0 sein kann. Das Zeichen
"_" kennzeichnet ein beliebiges
alphanumerisches Zeichen.
Jedes andere alphanumerische
Zeichen kennzeichnet sich selbst.
Beispiel 7.18
Finden Sie Namen und Personalnummer aller Mitarbeiter, deren
Name mit dem Buchstaben "K"
beginnt.
SELECT m_name, m_nr
FROM mitarbeiter
WHERE m_name
LIKE 'K%';
Das
Ergebnis ist:
m_name |
m_nr |
Keller |
25348 |
Kaufmann |
2581 |
(2 rows)
Beispiel 7.19
Nennen Sie Namen, Vornamen
und Personalnummer aller
Mitarbeiter, deren Vorname als
zweiten Buchstaben "a" hat.
SELECT
m_nr, m_name, m_vorname
FROM mitarbeiter
WHERE m_vorname LIKE '_a%';
Das
Ergebnis ist:
m_nr |
m_name |
m_vorname |
25348 |
Keller |
Hans |
18316 |
Mueller |
Gabriele |
9031 |
Meier |
Rainer |
(3 rows)
Der
Benutzer kann mit der Angabe ESCAPE selbst festlegen,
welches Zeichen als Entwertungszeichen verwendet wird. Die
Angabe
spalte_3 LIKE '%z_%' ESCAPE 'z'
sucht alle Datenwerte in der Spalte spalte_3,
die das Zeichen
"_" (Unterstrich) an
irgendeiner Stelle der
Zeichenkette
enthalten.
Die Bedingung
spalte_4 NOT LIKE 'muster'
ist identisch mit
NOT (spalte_4 LIKE 'muster')
Beispiel 7.20
Nennen Sie alle Mitarbeiter, deren
Name nicht mit "mann"
endet.
SELECT *
FROM mitarbeiter
WHERE m_name NOT LIKE '%mann';
Das
Ergebnis ist:
m_nr |
m_name |
m_vorname |
abt_nr |
25348 |
Keller |
Hans |
a3 |
10102 |
Huber |
Petra |
a3 |
18316 |
Mueller |
Gabriele |
a1 |
29346 |
Probst |
Andreas |
a2 |
9031 |
Meier |
Rainer |
a2
|
28559 |
Mozer |
Sibille |
a1 |
(6 rows)
Bis
jetzt wurde der Vergleich in der WHERE-Klausel immer mit
einer Konstanten bzw. einem Ausdruck
durchgeführt. Zusätzlich
dazu ist es möglich, den
Vergleich mit dem Ergebnis einer
weiteren SELECT-Anweisung durchzuführen. Eine solche
SELECTAnweisung,
die Teil der
Bedingung einer WHERE-Klausel
ist,
wird einfache Unterabfrage genannt. (Neben der
einfachen
Unterabfrage gibt es auch die
korrelierten Unterabfragen, die
in Kapitel 8 erklärt werden.)
Jede
Unterabfrage wird häufig
als innere SELECT-Anweisung
bezeichnet, dies im Unterschied zur
äußeren SELECT-Anweisung,
in
der die innere
eingeschlossen ist. In einer Abfrage
mit
einfacher Unterabfrage wird stets
zunächst die innere
SELECTAnweisung
ausgewertet und ihr Ergebnis dann an die äußere
SELECT-Anweisung weitergegeben.
Eine einfache Unterabfrage kann im Zusammenhang mit folgenden
Operatoren auftreten:
- allen
Vergleichsoperatoren;
- dem IN-Operator;
- dem ANY bzw.
ALL-Operator und
- dem EXISTS-Operator.
Beispiel 7.21
Nennen Sie die Abteilungsnummer des Mitarbeiters, der am
15.10.1989 eingestellt wurde.
SELECT abt_nr
FROM mitarbeiter
WHERE m_nr =
(SELECT m_nr
FROM arbeiten
WHERE einst_dat = '15-oct-1989');
Das Ergebnis ist:
abt_nr |
a2
|
(1 row)
Wie aus Beispiel 7.21 ersichtlich,
wird die Unterabfrage
immer in Klammern eingeschlossen.
Die Unterabfrage
kann auch mit
den anderen
Vergleichsoperatoren im Zusammenhang
stehen.
Beispiel 7.22
Nennen Sie die Nummern aller
Projekte, in welchen Mitarbeiter
arbeiten, deren Personalnummer
kleiner als die Nummer des
Mitarbeiters namens Mueller ist.
SELECT DISTINCT pr_nr
FROM arbeiten
WHERE m_nr <
(SELECT m_nr
FROM
mitarbeiter
WHERE m_name = 'Mueller');
Das Ergebnis ist:
pr_nr |
p1
|
p3
|
(2 rows)
Wie aus den beiden letzten
Beispielen ersichtlich, darf die
innere SELECT-Anweisung nur einen Wert als Ergebnis liefern,
falls sie im Zusammenhang mit einem Vergleichsoperator
erscheint. Dies ist auch
logisch, weil der Vergleich
mit
mehreren Ergebniswerten nicht
sinnvoll wäre.
Wie
schon im vorherigen
Abschnitt erklärt, liefert
der
IN-Operator als Ergebnis eine
Anzahl von Konstanten, die
dann
mit den Datenwerten einer Spalte verglichen werden. Die
Verwendung des IN-Operators mit der Unterabfrage verläuft
ähnlich. Die innere SELECT-Anweisung liefert einen oder
mehrere Ergebniswerte, mit denen
die Datenwerte einer Spalte
verglichen werden.
Beispiel 7.23
Nennen Sie die Daten aller
Mitarbeiter, die in
München
arbeiten.
SELECT *
FROM
mitarbeiter
WHERE abt_nr IN
(SELECT
abt_nr
FROM abteilung
WHERE stadt = 'Muenchen');
Das Ergebnis ist:
m_nr |
m_name |
m_vorname |
abt_nr |
18316 |
Mueller |
Gabriele |
a1 |
29346 |
Probst |
Andreas |
a2 |
9031 |
Meier |
Rainer |
a2
|
2581 |
Kaufmann |
Brigitte |
a2
|
28559 |
Mozer |
Sibille |
a1 |
(5 rows)
Jede Unterabfrage kann eine
weitere Unterabfrage enthalten.
In diesem Fall sprechen wir von
geschachtelten Unterabfragen.
Die
Anzahl der geschachtelten Unterabfragen ist von der
Implementierung und
von dem Speicherplatz abhängig, der
für eine Abfrage (mit allen
dazugehörigen Unterabfragen)
festgelegt ist. Bei allen
geschachtelten, einfachen
Unterabfragen wird zunächst die innerste SELECT-Anweisung
abgearbeitet und
dann das Ergebnis
der nächsthöheren
SELECT-Anweisung übergeben. So wird
weiter verfahren, bis die
äußere SELECT-Anweisung erreicht und
abgearbeitet wird.
Beispiel 7.24
Nennen Sie die Namen aller
Mitarbeiter, die im Projekt Apollo
arbeiten.
SELECT m_name
FROM mitarbeiter
WHERE m_nr IN
( SELECT m_nr
FROM arbeiten
WHERE pr_nr =
( SELECT pr_nr
FROM projekt
WHERE pr_name =
'Apollo'))
Das
Ergebnis ist:
m_name |
Huber |
Probst |
Meier |
Mozer |
(4 rows)
Die innerste SELECT-Anweisung wählt den Datenwert der
Spalte
pr_nr (p1) der Tabelle
projekt aus, dessen Projektname Apollo
lautet. Die mittlere SELECT-Anweisung
vergleicht anschliessend
diesen Wert mit den
Datenwerten der gleichnamigen Spalte
in
der Tabelle arbeiten. Das Ergebnis der
mittleren
SELECT-Anweisung beinhaltet mehrere Werte, die mit Hilfe des
IN-Operators mit den
Datenwerten der Spalte m_nr
in der
Tabelle mitarbeiter verglichen
werden.
Die
Operatoren ANY und ALL werden
immer im Zusammenhang mit
einem Vergleichsoperator benutzt. Die allgemeine Form beider
Operatoren ist:
ausdruck vergl_op [ANY | ALL] (unterabfrage) ,
wobei vergl_op einen der
Vergleichsoperatoren darstellt.
Beim
ANY-Operator wird die Bedingung als wahr ausgewertet,
falls die Unterabfrage
wenigstens eine Reihe als Ergebnis
liefert, die dem angegebenen
Vergleich entspricht.
Beispiel 7.25
Finden Sie Personalnummer,
Projektnummer und Aufgabe
der
Mitarbeiter, deren
Eintrittsdatum in das
entsprechende
Projekt nicht das älteste ist.
SELECT m_nr, pr_nr, aufgabe
FROM arbeiten
WHERE einst_dat > ANY
(SELECT einst_dat
FROM arbeiten);
Das Ergebnis ist:
m_nr |
pr_nr |
aufgabe |
10102 |
p1
|
Projektleiter |
10102 |
p3
|
Gruppenleiter |
25348 |
p2
|
Sachbearbeiter |
18316 |
p2 |
|
2581 |
p3
|
Projektleiter |
9031 |
p1
|
Gruppenleiter |
28559 |
p1 |
|
28559 |
p2
|
Sachbearbeiter |
9031 |
p3
|
Sachbearbeiter |
29346 |
p1
|
Sachbearbeiter |
(10 rows)
In Beispiel 7.25 wird jeder
Datenwert der Spalte einst_dat
mit allen Datenwerten derselben
Spalte (auch mit sich selbst)
verglichen. Für alle Datenwerte, abgesehen von einem, gilt,
daß beim Vergleich die Bedingung
wenigstens in einem Fall
erfüllt ist. Die Reihe mit dem
ältesten Eintrittsdatum wird
nicht ausgewählt, weil für
sie der Vergleich nicht erfüllt
ist.
Beispiel 7.26
Nennen Sie die Namen und
Vornamen aller Mitarbeiter, die im
Projekt p1 arbeiten.
SELECT m_name, m_vorname
FROM mitarbeiter
WHERE m_nr = ANY
(SELECT m_nr
FROM arbeiten
WHERE pr_nr =
'p1');
Das
Ergebnis ist:
m_name |
m_vorname |
Huber |
Petra |
Probst |
Andreas |
Meier |
Rainer |
Mozer |
Sibille |
(4 rows)
Beim
ALL-Operator wird die
Bedingung als wahr ausgewertet,
wenn alle Ergebnisse der
Unterabfrage dem angegebenen
Vergleich entsprechen.
Beispiel 7.27
Nennen Sie die Aufgabe
des Mitarbeiters, der die kleinste
Personalnummer hat.
SELECT aufgabe
FROM arbeiten
WHERE m_nr <=
ALL
(SELECT m_nr
FROM
mitarbeiter);
Das Ergebnis ist:
aufgabe |
Projektleiter |
(1 row)
Neben den Operatoren ANY und ALL existiert noch ein Operator
- SOME. Dieser Operator ist
gleichbedeutend mit ANY.
Die Operatoren
ALL und ANY haben einige
Nachteile, die
gegen ihre Verwendung bei Unterabfragen sprechen. Der größte
Nachteil ist, daß die
korrekte semantische Bedeutung beider
Operatoren verwechselt werden kann. Auf der anderen Seite
können die beiden Operatoren leicht
durch den EXISTS-Operator
ersetzt werden, wie wir im nächsten Kapitel zeigen
werden.
Deswegen empfehlen wir, die Verwendung beider Operatoren auf
ein Minimum zu reduzieren.
Der EXISTS-Operator prüft das
Ergebnis einer Unterabfrage;
falls die Unterabfrage
zumindest eine Reihe als
Ergebnis
liefert, wird die Bedingung als
wahr ausgewertet. Falls die
Unterabfrage keine Reihe
als Ergebnis liefert,
wird die
Bedingung in der WHERE-Klausel als
falsch ausgewertet.
Die allgemeine Form des
EXISTS-Operators ist:
[NOT] EXISTS (unterabfrage)
Die
Beispiele zum EXISTS-Operator finden Sie in Kapitel 8.
Die
GROUP BY-Klausel definiert eine oder mehrere Spalten als
Gruppenkennzeichen, wonach die Reihen
gruppiert werden.
Beispiel 7.28
Welche Aufgaben üben die Mitarbeiter
der Firma aus?
SELECT aufgabe
FROM arbeiten
GROUP BY aufgabe;
Das
Ergebnis ist:
aufgabe |
Projektleiter |
Gruppenleiter |
Sachbearbeiter |
(4 rows)
Wie wir aus Beispiel 7.28 ersehen
können, baut die GROUP
BY-Klausel für jeden unterschiedlichen Datenwert (auch für
den
NULL-Wert) der genannten
Spalte eine Gruppe auf. Falls
die GROUP BY-Klausel
angegeben ist, muß jede Spalte in der
Projektion auch in der
GROUP BY-Klausel
erscheinen. Zudem
darf
die Projektion nur
alphanumerische Konstanten und
Aggregatfunktionen anderer Spalten enthalten, die in
der
GROUP BY-Klausel nicht erscheinen
müssen.
In der GROUP BY-Klausel können auch
mehrere Spalten angegeben
werden. In diesem Fall wird die
Gruppierung auf Grund aller
angegebenen Spalten durchgeführt.
Beispiel 7.29
Gruppieren Sie die Mitarbeiter nach Projektnummer und
Aufgabe.
SELECT pr_nr, aufgabe
FROM arbeiten
GROUP BY pr_nr, aufgabe;
Das Ergebnis ist:
pr_nr |
aufgabe |
p1
|
Gruppenleiter |
p1
|
Projektleiter |
p1
|
Sachbearbeiter |
p1 |
|
p2
|
Sachbearbeiter |
p2 |
|
p3
|
Gruppenleiter |
p3
|
Projektleiter |
p3
|
Sachbearbeiter |
(9 rows)
Wie
aus dem Ergebnis
ersichtlich, gibt es
insgesamt 9
Gruppen, in denen Projektnummer und
Aufgabe unterschiedlich
sind. Die beiden Gruppen, die mehr
als eine Reihe beinhalten,
sind
p2 Sachberabeiter
25348, 28559
p2 NULL
18316, 29346
Die
Reihenfolge der Spalten in der
GROUP BY-Klausel muss
nicht unbedingt der Reihenfolge der
Spalten in der Projektion
entsprechen.
Zu den Aggregatfunktionen gehören
folgende Funktionen:
- MIN;
- MAX;
- SUM;
- AVG und
- COUNT.
Alle
Aggregatfunktionen werden stets auf
eine Gruppe von
Reihen angewendet, wobei die
Gruppe auch alle
Reihen
einer Tabelle umfassen kann.
Als Ergebnis liefert
jede
Aggregatfunktion einen
konstanten Wert, der
in einer
separaten Spalte im Ergebnis
erscheint.
Die
Aggregatfunktionen können in
einer SELECT-Anweisung
mit
oder ohne GROUP
BY-Klausel erscheinen. Falls
die
SELECT-Anweisung die GROUP
BY-Klausel nicht enthält, dürfen
in der Projektion nur die Spaltennamen angegeben werden, die
als
Parameter der Aggregatfunktion
erscheinen. Deswegen ist
das folgende Beispiel falsch:
Beispiel 7.30
SELECT m_name, MIN(m_nr)
FROM mitarbeiter;
Alle
Spaltennamen, die nicht
Parameter der Aggregatfunktion
sind, dürfen in der SELECT-Anweisung erscheinen, falls sie
zur Gruppierung verwendet werden.
Für alle Aggregatfunktionen kann
zwischen den Angaben
- ALL und
- DISTINCT
gewählt werden. ALL kennzeichnet alle Werte einer Spalte und
stellt die Voreinstellung dar. Sie gilt also,
wenn weder
ALL
noch DISTINCT angegeben sind. DISTINCT kennzeichnet alle
unterschiedlichen Werte einer Spalte.
Die Aggregatfunktionen MIN und
MAX berechnen den kleinsten
bzw. den größten Datenwert einer
Spalte.
Beispiel 7.31
Nennen Sie die kleinste
Personalnummer eines Mitarbeiters.
SELECT MIN (m_nr)
FROM
mitarbeiter;
Das Ergebnis ist:
col1 |
2581 |
(1 row)
Das Ergebnis dieses Beispiels ist nicht sehr
aussagekräftig.
Wir wissen nicht, wie der Mitarbeiter
mit der kleinsten
Personalnummer heißt. Wie
schon gezeigt, ist die
direkte
Angabe des Mitarbeiternamens in
der SELECT-Anweisung nicht
erlaubt. Damit der Name auch angegeben werden kann, muß
eine
Unterabfrage mit der Funktion MIN
aufgebaut werden.
Beispiel 7.32
Nennen Sie Personalnummer und Namen des Mitarbeiters mit der
kleinsten Personalnummer.
SELECT m_nr, m_name
FROM mitarbeiter
WHERE m_nr =
(SELECT MIN(m_nr)
FROM mitarbeiter);
Das Ergebnis ist:
m_nr |
m_name |
2581 |
Kaufmann |
(1 row)
Beispiel 7.33
Finden Sie die Personalnummer des Projektleiters, der als
letzter eingestellt wurde.
SELECT m_nr
FROM arbeiten
WHERE einst_dat =
(SELECT MAX(einst_dat)
FROM arbeiten
WHERE aufgabe = 'Projektleiter');
Das Ergebnis ist:
m_nr |
2581 |
(1 row)
Die
Funktionen MIN und MAX können
auf alle alphanumerischen
Werte angewendet werden. Bei den
alphanumerischen Werten wird
der kleinste bzw. der
größte Wert durch den Vergleich der
entsprechenden Zeichen nach ihrem
Binärcode ermittelt.
Die
Angabe DISTINCT, die
mehrfach vorhandene Werte
in
einer Spalte entfernt, hat
keine Bedeutung für
die
Aggregatfunktionen MIN und
MAX. Falls MIN bzw.
MAX auf
eine Spalte mit NULL-Werten
angewendet wird, werden
alle
NULL-Werte vor der Berechnung der
Aggregatfunktion entfernt.
Die Aggregatfunktion SUM berechnet die Summe der Werte einer
Spalte. Die Spalte muß vom
numerischen Datentyp sein.
Beispiel 7.34
Berechnen sie die Summe
der finanziellen Mittel
aller
Projekte.
SELECT SUM(mittel) AS summe
FROM projekt;
Das Ergebnis ist:
summe |
401500.000 |
(1 row)
Durch die Angabe DISTINCT
werden die mehrfach vorhandenen
Werte in der betreffenden Spalte vor Verwendung der
Funktion
SUM eliminiert. Falls
die Funktion SUM auf eine Spalte
mit
NULL-Werten angewendet wird, werden
vor der Berechnung der
Summe alle NULL-Werte entfernt.
Die Aggregatfunktion AVG berechnet das arithmetische Mittel
der
Datenwerte einer Spalte.
Diese Spalte muß
einen
numerischen Datentyp haben.
Beispiel 7.35
Berechnen Sie das arithmetische
Mittel der Geldbeträge, die
höher als 100.000 DM sind.
SELECT AVG(mittel) AS avg_mittel
FROM
projekt
WHERE mittel > 100000;
Das Ergebnis ist:
avg_mittel |
153250.000 |
(1 row)
Durch die Angabe DISTINCT
werden alle mehrfach vorhandenen
Werte vor der Berechnung des
arithmetischen Mittels aus der
betreffenden Spalte eliminiert. Falls die Funktion AVG auf
eine Spalte mit NULL-Werten
angewendet wird, werden
alle
NULL-Werte vor der
Berechnung des arithmetischen Mittels
entfernt.
Die Aggregatfunktion COUNT hat zwei
verschiedene Formen. Die
erste Form sieht wie folgt aus:
COUNT (DISTINCT sp_name)
Sie berechnet die Anzahl der Werte der Spalte sp_name,
wobei
alle mehrfach vorhandenen Werte nicht
berücksichtigt werden.
DISTINCT muß in diesem Fall angegeben
werden.
Beispiel 7.36
Finden Sie heraus, wieviele verschiedene Aufgaben in jedem
Projekt ausgeübt werden.
SELECT pr_nr, COUNT(DISTINCT aufgabe) AS anzahl
FROM arbeiten
GROUP BY pr_nr;
Das Ergebnis
ist:
pr_nr |
anzahl |
p1 |
3 |
p2 |
1 |
p3 |
3 |
(3 rows)
Die
Funktion COUNT DISTINCT entfernt alle NULL-Werte aus der
betreffenden Spalte.
Die zweite Form der Funktion COUNT sieht folgendermaßen aus:
COUNT (*)
Sie
berechnet die Anzahl der Reihen.
Beispiel 7.37
Finden Sie heraus, wieviele
Mitarbeiter in jedem
Projekt
arbeiten.
SELECT pr_nr, COUNT(*)
AS anzahl
FROM arbeiten
GROUP BY pr_nr;
Das
Ergebnis ist:
pr_nr |
anzahl |
p1 |
4 |
p2 |
3 |
p3 |
3 |
(3 rows)
Im
Unterschied zu der
ersten Form der
COUNT-Funktion,
berücksichtigt COUNT(*) auch Reihen
mit NULL-Werten.
Beispiel 7.38
Gruppieren Sie die Reihen
der Tabelle arbeiten nach
den vorhandenen Aufgaben
und finden Sie
die Anzahl der
Mitarbeiter der jeweiligen Aufgaben
heraus.
SELECT aufgabe, COUNT(*) AS anz_aufg
FROM arbeiten
GROUP BY aufgabe;
Das Ergebnis ist:
aufgabe |
anz_aufg |
Gruppenleiter |
2 |
Projektleiter |
2 |
Sachbearbeiter |
4 |
|
3 |
(4 rows)
Das
Ergebnis der Funktion
COUNT ist 0, falls sie auf eine
leere Menge angewendet wird (d.h. das Ergebnis liefert keine
Reihe).
Die
HAVING-Klausel hat dieselbe Funktion für die GROUP
BYKlausel
wie die WHERE-Klausel für die
SELECT-Anweisung. Mit
anderen Worten: Die
HAVING-Klausel definiert die
Bedingung
nach der die
Reihengrupen ausgewählt werden.
Die allgemeine
Form der HAVING-Klausel ist:
HAVING bedingung
wobei bedingung Aggregatfunktionen und Konstanten enthalten
darf. Der Ausdruck in bedingung muß
je Gruppe stets
einen einzigen Wert als
Ergebnis liefern. In
der Praxis
werden fast ausschließlich Vergleiche mit Aggregatfunktionen
durchgeführt.
Beispiel 7.39
Nennen Sie alle Projekte,
mit denen weniger
als vier
Mitarbeiter befasst sind.
SELECT pr_nr
FROM arbeiten
GROUP BY pr_nr
HAVING
COUNT(*) < 4;
Das Ergebnis ist:
pr_nr |
p3 |
(1 row)
Alle Reihen der Tabelle arbeiten
werden zunächst in bezug auf
die
Spalte pr_nr gruppiert.
Die Aggregatfunktion COUNT(*)
zählt alle Reihen jeder Gruppe und
wählt die Gruppen aus, die
weniger als vier Reihen beinhalten.
Die
HAVING-Klausel kann auch
ohne die GROUP
BY-Klausel
benutzt werden, obwohl dies in der
Praxis selten vorkommt. In
diesem Fall wird die gesamte Tabelle als eine einzige Gruppe
betrachtet.
Die ORDER BY-Klausel definiert die
Reihenfolge der Ausgabe
aller ausgewählten Reihen einer
SELECT-Anweisung. Diese
Klausel ist optional und erscheint
immer am Ende
einer
SELECT-Anweisung. Die allgemeine Form der ORDER BY-Klausel
ist:
ORDER BY {spalte | ganzzahl [ASC|DESC]},...
spalte bezeichnet eine Spalte, mit der der Sortierbegriff
definiert wird. Mit der
Angabe von ganzzahl wird eine ganze
Zahl definiert, die die
Position einer Spalte kennzeichnet.
ASC kennzeichnet die aufsteigende und DESC die absteigende
Sortierfolge. Fehlt
diese Angabe, werden
die Reihen
aufsteigend sortiert.
Beispiel 7.40
Geben Sie Personalnummer, Namen
und Vornamen aller
Mitarbeiter, sortiert nach
Personalnummern, an.
SELECT m_nr, m_name, m_vorname
FROM mitarbeiter
ORDER BY m_nr;
Das
Ergebnis ist:
m_nr |
m_name |
m_vorname |
2581 |
Kaufmann |
Brigitte |
9031 |
Meier |
Rainer |
10102 |
Huber |
Petra |
18316 |
Mueller |
Gabriele |
25348 |
Keller |
Hans
|
28559 |
Mozer |
Sibille |
29346 |
Probst |
Andreas |
(7 rows)
Die
in der ORDER BY-Klausel erscheinende Spalte muß in der
Projektion vorhanden sein. Die
Spalte kann auch implizit
durch die Angabe des
Zeichens "*" für alle Spalten einer
Tabelle vorhanden sein.
Der
Sortierbegriff kann, wie aus der Beschreibung der Syntax
ersichtlich, mehrere Spalten
beinhalten.
Beispiel 7.41
Geben Sie Namen, Vornamen
und Abteilungsnummer aller
Mitarbeiter an, deren Personalnummer kleiner als 20000 ist.
Die Ausgabe soll aufsteigend nach
Namen und Vornamen der
Mitarbeiter sortiert sein.
SELECT m_name, m_vorname, abt_nr
FROM mitarbeiter
WHERE m_nr < 20000
ORDER BY m_name,
m_vorname;
Das Ergebnis ist:
m_name |
m_vorname |
abt_nr |
Huber |
Petra |
a3 |
Kaufmann |
Brigitte |
a2 |
Meier |
Rainer |
a2 |
Mueller |
Gabriele |
a1 |
(4 rows)
Jede
Spalte in der
ORDER BY-Klausel kann durch eine ganze
Zahl
ersetzt werden, die die Position
dieser Spalte in der
Projektion definiert. Im letzten Beispiel könnte die ORDER
BY-Klausel auch folgende Form haben:
ORDER BY 1,2
Die
Verwendung der ganzen Zahlen in der ORDER BY-Klausel ist
die einzige Alternative, falls der
Sortierbegriff durch eine
Aggregatfunktion
definiert ist, wie
das folgende Beispiel
verdeutlicht.
Beispiel 7.42
Finden Sie die Anzahl aller Mitarbeiter in jedem Projekt und
sortieren Sie sie anschließend in
absteigender Reihenfolge.
SELECT pr_nr, COUNT(*) AS anzahl
FROM arbeiten
GROUP BY pr_nr
ORDER BY 2 DESC;
Das
Ergebnis ist:
pr_nr |
anzahl |
p1 |
4 |
p2
|
4 |
p3 |
3 |
(3 rows)
Bei
INGRES-SQL werden die
NULL-Werte bei aufsteigender
Sortierfolge nach allen anderen Werten, und bei
absteigender
Sortierfolge vor allen anderen Werten
ausgegeben.
Zusätzlich zu allen Formen
der SELECT-Anweisung, die
wir
bis jetzt beschrieben
haben, ist es
möglich, zwei
SELECT-Anweisung mit
einem Mengenoperator zu
verbinden.
INGRES-SQL unterstützt die
Mengenoperation Vereinigung.
Die Vereinigung zweier Datenmengen
beinhaltet alle Daten, die
entweder in der
ersten, oder in der zweiten oder in beiden
Datenmengen enthalten sind. Der Operator für die Vereinigung
der Datenmengen heißt bei SQL UNION.
Die allgemeine Form des Operators
UNION ist:
select_1 UNION [ALL] select_2 [UNION [ALL] select_3 ...]
select_1 und select_2
kennzeichnen zwei SELECT-Anweisungen,
die
der Operator UNION
verbindet. Die Angabe
ALL
legt fest, daß auch
mehrfach vorhandene Reihen
der
Ergebnistabelle ausgegeben
werden sollen. Diese
Angabe
beim
Operator UNION hat
dieselbe Bedeutung wie
in der
Projektion einer
SELECT-Anweisung. Trotzdem gibt
es
einen wichtigen Unterschied. In
der Projektion ist
die
Angabe ALL Voreinstellung, d.h. die
mehrfach vorhandenen
Reihen der Ergebnistabelle einer
SELECT-Anweisung werden
ausgegeben, falls weder ALL noch DISTINCT
angegeben ist.
Beim UNION-Operator
muß man ALL explizit angeben, damit die
mehrfach vorhandenen Reihen
ausgegeben werden.
Damit wir auch praktische
Beispiele mit der Mengenoperation
Vereinigung zeigen können,
werden wir eine
neue Tabelle
mit_erweiter erstellen. Die Tabelle mit_erweiter entspricht
der
Tabelle mitarbeiter bis auf eine zusätzliche Spalte -
wohnort. Die Spalte wohnort beschreibt den Wohnort
jedes
Mitarbeiters.
Die Tabelle mit_erweiter hat nach
der Erstellung und dem
Einfügen der Daten folgende Form:
mit_erweiter
m_nr |
m_name |
m_vorname |
abt_nr |
wohnort |
25348 |
Keller |
Hans |
a3
|
Muenchen |
10102 |
Huber |
Petra |
a3 |
Landshut |
18316 |
Mueller |
Gabriele |
a1 |
Rosenheim
|
29346 |
Probst |
Andreas |
a2
|
Augsburg
|
9031 |
Meier
|
Rainer
|
a2
|
Augsburg
|
2581 |
Kaufmann
|
Brigitte |
a2 |
Muenchen |
28559 |
Mozer |
Sibille |
a1 |
Ulm
|
Beispiel 7.43
Finden Sie alle Wohnorte der
Mitarbeiter und alle Standorte
der Abteilungen.
SELECT wohnort
FROM mit_erweiter
UNION
SELECT stadt
FROM abteilung;
Das Ergebnis ist:
wohnort |
Augsburg |
Landshut |
Muenchen |
Rosenheim |
Stuttgart |
Ulm |
(6 rows)
Damit zwei
SELECT-Anweisungen mit dem
UNION-Operator
verbunden sein können, müssen
folgende Voraussetzungen
erfüllt sein:
a) die Anzahl der Spalten in den
beiden Projektionen muß
gleich sein;
b) die entsprechenden
Spalten müssen denselben
Typ
haben.
Falls die Ausgabe sortiert
sein soll, darf
die ORDER
BY-Klausel nur in der letzten
SELECT-Anweisung angegeben
werden. Der Sortierbegriff in der
ORDER BY-Klausel darf in
diesem Fall nur mit Hilfe einer Ganzzahl definiert werden,
die die Position der Spalte
kennzeichnet.
Beispiel 7.44
Finden Sie die Personalnummer der
Mitarbeiter, die entweder
der Abteilung a1 angehören oder vor
dem 1.1.1988 in
das
Projekt eingetreten sind. Die Personalnummer sollen sortiert
ausgegeben werden.
SELECT m_nr
FROM mitarbeiter
WHERE abt_nr = 'a1'
UNION
SELECT m_nr
FROM arbeiten
WHERE einst_dat
< '01-jan-1988'
ORDER BY 1;
Das
Ergebnis ist:
m_nr |
18316 |
28559 |
29346 |
(3 rows)
Der UNION-Operator ist dem Operator
OR ähnlich. In
manchen Fällen ist es auch möglich, die Verbindung zweier
SELECT-Anweisungen mit
dem UNION-Operator durch
eine
SELECT-Anweisung mit dem Operator OR
zu ersetzen.
Beispiel 7.45
Finden Sie alle Mitarbeiter, die entweder der Abteilung a1
oder a2 oder aber beiden angehören.
SELECT m_nr, m_name, m_vorname
FROM mitarbeiter
WHERE abt_nr = 'a1'
UNION
SELECT m_nr, m_name,
m_vorname
FROM
mitarbeiter
WHERE abt_nr = 'a2';
Das Ergebnis ist:
m_nr |
m_name |
m_vorname |
2581 |
Kaufmann |
Brigitte |
9031 |
Meier |
Rainer |
18316 |
Mueller |
Gabriele |
28559 |
Mozer |
Sibille |
29346 |
Probst |
Andreas |
(5 rows)
Dieselbe Aufgabe
kann mit dem OR-Operator
einfacher gelöst
werden:
Beispiel 7.46
SELECT m_nr, m_name, m_vorname
FROM mitarbeiter
WHERE abt_nr = 'a1'
OR abt_nr = 'a2';
Der UNION-Operator kann nicht durch den OR-Operator ersetzt
werden, falls man Reihen aus zwei
verschiedenen Tabellen
wählt, wie es in den Beispielen 7.43
und 7.44 der Fall ist.
Zusätzlich zu der Operation
Vereinigung existieren in der
Mengenlehre zwei weitere Operationen:
- Durchschnitt
und
- Differenz.
Der
Durchschnitt zweier Datenmengen beinhaltet alle Daten,
die sowohl in der
ersten als auch in der zweiten Datenmenge
enthalten sind.
Die
Differenz zweier Datenmengen
beinhaltet alle Daten, die
in
der ersten Datenmenge enthalten
sind und in der zweiten
nicht.
INGRES-SQL unterstützt diese zwei
Operationen nicht direkt.
Trotzdem ist es möglich, die beiden Operationen mit Hilfe
anderer Operatoren zu ersetzen. Der Durchschnitt kann durch
den operator EXISTS (siehe Beispiel 8.21) und die Differenz
durch den Operator NOT EXISTS
(siehe Beispiel 8.22) ersetzt
werden.
A.7.1 Wählen
Sie alle Reihen
der Tabellen arbeiten und
mitarbeiter aus.
A.7.2 Finden Sie die Personalnummer aller
Sachbearbeiter.
A.7.3 Finden
Sie die Personalnummer der Mitarbeiter, die in
Projekt p2 arbeiten und
deren Personalnummer kleiner als
10000 ist.
A.7.4 Finden
Sie die Personalnummer der Mitarbeiter, die nicht
im Jahr 1988 in ihr Projekt
eingesetzt sind.
A.7.5 Finden
Sie Personalnummer aller
Mitarbeiter, die in
Projekt p1 eine leitende
Aufgabe (Gruppen- oder
Projektleiter) haben.
A.7.6 Finden
Sie das Einstellungsdatum der Mitarbeiter in
Projekt p2, deren Aufgabe
noch nicht festgelegt ist.
A.7.7 Finden
Sie Personalnummer, Namen
und Vornamen aller
Mitarbeiter, deren Name mit
"M" bzw. "H"
anfängt und mit
"er" endet.
A.7.8 Nennen
Sie die Personalnummer aller
Mitarbeiter, deren
Standort Stuttgart ist.
A.7.9 Finden
Sie Namen und Vornamen aller
Mitarbeiter, die am
01-apr-1989 eingesetzt worden
sind.
A.7.10 Gruppieren
Sie alle Abteilungen auf Grund ihres
Standortes.
A.7.11 Nennen Sie die grösste existierende
Personalnummer.
A.7.12 Welche Aufgaben werden von mehr als
zwei Mitarbeiter
ausgeübt?
A.7.13 Finden
Sie die Personalnummer aller
Mitarbeiter, die
entweder Sachbearbeiter sind oder der
Abteilung a3
angehören.
A.7.14 Warum ist folgende Aufgabe falsch
SELECT pr_name
FROM projekt
WHERE pr_nr =
(SELECT pr_nr
FROM
arbeiten
WHERE aufgabe = 'Sachbearbeiter');
Wie sollte diese Aufgabe richtig
lauten?