SELECT - Schritt für Schritt

Der SQL-Befehl zum Abfragen von Daten aus einer Datenbank ist sehr mächtig und kann daher ganz schön komplex werden. Daher versuche ich hier Ihnen eine kleine Schritt-für-Schritt-Hilfestellung zum Aufbau bzw. zum Formulieren eines SELECT-Befehls zu geben. Es wird Ihnen evtl. leichter falen, wenn Sie die folgenden Fragen nach einander beantworten und Ihren SELECT-Befehl dabei Schritt für Schritt aufbauen/ergänzen:

  1. Welche Daten(-Felder) benötigen Sie?
  2. Zu allererst müssen Sie wissen und, wenn Sie es nicht wissen, suchen, in welche Datenfeldern die von Ihnen benötigte Information in der Datenbank gespeichert wird. In diesem Beispiel möchten wir eine einfache Statistik über die Anzahl von einem Verkäufer betreuten Kunden fahren. Die Verkäufernummer, der Verkäufername und die Kundennummer müssten dazu ausreichend sein.

    SELECT vnum, vname, knum
    ;
  3. In welchen Tabellen stehen die benötigten Daten?
  4. Die Verkäufernummer und der Verkäufername stehen in der Verkäufertabelle tverkauf und für die Kundennummer ist die Kundentabelle wahrscheinlich am bessten.

    SELECT a.vnum, a.vname, b.knum
    FROM tverkauf a, tkunden b
    ;
  5. In welcher Beziehung stehen die Tabellen zu einander und wie können Sie verknüpft werden?
  6. Ünber die zwei hier verwendeten Tabellen wissen wir folgendes:
    Nicht jeder Verkäufer hat einen Kunden, daher müssen die Daten aus den Tabellen so zusammengebracht werden, dass bei der Tabellenverknüpfung kein Verkäufer ausgelassen wird: wir brauchen alle Datensätze aus der Tabelle tverkauf und suchen dazu passende Daten aus der Tabelle tkunden, wenn welche da sind --> LEFT JOIN
    In der Kundentabelle ist zusätzlich die Verkäufernummer des betreuenden verkäufers gespeichert, da dies auch der Schlüssel der anderen Tabelle ist, können die Daten über die Verkäufernummer verknüpft werden --> a.vnum = b.vnum

    SQL92::
    SELECT a.vnum, a.vname, b.knum
    FROM tverkauf a LEFT JOIN tkunden b ON a.vnum=b.vnum
    ;
    Standard-SQL::
    SELECT a.vnum, a.vname, b.knum
    FROM tverkauf a, OUTER tkunden b
    WHERE a.vnum=b.vnum
    ;

    Wenn das LEFT JOIN oder das OUTER weggelassen wird, dann werden nur Verkäufer ausgegeben, die auch einen korrespondieren Datensatz in der Kundetabelle haben, daher keine Verkäufer ohne Kunden.
    Wenn das Verknüpfungskriterium a.vnum=b.vnum weggelassen wird, dann wird ein sog. kartesisches Produkt erzeugt - die Kombination aller Verkäufer mit allen Kunden, was in unserem Fall einen ziemlichen Datenmüll ergeben würde.

  7. Sollen alle Daten ausgegeben werden, oder kann man bzw. sollen sie einschränkt werden?
  8. Sagen wir mal, dass uns nur die Verkäufer in Berlin interessieren:

    SQL92::
    SELECT a.vnum, a.vname, b.knum
    FROM tverkauf a LEFT JOIN tkunden b ON a.vnum=b.vnum
    WHERE a.stadt='Berlin'
    ;
    Standard-SQL::
    SELECT a.vnum, a.vname, b.knum
    FROM tverkauf a, OUTER tkunden b
    WHERE a.vnum=b.vnum
    AND a.stadt='Berlin'
    ;
  9. Werden Detailinformationen bzw. einzelne Daten benötigt oder wird eine Statistik/Gruppierung/Verdichtung benötigt?
  10. Da wir wissen wollen, wie viel Kunden von einem Verkäufer betreut werden, müssen wie alle Kunden pro Verkäufer zählen --> COUNT.
    Dies bedeutet, dass wir die Daten hier Aggregieren bzw. Gruppieren müssen --> GROUP BY

    SQL92::
    SELECT a.vnum, a.vname, COUNT(DISTINCT b.knum) AS anzahl
    FROM tverkauf a LEFT JOIN tkunden b ON a.vnum=b.vnum
    WHERE a.stadt='Berlin'
    GROUP BY vnum, vname
    ;
    Standard-SQL::
    SELECT a.vnum, a.vname, COUNT(*) AS anzahl
    FROM tverkauf a, OUTER tkunden b
    WHERE a.vnum=b.vnum
    AND a.stadt='Berlin'
    GROUP BY vnum, vname
    ;
  11. Soll die gebildete Statistik/Gruppierung/Verdichtung noch weiter bereinigt werden?
  12. Nehmen wir an, dass wir auf der Suche nach schwarzen Schafen unter den Verkäufern sind und Verkäufer mit Vielen Kunden von voirn herein nicht betrachten wollen. Dann müssen wie aus den Ergebnissen der Kundenzählung zu allen verkäufern nur die ausselektieren, die uns interessieren. In diesem beispiel, wollen wir alle Verkäufe nicht betrachten, wie 100 und mehr Kunden haben:

    SELECT a.vnum, a.vname, COUNT(DISTINCT b.knum) AS anzahl
    FROM tverkauf a LEFT JOIN tkunden b ON a.vnum=b.vnum
    WHERE a.stadt='Berlin'
    GROUP BY vnum, vname
    HAVING COUNT(DISTINCT b.knum) 
    ;
  13. Wie sollen die Ergebnisse sortiert werden?
  14. Auf unserer Suche nach den "scharzen Schafen" wollen wir zuerst die Verkäufer sehen die weniger Kunden haben, daher soll das Ergebnis nach der Kundeanzahl aufsteigend sortiert werden:

    SELECT a.vnum, a.vname, COUNT(DISTINCT b.knum) AS anzahl
    FROM tverkauf a LEFT JOIN tkunden b ON a.vnum=b.vnum
    WHERE a.stadt='Berlin'
    GROUP BY vnum, vname
    HAVING COUNT(DISTINCT b.knum) ORDER BY anzahl ASC
    ;
  15. Möchten Sie die Anzahl der ausgegebenen Datensätze beschränken?
  16. Da wir unserem Verkaufs-Chef nur einige Mitarbeitergespräche zumuten wollen, begrenzen wir die Anzahl der Datensätze im Ergebnis auf 10:

    SQL92::
    SELECT a.vnum, a.vname, COUNT(DISTINCT b.knum) AS anzahl
    FROM tverkauf a LEFT JOIN tkunden b ON a.vnum=b.vnum
    WHERE a.stadt='Berlin'
    GROUP BY vnum, vname
    HAVING COUNT(DISTINCT b.knum) LIMIT 10
    ;
    Informix::
    SELECT FIRST 10 a.vnum, a.vname, COUNT(DISTINCT b.knum) AS anzahl
    FROM tverkauf a LEFT JOIN tkunden b ON a.vnum=b.vnum
    WHERE a.stadt='Berlin'
    GROUP BY vnum, vname
    HAVING COUNT(DISTINCT b.knum) 
    
  17. Sollen die Ergebnisse in eine, ggf. temporäre, Tabelle geschrieben werden?
  18. Wenn die so gebildeten Daten noch weiter verarbeitet werden sollen, z.B. in weiteren SELECT-Befehlen, dann können die Ergebnisse in eine (temporäre) Tabelle geschrieben werden. So will der besagte Verkaufschef vielleicht selbst entscheiden, wie viel Mitarbeitergespräche er führen will. Dann bauen wie die Datensatz-Anzahl-Begrenzung wieder aus und schreiben stattdesen die Daten in eine Tabelle:

    Temporäre Tabelle
    SELECT a.vnum, a.vname, COUNT(DISTINCT b.knum) AS anzahl
    FROM tverkauf a LEFT JOIN tkunden b ON a.vnum=b.vnum
    WHERE a.stadt='Berlin'
    GROUP BY vnum, vname
    HAVING COUNT(DISTINCT b.knum) INTO TEMP verkauf_score
    ;
    Reguläre, fest angelegte Tabelle (muss vorher mit CREATE TABLE angelegt sein)
    INSERT INTO verkauf_score
    SELECT a.vnum, a.vname, COUNT(DISTINCT b.knum) AS anzahl
    FROM tverkauf a LEFT JOIN tkunden b ON a.vnum=b.vnum
    WHERE a.stadt='Berlin'
    GROUP BY vnum, vname
    HAVING COUNT(DISTINCT b.knum) 
    
Categories: