Professioneller Einstieg in Oracle SQL

1 Auswertungen in relationalen Datenbanken

1.1 Grundstruktur der SELECT-Anweisung

SELECT-Klausel
FROM-Klausel

1.1.1 Möglichkeiten in der Select-Klausel

Spaltenliste z.B. Spaltenname 1, Spaltenname 2
* d.h. KEINE Projektion, also ALLE Spalten der "Datenquelle"
DISTINCT sorgt für EINDEUTIGE Ergebnissätze
Ausdrücke als Elemente einer Spaltenliste Skalare Funktionen, Subselects (Unterabfragen)

1.1.2 Möglichkeiten in der FROM-Klausel

Ein Tabellenname legt die eine Datenquelle fest
Liste an Tabellennamen erteilt den Auftrag, das "kartesische Produkt" zu bilden
JOIN-Aufträge zur Einschränkung des kartesischen Produktes
  • als INNER JOIN
  • um NUR die Kombination von Datensätzen zu erhalten, die zusammengehören
  • Mögliche Syntax:
    1. Tabellenname1 JOIN Tabellenname2 ON Vergleichsbedingung mit Vergleichsbedingung: Spalte_aus_Tabelle1 = Spalte_aus_Tabelle2
    2. Tabellenname1 INNER JOIN Tabellenname2 USING(Spaltenname)
      • z.B. Kunde INNER JOIN Auftrag USING(KDNR)
  • andere JOIN Aufträge: später!
Grundsätzlich: NUR in der FROM-Klausel können Tabellen-Aliase zugeordnet werden: Syntax: Tabellenname Alias
Sinn:
  • z.B. anstelle von Auftrag.KDNR kürzer A.KDNR
    (sofern in der FROM-Klausel: FROM Auftrag A, ... )
  • falls eine Tabelle ein Beziehung zu sich selbst aufweist, muss diese Tabelle ggfs. mehrfach in der FROM-Klausel angegeben werden; dann MUSS ( zur eindeutigen Angabe einer jeden Spalte!) bei jeder Angabe des Tabellenname ein (unterschiedlicher) Alias zugeordnet werden
    Details und Beispiele: später!

1.2 Weitere optionale Klauseln

WHERE-Klausel

1.2.1 Sinn

1.2.2 Syntax

  1. für Restriktionsbedingungen:
    • Eine Einfache Vergleichsbedingung:
      • Spaltenname Vergleichsoperator Vergleichswert
      • Vergleichsoperatoren:
        Operator Beschreibung
        = ist gleich
        > größer
        < kleiner
        <> ungleich
        <= kleiner gleich
        >= größer gleich
      • Vergleichswerte:
        • Numerische Konstanten (Zahlen) ohne Kennzeichnung angeben!
          z.B. 1 100 4711 1.75 (für "normal" 1,75)
        • Text-Konstanten in EINFACHE Hochkommata einschließen!
          z.B. 'Nürnberg' 'Huber'
        • Datum-Konstanten (wie Text-Konstanten) in EINFACHE Hochkommata einschließen!
          z.B. '18.1.2016' '01.01.2017'
    • Zusammengesetzte Bedingungen:
      • einfache_Bedingung1 Verknüpfungsoperator einfache_Bedigung2
      • Verknüpfungsoperatoren: AND OR
      • AND: BEIDE einfachen Bedingungen müssen wahr sein, damit die zusammengesetzte Bedingung wahr ist
      • OR: mindestens EINE Bedingung muss wahr sein ...
      • Regel: AND hat Vorrang vor OR (d.h. AND-Verknüpfungen sind implizit geklammert)
      • Beispiele:
        • Ort='Nürnberg' AND Kunde_seit<=2000
        • Ort='Nürnberg' OR Ort='Fürth'
        • Ort='Nürnberg' OR Ort='Fürth' AND Kunde_seit<=2000 Im Ergebnis landen nur Fürth wenn Kunde_seit<=2000 zutrifft. Nürnberg erscheint ohne diese Einschränkung
        • (Ort='Nürnberg' OR Ort='Fürth') AND Kunde_seit<=2000
    • Aufzählungen:
      Spaltenname IN (Listen von Vergleichswerten) eine Ersatz-Schreibweise für spezielle OR-Verküpfungen!
      z.B. Ort IN ('Nürnberg','Fürth','Erlangen') ist eine Kurzschreibweise für:
      Ort='Nürnberg' OR Ort='Fürth' OR Ort='Erlangen'
      Spaltenname NOT IN (Listen von Vergleichswerten) eine sogenannte "negierte" Aufzählung
      z.B. Ort NOT IN ('Hof', 'Ulm', 'Rom') ist eine Kurzschreibweise für:
      Ort<>'Hof' AND Ort<>'Ulm' AND Ort<>'Rom'
    • Wertebereichsprüfungen:
      Spaltenname BETWEEN Anfangswert AND Endewert eine Ersatz-Schreibweise für (eine) spezielle AND Verknüpfung
      z.B.
      • Menge BETWEEN 100 AND 500
        eine Kurzschreibweise für: Menge >= 100 AND Menge <= 500
      • BestellDatum BETWEEN '01.10.2015' AND '31.12.2015'
      Spaltenname NOT BETWEEN Anfangswert AND Endewert ist erfüllt, falls der Spaltenwert AUßERHALB des Wertebereichs liegt
      z.B. Menge NOT BETWEEN 20 AND 70 ist eine Kurzschreibweise für:
      Menge < 20 OR Menge > 70
    • Mustervergleiche:
      Teile eines Text-Inhaltes sind bekannt, aber NICHT der vollständige Wert!
      Spaltenname LIKE Vergleichs-Muster
      • Vergleichs-Muster MUSS MINDESTENS 1 "Joker-Zeichen" enthalten
      • Mögliche "Joker-Zeichen":
        • % Platzhalter für beliebig viele beliebige Zeichen (auch kein einziges!)
        • _ (Unterstrich) Platzhalter für genau 1 beliebiges Zeichen
      Typische Fragestellung:
      1. Spaltenwert muss BEGINNEN MIT:
        Bezeichnung LIKE 'Ha%'
      2. Spaltenwert muss ENDEN MIT:
        z.B. Bezeichnung LIKE '%nuss'
      3. Spaltenwert muss ENTHÄLT:
        z.B. Bezeichnung LIKE '%wurst%'
      Spaltenname NOT LIKE Vergleichsmuster z.B. Nachname NOT LIKE '%er' ist wahr, falls der Wert in der Spalte Nachname NICHT mit "er" endet
    • "Leere" Spalten finden:
      Spaltenname IS NULL Dient dem auffinden von Datensätzen in denen eine anzugebende Spalte (noch) nicht gefüllt ist. (d.h. keinen Wert besitzt)
      z.B. Liefer_Datum IS NULL
      Spaltenname IS NOT NULL liefert DIE Datensätze in denen die angegebene Spalte GEFÜLLT ist (d.h. NICHT LEER ist)
  2. für Joinbedingungen (sofern noch nicht in der FROM-Klausel erledigt)

    allgemeiner Aufbau: Spalte_aus_Tabelle1 = Spalte_aus_Tabelle2

    SELECT ...
    FROM Kunde, Auftrag
    WHERE K_KDNR = A_KDNR
    AND K_ORT = 'Nürnberg'
    SELECT ...
    FROM Kunde INNER JOIN Auftrag
    ON K_KDNR = A_KDNR
    WHERE K_ORT = 'Nürnberg'

1.3 "Werkzeuge" für zusammenfassende Auswertungen

1.3.1 Aggregatfunktionen

1.3.2 Gruppierte Auswertungen

1.3.3 Einschränkung von Gruppierergebnissen

1.3.4 Sortierung der Ergebnissätze

1.4 Arbeiten mit Datumswerten

1.4.1 Aufbau einer Datumsspalte

1.4.2 Zugriff auf einzelne Komponenten

1.5 Mengentheoretische SQL-Anweisungen

1.5.1 Zur Bildung der Schnittmenge

1.5.2 zur Bildung der Vereinigungsmenge

1.5.3 zur Bildung der Differenzmenge

1.6 Auswertungen, die mehrere SELECT-Anweisungen benötigen

1.6.1 Formales

1.6.2 Beispiel

Wie heißen der bzw. die Mitarbeiter mit dem höchsten Gehalt?

Lösung Möglichkeit:

  1. über Sub-Select:
    SELECT MNAME
    FROM MITARB
    WHERE MGEHALT = (SELECT MAX(MGEHALT) FROM MITARB)
    					
  2. über anonyme View
    SELECT MNAME
    FROM MITARB JOIN (SELECT MAX(MGEHALT) MAXGEHALT
    		  FROM MITARB)
    ON MGEHALT = MAXGEHALT
    					
  3. über "echtes" View-Objekt
    1. Anlegen des View-Objektes
      CREATE VIEW VMAXGEHALT AS 
      SELECT MAX(MGEHALT) MAXGEHALT FROM MITARB
      							
      (Testen: SELECT * FROM VMAXGEHALT)
    2. "echtes View-Objekt ANSTELLE der anonymen View in die abschießende SELECT-Anweisung einsetzen
      SELECT MNAME
      FROM MITARB JOIN VMAXGEHALT
      ON MGEHALT = MAXGEHALT
      							

1.6.3 Weitere typische beispielhafte Fragestellungen

1.7 Typische beispielhafte Fragestellungen, in denen Outer Joins benötigt werden

1.7.1 Syntax und Wirkungsweise

1.8 DML-Anweisungen

1.8.1 Begriff

1.8.2 3 Anweisungsarten

  1. Schreiben eines neuen Datensatzes in eine Tabelle
    Syntax
    1. Möglichkeit INSERT INTO Tabellenname VALUES(Werteliste)
    Voraussetzung:
    • die Struktur der Tabelle ist bekannt (d.h. welche Spalten von welchem Datentyp in welcher Reihenfolge)
    • Für JEDE Spalte MUSS in der Werteliste genau ein Wert angegeben werden!
    • Sollte eine Spalte "leer" bleiben müssen, muss als Wert NULL angegeben werden!
    Beispiel 1: Es soll ein neuer Artikel ins Sortiment aufgenommen werden:
    • Bezeichnung: Maus 123
    • Zubehör
    • ArtikelNr: 21
    • Bezogen von: Lieferant mit der Nr 5
    INSERT INTO ARTIKEL VALUES(21, 'Maus 123', 'Zubehör', 5)
    Beispiel 2: Ein neuer Mitarbeiter wurde eingestellt:
    • Name: Hutzler
    • Gehalt: 3333
    • Zur Zeit noch kein Vorgesetzter
    INSERT INTO MITARB VALUES('Hutzler', NULL, 3333)
    2. Möglichkeit INSERT INTO Tabellenname (Spaltenliste) VALUES (Werteliste)
    Merkmal:
    • alle Tabellenspalten die NICHT in der Spaltenliste aufgeführt sind, werden automatisch mit NULL belegt
    • außerdem können die Spalten in einer beliebigen Reihenfolge angegeben werden!
    • Der erste Wert in der Werteliste wird der ersten Spalte der Spaltenliste zugeordnet,
      Der zweite Wert in der Werteliste wird der zweiten Spalte der Spaltenliste zugeordnet,
      usw. ...
    Beispiel 1: Es ist ein weiterer Mitarbeiter eingestellt worden:
    • Gehalt: 5555
    • Kein Vorgesetzter
    • Beck
    INSERT INTO MITARB (MGEHALT, MNAME) VALUES (5555, 'Beck')
    Beispiel 2: Der neue Lieferant Toshiba mit der Nummer 11 soll aufgenommen werden.
    INSERT INTO LIEFERANTEN (LIEF_NAME, LIEF_NR) VALUES ('Toshiba', 11)
  2. Löschen von Datensätzen (einer oder mehrere) aus einer Tabelle
    Syntax
    DELETE FROM Tabellenname zum löschen ALLER Datensätze aus der angegebenen Tabelle
    DELETE FROM Tabellenname WHERE Bedingung zum löschen der Datensätze, die die Bedingung erfüllen
    Beispiel 1: Der Lieferant mit der Nr 5 soll entfernt werden
    DELETE FROM LIEFERANTEN WHERE LIEF_NR = 5
    Beispiel 2: Die Artikel mit der Nr. 4, 6 und 7 sollen entfernt werden
    DELETE FROM ARTIKEL WHERE ART_NR IN (4, 6, 7)
    Beispiel 3: Die Kunden, zu denen aktuell keine Bestellungen vorliegen, sollen entfernt werden:
    DELETE FROM KUNDEN WHERE KNR NOT IN (
    SELECT DISTINCT KNR
    FROM BESTELLUNGEN)
  3. Ändern von Spaltenwerten in Datensätzen einer Tabelle
    Syntax
    1. Möglichkeit Ändern der Werte in einer Spalte einer Tabelle in ALLEN Datensätzen
    UPDATE Tabellenname SET Spaltenname = Wert
    Beispiel 1: Bei allen Bestellvorgängen soll die Bestellmenge auf 5 gesetzt werden:
    UPDATE BESTELLUNGEN SET MENGE = 5
    Beispiel 2: Die Gehälter aller Mitarbeiter sollen um 5% erhöht werden:
    UPDATE MITARB SET MGEHALT = MGEHALT * 1.05
    2. Möglichkeit Ändern der Werte in einer Spalte einer Tabelle NUR in bestimmten Datensätzen
    UPDATE Tabellenname SET Spaltenname = Wert WHERE Bedingung
    Beispiel 1: Der Kunde mit der Nr. 5 hat seinen Namen geändert: Köhler
    UPDATE KUNDEN SET KNAME = 'Köhler' WHERE KNR = 5
    Beispiel 2: Die Mitarbeiter des Vorgesetzten Frisch erhalten ein um 500€ höheres Gehalt
    UPDATE MITARB SET MGEHALT = MGEHALT + 500 WHERE MCHEF = 'FRISCH'
    3. Möglichkeit Ändern der Werte in MEHREREN Spalten einer Tabelle (in allen oder nur bestimmten Datensätzen)
    UPDATE Tabellenname SET
           Spaltenname1 = Wert1,
           Spaltenname2 = Wert2,
           Spaltenname3 = Wert3,
           usw. ...
    WHERE Bedingung
    Beispiel 1: Der Kunde mit der Nr. 5 ist umgezogen; neue Adresse: 90402 Nürnberg, Peuntgasse 4
    UPDATE KUNDEN
    SET KPLZ = 90402,
        KORT = 'Nürnberg',
        KSTRASSE = 'Peuntgasse',
        KHSNR = '4'
    WHERE KNR = 5
    Beispiel 2: Die Mitarbeiter des Vorgesetzten Frisch sollen dem Mitarbeiter Müller direkt unterstellt werden und ihr Gehalt soll 1000€ weniger als das Gehalt von Müller betragen
    UPDATE MITARB
    SET MCHEF = 'Müller',
        MGEHALT = (SELECT MGEHALT
                   FROM MITARB
                   WHERE MNAME = 'Müller') - 1000
    WHERE MCHEF = 'Frisch'

1.9 korrelierte Unterabfragen

1.9.1 Wesen

bei der Auswertung eines Datensatzes in der Unterabfrage (d.h. Sub-Select) muss der jeweils aktuelle Datensatz der "äußeren" Abfrage berücksichtigt werden.

1.9.2 Formales

2 Arbeiten mit "Datums"

3 Übungen

SQL-Übungen (zur Einstimmung) - Beispiel-Szenario

Gegeben sei folgendes 'Beispiel-Szenario'
Von KUNDEN können BESTELLUNGEN über ARTIKEL aufgegeben werden, die ihrerseits von bestimmten LIEFERANTEN bezogen werden.

Tabelle LIEFERANTEN
LIEF_NR LIEF_NAME
1 NEC
2 Audio Master
3 Thomson
4 Easyprint
5 Sharp
Tabelle ARTIKEL
ART_NR ART_BEZ ART_ART LIEF_NR
1 Multisync II Monitor 1
2 Multisync I Monitor 2
3 Herkules Grafikkarte 1
4 Thomson Monitor 3
5 Flat 14" Monitor 2
6 P6 + Drucker 4
7 P7 + Drucker 4
8 Laser Printer Drucker 4
Tabelle BESTELLUNGEN
KNR ART_NR MENGE
1 2 1
1 3 3
4 2 2
2 8 1
3 1 1
3 8 1
3 3 1
Tabelle KUNDEN
KNR KNAME KSTRASSE KHSNR KPLZ KORT
1 FAMA Goethestr 19 60700 Langen
2 GSA Hoenbergstr 2a 63700 Oberursel
3 Klöckner Paradiesweg 7 20800 Pinneberg
4 RADOVAN Im Sand 45 10000 Berlin
5 Göhler Schmalweg 11 69000 Heidelberg

Völlig unabhängig davon gibt es noch eine weitere Tabelle namens MITARB

In dieser Tabelle gibt es pro Mitarbeiter 1 Datensatz

Stark vereinfacht wird darin für jeden einzelnen Mitarbeiter (identifizierbar über die Spalte MNAME ) das Gehalt des jeweiligen Mitarbeiters (Spalte MGEHALT ) sowie der Name des direkten Vorgesetzten (Spalte MCHEF ), der natürlich ebenfalls ein Mitarbeiter ist (!!!), festgehalten

Tabelle MITARB
MNAME MCHEF MGEHALT
Müller 4500
Günther Müller 3000
Weber Müller 4000
Frisch Müller 4600
Heck Günther 3100
Hinz Günther 2700
Hilt Günther 2900
Meier Frisch 2100
Korn Frisch 3200

Beispiele:
der Mitarbeiter "Meier" erhält ein Gehalt von 2100 Euro; sein Vorgesetzter heißt Frisch

der Mitarbeiter "Müller" erhält ein Gehalt von 4500 Euro; er hat k e i n e n Vorgesetzten

SQL-Übungen (zur Einstimmung)

Formulieren Sie geeignete SELECT -Anweisungen zu den folgenden Fragestellungen.

Notieren Sie sich bitte jeweils Ihre Eingaben und überprüfen Sie die erhaltenen/angezeigten Ergebnisse mit Hilfe der Ihnen vorliegenden Zusammenstellung der Tabelleninhalte aus der Vorlage bzw. durch wiederholtes Anzeigen der Ausgangsinhalte.

  1. Zeigen Sie jeweils die kompletten Inhalte der Tabellen LIEFERANTEN, ARTIKEL, KUNDEN und BESTELLUNGEN an.
    SELECT * FROM KUNDEN;
    SELECT * FROM LIEFERANTEN;
    SELECT * FROM ARTIKEL;
    SELECT * FROM BESTELLUNGEN;
    SELECT * FROM MITARB;
  2. Welche Nummern und welche Bezeichnungen haben die gespeicherten Artikel?
    SELECT ART_NR, ART_BEZ FROM ARTIKEL;
  3. Aus welchen Orten stammen die gespeicherten Kunden?
    SELECT KORT FROM KUNDEN;
  4. Welche Artikel (Nr., Bez.) sind Monitore?
    SELECT ART_NR, ART_BEZ
    FROM ARTIKEL
    WHERE ART_ART = 'Monitor';
  5. Welche Artikel (Nr., Bez., Art) werden vom Lieferanten 2 bezogen?
    SELECT ART_NR, ART_BEZ ART_ART
    FROM ARTIKEL
    WHERE LIEF_NR = 2;
  6. Zu welchen Artikeln (Nr., Bez., Art) liegen eigentlich Bestellungen vor?
    SELECT DISTINCT A.ART_NR, A.ART_BEZ, A.ART_ART
    FROM BESTELLUNGEN B JOIN ARTIKEL A
    ON B.ART_NR = A.ART_NR;
  7. Gibt es Bestellungen (alle Angaben) zum Artikel mit der Nr. 4?
    SELECT * 
    FROM BESTELLUNGEN
    WHERE ART_NR = 4;
  8. Ermitteln Sie die Adresse der Firma Klöckner.
    SELECT KSTRASSE, KHSNR, KPLZ,KORT
    FROM KUNDEN
    WHERE KNAME = 'Klöckner'
  9. Welche Kunden (alle Angaben) sind im Postleitzahlengebiet 6 ansässig?
    SELECT *
    FROM KUNDEN
    WHERE KPLZ LIKE '6%'
    
    ODER BESSER (KPLZ ist ein nummerischer Wert!)
    
    SELECT *
    FROM KUNDEN
    WHERE KPLZ BETWEEN 60000 AND 69999;
  10. Welche Lieferanten (Name) liefern einen Monitor?
    SELECT DISTINCT LIEF_NAME
    FROM LIEFERANTEN L JOIN ARTIKEL A
    ON L.LIEF_NR = A.LIEF_NR
    WHERE A.ART_ART = 'Monitor';
  11. Welche Artikel (Nr., Bez., Art) werden vom Lieferanten NEC bezogen?
    SELECT ART_NR, ART_BEZ, ART_ART
    FROM LIEFERANTEN L JOIN ARTIKEL A
    ON L.LIEF_NR = A.LIEF_NR
    WHERE L.LIEF_NAME = 'NEC';
  12. Welche Artikel (Nr., Bez., Art) wurden vom Kunden Klöckner bestellt?
    SELECT A.ART_NR, ART_BEZ, ART_Art
    FROM KUNDEN K JOIN BESTELLUNGEN B
    ON K.KNR = B.KNR
    JOIN ARTIKEL A
    ON B.ART_NR = A.ART_NR
    WHERE KNAME = 'Klöckner';
  13. Von welchem/welchen Lieferanten (Name) werden die Artikel bezogen, die vom Kunden FAMA bestellt wurden?
    SELECT DISTINCT LIEF_NAME
    FROM KUNDEN K
    	JOIN BESTELLUNGEN USING(KNR)
    	JOIN ARTIKEL USING(ART_NR)
    	JOIN LIEFERANTEN USING(LIEF_NR)
    WHERE KNAME = 'FAMA';
  14. Welche Kunden (alle Angaben) haben Artikel bestellt, die vom Lieferanten NEC bezogen werden?
    SELECT DISTINCT K.*
    FROM KUNDEN K
    	JOIN BESTELLUNGEN B ON K.KNR = B.KNR
    	JOIN ARTIKEL USING(ART_NR)
    	JOIN LIEFERANTEN USING(LIEF_NR)
    WHERE LIEF_NAME= 'NEC';
  15. Zu welchen Monitoren (Nr., Bez.) liegen derzeit Bestellungen vor?
    SELECT DISTINCT ART_NR, ART_BEZ
    FROM ARTIKEL JOIN BESTELLUNGEN USING(ART_NR)
    WHERE ART_ART = 'Monitor';
  16. Von welchen Lieferanten (Name) werden diejenigen Artikel bezogen, zu denen Bestellungen über mehr als 1 Stück vorliegen?
    SELECT DISTINCT LIEF_NAME
    FROM BESTELLUNGEN
    	JOIN ARTIKEL USING(ART_NR)
    	JOIN LIEFERANTEN USING(LIEF_NR)
    WHERE MENGE > 1;
  17. Welche Kunden (Name, Ort) haben jeweils mehr als 1 Stück eines Artikels bestellt?
    SELECT DISTINCT KNAME, KORT
    FROM BESTELLUNGEN JOIN KUNDEN USING(KNR)
    WHERE MENGE > 1;
  18. Welche Kunden (Name, Ort) haben welche Artikel (Nr., Bez.) in welcher Stückzahl bestellt?
    SELECT KNAME, KORT, ART_NR, ART_BEZ, MENGE
    FROM BESTELLUNGEN
    	JOIN KUNDEN USING(KNR)
    	JOIN ARTIKEL USING(ART_NR);
  19. Welche Kunden (Name, Ort) haben einen Monitor bestellt?
    SELECT KNAME, KORT
    FROM BESTELLUNGEN
    	JOIN KUNDEN USING(KNR)
    	JOIN ARTIKEL USING(ART_NR)
    WHERE ART_ART = 'Monitor';
  20. Von welchen Kunden (Nr., Name, Ort) liegen überhaupt Bestellungen vor?
    SELECT DISTINCT KNR, KNAME, KORT
    FROM BESTELLUNGEN JOIN KUNDEN USING(KNR);
  21. Zeigen Sie den kompletten Inhalt der Tabelle MITARB an
    SELECT * FROM MITARB;
  22. Welche Mitarbeiternamen beginnen mit einem H?
    SELECT MNAME
    FROM MITARB
    WHERE MNAME LIKE 'H%';
  23. Wer (Name, Gehalt) verdient mehr als 3000 Euro?
    SELECT MNAME, MGEHALT
    FROM MITARB
    WHERE MGEHALT > 3000;
  24. Wie heißen die Mitarbeiter von Frau/HerrnFrisch?
    SELECT MNAME
    FROM MITARB
    WHERE MCHEF = 'Frisch';
  25. Zeigen Sie für alle Mitarbeiter, die mehr verdienen als ihr "Chef", deren Namen, ihr Gehalt, den Namen ihres "Chefs" und dessen Gehalt an.
    SELECT B.MNAME, B.MGEHALT, B.MCHEF, A.MGEHALT
    FROM MITARB A JOIN MITARB B ON A.MNAME = B.MCHEF
    WHERE B.MGEHALT > A.MGEHALT;
  26. Finden Sie heraus, ob bzw. welcher "Chef" weniger als 4000 Euro verdient und zeigen Sie dessen Name und Gehalt an.
    SELECT B.MCHEF,
          (SELECT MGEHALT
           FROM MITARB
           WHERE MNAME = B.MCHEF) SGEHALT
    FROM MITARB A JOIN MITARB B ON A.MNAME = B.MCHEF
    GROUP BY B.MCHEF
    HAVING (SELECT MGEHALT
    	FROM MITARB
    	WHERE MNAME = B.MCHEF) < 4000;
    
    ODER
    
    SELECT DISTINCT A.MCHEF, A.MGEHALT
    FROM MITARB A JOIN MITARB B ON A.MNAME = B.MCHEF
    WHERE A.MGEHALT < 4000
Fallstudie Fahrradverleih Übungen
  1. Formulieren Sie bitte zu folgenden Fragestellungen jeweils geeignete SELECT-Anweisungen.
    1. Wie viel wurde für die Anschaffung von Fahrrädern in 2015 insgesamt ausgegeben?
      SELECT SUM(F_EK)
      FROM FAHRRAEDER
      WHERE F_ADAT BETWEEN '01.01.2015' AND '31.12.2015'
    2. Wie viele Fahrräder gibt es pro Hersteller (Hersteller, Anzahl Fahrräder)?
    3. Wie viele Damenräder wurden pro Hersteller angeschafft (Hersteller, Anzahl Fahrräder)
  2. Formulieren Sie zu folgenden Fragestellungen jeweils geeignete SELECT-Anweisungen.
    1. Für welche Touren (alle Angaben) liegt zurzeit (noch) keine einzige Anmeldung vor?
      SELECT T.*
      FROM TOUREN T
      WHERE T_TNR NOT IN (SELECT TA_TNR
                         FROM TOURANMELDUNGEN
                         GROUP BY TA_TNR)
    2. Welche Fahrräder (Nr, Hersteller, Bez.) sind zurzeit verfügbar, also nicht entliehen?
      SELECT F_FNR, F_HERST, F_BEZ
      FROM FAHRRAEDER
      WHERE F_FNR NOT IN (SELECT V_FNR
                          FROM VERLEIHDATEN
                          WHERE V_RDAT IS NULL)
    3. Für welche Touren liegen zurzeit weniger als 3 Anmeldungen vor (Nr, Zielort, Beginn, Anzahl Anmeldungen)?
      SELECT T_TNR, T_ORT, T_BDAT, COUNT(TA_TNR)
      FROM TOUREN LEFT OUTER JOIN TOURANMELDUNGEN
      ON T_TNR = TA_TNR
      GROUP BY T_TNR, T_ORT, T_BDAT
      HAVING COUNT(TA_TNR) < 3
    4. Welches ist das älteste Fahrrad bzw. welche sind die ältesten Fahrräder (Nr, Hersteller, Bez., Art, Anschaffungsdatum)?
      SELECT F_FNR, F_HERST, F_BEZ, F_ART, F_ADAT
      FROM FAHRRAEDER
      WHERE F_ADAT = (SELECT MIN(F_ADAT)
                      FROM FAHRRAEDER)
    5. Bei welchem bzw. welchen Hersteller(n) wurde seit 2010 am meisten für die Anschaffung von Damenrädern ausgegeben (Hersteller, Betrag)?
      SELECT F_HERST, SUM(F_EK)
      FROM FAHRRAEDER
      WHERE F_TYP = 1
      AND F_ADAT >= TO_DATE('01.01.2010', 'DD.MM.YYYY')
      GROUP BY F_HERST
      HAVING SUM(F_EK) = (SELECT MAX(SUM(F_EK))
                          FROM FAHRRAEDER
                          WHERE F_TYP = 1
                          AND F_ADAT >= TO_DATE('01.01.2010', 'DD.MM.YYYY')
                          GROUP BY F_HERST)
                                              
    6. Für welche Tour(en) liegen die meisten Anmeldungen vor (Nr, Zielort, Beginn, Anzahl Anmeldungen)?
      SELECT T_TNR, T_ORT, T_BDAT, ANZAHL
      FROM TOUREN JOIN (SELECT TA_TNR, COUNT(*) ANZAHL
                        FROM TOURANMELDUNGEN
                        GROUP BY TA_TNR
                        HAVING COUNT(*) = (SELECT MAX(COUNT(*))
                                           FROM TOURANMELDUNGEN
                                           GROUP BY TA_TNR))
      ON T_TNR = TA_TNR
    7. Wohin führt bzw. führen die Tour(en), die als nächstes angeboten wird bzw. werden?
      (d.h. es ist nur der eine "nächste" Beginntermin interessant, falls es überhaupt einen nächsten gibt!!!)
      SELECT T_ORT
      FROM TOUREN
      WHERE T_BDAT = (SELECT MIN(T_BDAT)
                      FROM TOUREN
                      WHERE T_BDAT > SYSDATE)
Fallstudie Firma - Situationsbeschreibung
Aufgabenbeschreibung

Mit dem folgenden Szenario soll eine Firma abgebildet werden, deren Mitarbeiter gewissen Abteilungen angehören und gleichzeitig in Projekten, die unabhängig von den Abteilungen sind, arbeiten. Dementsprechend existieren vier Tabellen mit den angegebenen beispielhaften Inhalten.

SQL Anweisungen
CREATE TABLE ABTEILUNG (
ABT_NR varchar2(2) NOT NULL,
ABT_NAME varchar2(15) NOT NULL,
STADT varchar2(15) NOT NULL,
PRIMARY KEY(ABT_NR));

INSERT INTO ABTEILUNG VALUES ('a1', 'Beratung', 'Muenchen');
INSERT INTO ABTEILUNG VALUES ('a2', 'Diagnose', 'Muenchen');
INSERT INTO ABTEILUNG VALUES ('a3', 'Freigabe', 'Stuttgart');

CREATE TABLE PROJEKT (
PR_NR varchar2(2) NOT NULL,
PR_NAME varchar2(15) NOT NULL,
MITTEL Number(6) NOT NULL,
PRIMARY KEY(PR_NR));

INSERT INTO PROJEKT VALUES ('p1', 'Apollo', 120000);
INSERT INTO PROJEKT VALUES ('p2', 'Gemini', 95000);
INSERT INTO PROJEKT VALUES ('p3', 'Merkur', 186500);

CREATE TABLE MITARBEITER (
M_NR number(5) NOT NULL,
M_NAME varchar2(15) NOT NULL,
M_VORNAME varchar2(10) NOT NULL,
ABT_NR varchar2(2) NOT NULL,
WOHNORT varchar2(15) NOT NULL,
PRIMARY KEY(M_NR),
FOREIGN KEY(ABT_NR) REFERENCES ABTEILUNG(ABT_NR));

INSERT INTO MITARBEITER VALUES (25348, 'Keller', 'Hans', 'a3','Muenchen');
INSERT INTO MITARBEITER VALUES (10102, 'Huber','Petra', 'a3', 'Landshut');
INSERT INTO MITARBEITER VALUES (18316, 'Mueller', 'Gabriele', 'a1','Rosenheim');
INSERT INTO MITARBEITER VALUES (29346, 'Probst', 'Andreas', 'a2','Augsburg');
INSERT INTO MITARBEITER VALUES (9031, 'Meier','Rainer', 'a2','Augsburg');
INSERT INTO MITARBEITER VALUES (2581, 'Kaufmann', 'Brigitte', 'a2','Muenchen');
INSERT INTO MITARBEITER VALUES (28559, 'Mozer', 'Sibille', 'a1','Ulm');

CREATE TABLE ARBEITEN (
M_NR number(5) NOT NULL,
PR_NR varchar2(2) NOT NULL,
AUFGABE varchar2(30) NULL,
EINST_DAT DATE NOT NULL,
FOREIGN KEY(M_NR) REFERENCES MITARBEITER(M_NR),
FOREIGN KEY(PR_NR) REFERENCES PROJEKT(PR_NR));

INSERT INTO ARBEITEN VALUES (10102, 'p1', 'Projektleiter', '01.10.2003');
INSERT INTO ARBEITEN VALUES (10102, 'p3', 'Gruppenleiter','01.01.2004');
INSERT INTO ARBEITEN VALUES (25348, 'p2', 'Sachbearbeiter', '15.02.2003');
INSERT INTO ARBEITEN VALUES (18316, 'p2', '', '01.06.2004');
INSERT INTO ARBEITEN VALUES (29346, 'p2', '', '15.12.2002');
INSERT INTO ARBEITEN VALUES (2581, 'p3', 'Projektleiter', '15.10.2003');
INSERT INTO ARBEITEN VALUES (9031, 'p1', 'Gruppenleiter', '15.04.2004');
INSERT INTO ARBEITEN VALUES (28559, 'p1', '', '01.08.2003');
INSERT INTO ARBEITEN VALUES (28559, 'p2', 'Sachbearbeiter', '01.02.2004');
INSERT INTO ARBEITEN VALUES (9031, 'p3', 'Sachbearbeiter', '15.11.2003');
INSERT INTO ARBEITEN VALUES (29346, 'p1', 'Sachbearbeiter', '01.04.2004');

/*
DROP TABLE ABTEILUNG;
DROP TABLE PROJEKT;
DROP TABLE ARBEITEN;
DROP TABLE MITARBEITER;
*/
Tabelle ARBEITEN
m_nr pr_nr aufgabe einst dat
10102 p1 Projektleiter 01.10.2003
10102 p3 Gruppenleiter 01.01.2004
25348 p2 Sachbearbeiter 15.02.2003
18316 p2 01.06.2004
29346 p2 15.12.2002
2581 p3 Projektleiter 15.10.2003
9031 p1 Gruppenleiter 15.04.2004
28559 p1 01.08.2003
28559 p2 Sachbearbeiter 01.02.2004
9031 p3 Sachbearbeiter 15.11.2003
29346 p1 Sachbearbeiter 01.04.2004
Tabelle MITARBEITER
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
Tabelle ABTEILUNG
abt_nr abt_name stadt
a1 Beratung Muenchen
a2 Diagnose Muenchen
a3 Freigabe Stuttgart
Tabelle PROJEKT (Mittel sind hier in Euro angegeben)
pr_nr pr_name mittel
p1 Apollo 120000
p2 Gemini 95000
p3 Merkur 186500
Fallstudie Firma - Aufgaben
  1. Machen Sie sich zunächst einmal mit den beschriebenen Tabellen vertraut.

    Überlegen Sie sich, welche Zusammenhänge (vermutlich) zwischen den einzelnen Tabellen bestehen und über welche Spalten diese abgebildet werden könnten.

    Welche Spalte(n) könnte(n) jeweils 1 Zeile identifizieren?

  2. Formulieren Sie bitte zur Beantwortung der folgenden einfachen Fragestellungen jeweils passende SELECT -Anweisungen. Diese Aufgaben sollen Sie mit der beschriebenen Situation langsam vertraut machen ...

    1. Finden Sie die Namen und die Nummern aller Abteilungen, die ihren Sitz in Muenchen haben.
      SELECT ABT_NR, ABT_NAME
      FROM ABTEILUNG
      WHERE stadt = 'Muenchen'
    2. Nennen Sie die Namen und Vornamen aller Mitarbeiter, deren Mitarbeiternummer nicht kleiner als 15000 ist.
      SELECT M_NAME, M_VORNAME
      FROM MITARBEITER
      WHERE M_NR >= 15000
    3. Finden Sie alle Projekte (Alle Angaben), deren Finanzmittel mehr als 150000 $ betragen; der aktuelle Kurs liege bei 1,09 Dollar pro Euro (die Werte in der Tabelle PROJEKT sind Euro-Angaben)
      SELECT P.*, 1.09 * MITTEL "Mittel in Dollar"
      FROM PROJEKT P
      WHERE MITTEL* 1.09 > 150000
    4. Gesucht werden Mitarbeiternummer, Projektnummer und Aufgabe der Mitarbeiter, die im Projekt p2 Sachbearbeiter sind.
      SELECT M_NR, PR_NR, AUFGABE
      FROM ARBEITEN
      WHERE AUFGABE = 'Sachbearbeiter' AND PR_NR = 'p2'
    5. Gesucht wird die Mitarbeiternummer der Mitarbeiter, die entweder im Projekt p1 oder p2 (oder in beiden) arbeiten.
      SELECT M_NR
      FROM ARBEITEN
      WHERE PR_NR IN ('p1', 'p2')
    6. Nennen Sie Mitarbeiternummer und Nachnamen der Mitarbeiter, die nicht der Abteilung a2 zugeordnet sind.
      SELECT M_NR, M_NAME
      FROM MITARBEITER
      WHERE ABT_NR <> 'a2'
    7. Finden Sie alle Mitarbeiter (alle Angaben), deren Mitarbeiternummer weder 10102 noch 9031 ist.
      SELECT *
      FROM MITARBEITER
      WHERE M_NR NOT IN (10102, 9031)
    8. Nennen Sie die Mitarbeiternummer aller Mitarbeiter, die Projektleiter sind und vor oder nach 2003 eingestellt wurden.
      SELECT M_NR
      FROM MITARBEITER JOIN ARBEITEN USING(M_NR)
      WHERE AUFGABE = 'Projektleiter'
      AND TO_CHAR(EINST_DAT, 'YYYY') <> '2003'
    9. Finden Sie die Mitarbeiter- und Projektnummer aller Mitarbeiter, die im Projekt p1 arbeiten und deren Aufgabe (noch) nicht festgelegt wurde.
      SELECT M_NR, PR_NR
      FROM ARBEITEN
      WHERE PR_NR = 'p1' AND AUFGABE IS NULL
    10. Finden Sie Namen und Mitarbeiternummer aller Mitarbeiter, deren Name mit dem Buchstaben K beginnt.
      SELECT M_NR, M_NAME || ', ' || M_VORNAME
      FROM MITARBEITER
      WHERE M_NAME LIKE 'K%'
    11. Finden Sie Namen und Vornamen aller Mitarbeiter, deren Nachname nicht mit "er" endet.
      SELECT M_NAME
      FROM MITARBEITER
      WHERE M_NAME NOT LIKE '%er'
    12. Welche (unterschiedlichen) Aufgaben üben die Mitarbeiter der Firma aus?
      SELECT DISTINCT AUFGABE
      FROM ARBEITEN
      WHERE AUFGABE IS NOT NULL
  3. Formulieren Sie bitte zur Beantwortung der folgenden Fragestellungen jeweils passende SELECT-Anweisungen.
    1. Berechnen Sie die Summe der (finanziellen) Mittel aller Projekte.
      SELECT SUM(MITTEL)
      FROM PROJEKT
    2. Berechnen Sie den Durchschnitt der Mittel, die höher als 100.000 Euro sind.
      SELECT AVG(MITTEL)
      FROM PROJEKT
      WHERE MITTEL > 100000
    3. Finden Sie heraus, wie viele Mitarbeiter in jedem Projekt arbeiten. Neben der ermittelten Anzahl soll nur die Projektnummer angezeigt werden.
      SELECT PR_NR, COUNT(*) "Anzahl"
      FROM ARBEITEN
      GROUP BY PR_NR
    4. Welche Aufgaben werden von mehr als 2 Mitarbeitern ausgeübt?
      SELECT AUFGABE
      FROM ARBEITEN
      GROUP BY AUFGABE
      HAVING COUNT(AUFGABE) > 2
    5. Nennen Sie alle Projekte (Nr. und Name), mit denen weniger als 4 Mitarbeiter befasst sind.
      SELECT PR_NR, PR_NAME
      FROM ARBEITEN JOIN PROJEKT USING(PR_NR)
      GROUP BY PR_NR, PR_NAME
      HAVING COUNT(*) < 4
      Die korrekte Lösung um auch Projekte zu erhalten denen noch keine Mitarbeiter zugewiesen sind.
      SELECT PR_NR, PR_NAME
      FROM PROJEKT
      WHERE PR_NR NOT IN (SELECT PR_NR
                          FROM ARBEITEN
                          GROUP BY PR_NR
                          HAVING COUNT(*) >= 4)
    6. Nennen Sie Nachname und Abteilungsnummer aller Mitarbeiter, die im Oktober 2003 eingestellt wurden (d.h. in ein Projekt eingetreten sind).
      DISTINCT SELECT M_NAME, ABT_NR
      FROM ARBEITEN JOIN MITARBEITER USING(M_NR)
      WHERE TO_CHAR(EINST_DAT, 'Month YYYY')
      LIKE 'Oktober%2003'
    7. Finden Sie die (d.h. alle) Daten aller Mitarbeiter, die in Muenchen "arbeiten" (d.h. deren Abteilung den Standort Muenchen hat).
      SELECT M.*
      FROM ABTEILUNG A JOIN MITARBEITER M
      ON A.ABT_NR = M.ABT_NR
      WHERE STADT = 'Muenchen'
    8. Nennen Sie die Namen aller Mitarbeiter, die im Projekt Apollo arbeiten.
      SELECT M_NAME, M_VORNAME
      FROM MITARBEITER
      JOIN ARBEITEN USING(M_NR)
      JOIN PROJEKT USING(PR_NR)
      WHERE PR_NAME = 'Apollo'
    9. Nennen Sie Namen und Vornamen aller Mitarbeiter, die im Projekt p1 arbeiten und deren Aufgabe (noch) nicht festgelegt wurde..
      SELECT M_NAME, M_VORNAME
      FROM MITARBEITER
      JOIN ARBEITEN USING(M_NR)
      WHERE PR_NR = 'p1'
    10. Finden Sie die Mitarbeiternummer derjenigen Mitarbeiter, die der Abteilung a1 angehören oder vor 2003 in das Projekt eingetreten sind.
      SELECT DISTINCT M_NR
      FROM MITARBEITER
      JOIN ARBEITEN USING(M_NR)
      WHERE ABT_NR = 'a1'
      OR TO_CHAR(EINST_DAT, 'YYYY') < 2003
    11. Finden Sie die Städte, die sowohl Wohnorte der Mitarbeiter als auch Standorte der Abteilungen sind.
      SELECT DISTINCT STADT
      FROM MITARBEITER
      JOIN ABTEILUNG USING(ABT_NR)
      WHERE STADT = WOHNORT
    12. Finden Sie heraus, wieviel unterschiedliche Aufgaben in jedem Projekt ausgeübt werden.
      SELECT PR_NR, COUNT(DISTINCT AUFGABE)
      FROM ARBEITEN
      GROUP BY PR_NR
    13. Nennen Sie Namen und Vornamen aller Projektleiter, deren Abteilung den Standort Stuttgart hat.
      SELECT DISTINCT M_NAME, M_VORNAME
      FROM MITARBEITER
      JOIN ABTEILUNG USING(ABT_NR)
      JOIN ARBEITEN USING(M_NR)
      WHERE AUFGABE = 'Projektleiter'
      AND STADT = 'Stuttgart'
    14. Nennen Sie die Namen der Projekte, in denen Mitarbeiter arbeiten, die zur Abteilung Diagnose gehören.
      SELECT DISTINCT PR_NAME
      FROM PROJEKT
      JOIN ARBEITEN USING(PR_NR)
      JOIN MITARBEITER USING(M_NR)
      JOIN ABTEILUNG USING(ABT_NR)
      WHERE ABT_NAME = 'Diagnose'
    15. Finden Sie die Mitarbeiternummer des Projektleiters, der als letzter eingestellt wurde (d.h. in ein Projekt eingetreten ist).
      SELECT M_NR
      FROM ARBEITEN
      WHERE AUFGABE = 'Projektleiter'
      AND EINST_DAT = (SELECT MAX(EINST_DAT)
      		 FROM ARBEITEN A
      		 WHERE AUFGABE = 'Projektleiter')
    16. Nennen Sie die Aufgabe(n) des Mitarbeiters, der die kleinste Mitarbeiternummer hat.
      SELECT DISTINCT AUFGABE, M_NR
      FROM ARBEITEN
      WHERE M_NR = (SELECT MIN(M_NR)
      	      FROM ARBEITEN)
    17. Nennen Sie die Nummern aller Projekte, in welchen Mitarbeiter arbeiten, deren Mitarbeiternummer 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')
  4. Formulieren Sie bitte zur Beantwortung der folgenden Fragestellungen jeweils geeigenete SELECT-Anweisungen
    1. Welcher(r) Mitarbeiter (Mitarbeiternummer und Namen) sind bzw. ist als erste(r) überhaupt in irgendein Projekt eingetreten?
      SELECT M_NR, M_NAME, M_VORNAME
      FROM MITARBEITER JOIN ARBEITEN USING(M_NR)
      WHERE EINST_DAT = (SELECT MIN(EINST_DAT)
                         FROM ARBEITEN)
    2. Welche Projektnummer und welchen Namen hat das bzw. haben die Projekt(e), an denen die meisten Mitarbeiter arbeiten?
      SELECT PR_NR, PR_NAME
      FROM PROJEKT JOIN (SELECT PR_NR, COUNT(*) Anzahl
                         FROM ARBEITEN
                         GROUP BY PR_NR
                         HAVING COUNT(*) = (SELECT MAX(COUNT(*))
                                            FROM ARBEITEN
                                            GROUP BY PR_NR)) USING(PR_NR)
    3. Welche Mitarbeiternummer und welche Namen haben die Mitarbeiter der Abteilungen(en) mit den wenigsten Mitarbeitern? Geben Sie neben der Abteilungsnummer auch noch den Namen der Abteilung(en) mit an.
      CREATE OR REPLACE VIEW V_MITARB_ANZ_PRO_ABT AS
      SELECT ABT_NR, COUNT(*) Anzahl
      FROM MITARBEITER
      GROUP BY ABT_NR;
      
      CREATE OR REPLACE VIEW V_MIN_MITARB AS
      SELECT MIN(Anzahl) MinAnzahl
      FROM V_MITARB_ANZ_PRO_ABT
      
      SELECT M_NR, M_NAME, M_VORNAME, ABT_NR, ABT_NAME
      FROM MITARBEITER JOIN ABTEILUNG USING(ABT_NR)
      WHERE ABT_NR IN (SELECT ABT_NR
                       FROM V_MITARB_ANZ_PRO_ABT JOIN V_MIN_MITARB
                       ON ANZAHL= MINANZAHL)
    4. Welche Mitarbeiter (Mitarbeiternummer, Namen und Wohnort) wohnen in dem Ort, an dem auch ihre Abteilung ihren Standort hat?
      SELECT M_NR, M_NAME, M_VORNAME, WOHNORT
      FROM MITARBEITER JOIN ABTEILUNG USING(ABT_NR)
      WHERE WOHNORT = STADT
    5. Welche Mitarbeiter (Mitarbeiternummer, Mitarbeiternamen und Abteilungsname) arbeiten nur in 1 Projekt?
      SELECT M_NR, M_NAME, M_VORNAME, ABT_NR, ABT_NAME
      FROM ABTEILUNG JOIN MITARBEITER USING(ABT_NR)
      WHERE M_NR IN (SELECT M_NR
                     FROM ARBEITEN
                     GROUP BY M_NR
                     HAVING COUNT(*) = 1)
    6. Finden Sie die Abteilungsnummer(n) und Name(n) der Abteilung(en) mit den meisten Mitarbeitern.
      SELECT DISTINCT ABT_NR, ABT_NAME
      FROM MITARBEITER JOIN ABTEILUNG USING (ABT_NR)
      WHERE ABT_NR IN (SELECT ABT_NR
                       FROM MITARBEITER
                       GROUP BY ABT_NR
                       HAVING COUNT(*) = (SELECT MAX(COUNT(*))
                                          FROM MITARBEITER
                                          GROUP BY ABT_NR))
    7. Finden Sie die Städte, die zwar Standorte von Abteilungen, aber nicht Wohnorte der Mitarbeiter sind.
      SELECT STADT
      FROM ABTEILUNG
      MINUS
      SELECT WOHNORT
      FROM MITARBEITER
    8. Aus welcher bzw. welchen Abteilung(en) (Abteilungsnummer und Name) werden am häufigsten Mitarbeiter in den Projekten eingesetzt?
      SELECT ABT_NR, ABT_NAME
      FROM ABTEILUNG JOIN (SELECT ABT_NR
                           FROM MITARBEITER JOIN ARBEITEN USING(M_NR)
                           GROUP BY ABT_NR
                           HAVING COUNT(*) = (SELECT MAX(COUNT(*))
                                              FROM MITARBEITER
                                              JOIN ARBEITEN USING(M_NR)
                                              GROUP BY ABT_NR))
                                              USING(ABT_NR)
    9. Finden Sie die Projektnummer(n) und den bzw. die Namen des bzw. der Projekt(e), in dem bzw. denen weniger als 2 Sachbearbeiter eingesetzt sind.
      SELECT PR_NR, PR_NAME
      FROM PROJEKT JOIN ARBEITEN USING(PR_NR)
      WHERE AUFGABE = 'Sachbearbeiter'
      GROUP BY PR_NR, PR_NAME
      HAVING COUNT(*) = (SELECT MIN(COUNT(*))
                         FROM ARBEITEN
                         WHERE AUFGABE = 'Sachbearbeiter'
                         GROUP BY PR_NR)