Erläuterungen zu SQL-Grundlagen finden Sie in sql.htm.
Hier finden Sie kommentierte einfache Beispiele für SQL-Kommandos.
Inhalt
- Installation einer SQL-Datenbank
- Laden der Übungstabellen
- Einfache SQL-Kommandos anhand der Tabelle "Personen"
- Aggregatfunktionen anhand der Tabelle "Speisen"
- Joins anhand der Tabelle "Bestellung"
Installation einer SQL-Datenbank
Bitte verfahren Sie zur Installation Ihrer Datenbank, wie in der zur Datenbank gehörenden Dokumentation beschrieben ist.
Zu MySQL finden Sie für Windows eine kurze Installationsbeschreibung auch unter mysql.htm#InstallationUnterWindows und eine Anleitung zur Anlage einer Database und einer Tabelle unter mysql.htm#CreateDatabase.
Zu PostgreSQL finden Sie für Linux kurze Installationsbeschreibungen und eine Anleitung zur Anlage einer Database und einer Tabelle unter postgresql.htm.
Laden der Übungstabellen
Wenn Sie die folgenden SQL-Kommandos selbst ausprobieren wollen, müssen Sie vorher die drei Beispieltabellen "Personen", "Speisen" und "Bestellung" anlegen.
Bitte laden Sie dafür die Seite sql-commands.sql.htm in Ihren Webbrowser, markieren alles (im Microsoft Internet Explorer z.B. mit "Strg+A"), kopieren alles in den Zwischenspeicher (z.B. mit "Strg+C" oder "Strg+Einfg") und erstellen eine neue Datei "sql-commands.sql", in die Sie alles einfügen (z.B. mit "Strg+V" oder "Umschalt+Einfg").
Bei sehr vielen Datenbanken können Sie diese .sql-Datei an ein mit der Datenbank mitinstalliertes Hilfs- oder Administrationsprogramm übergeben und die enthaltenen SQL-Kommandos so alle in einem Durchgang ausführen (siehe z.B. unter "Ausführen" in mysql.htm).
Bei anderen Datenbanken benötigen Sie vielleicht spezielle Hilfs- oder Administrationsprogramme oder müssen eventuell die SQL-Kommandos einzeln ausführen.
Statt über Kommandozeilenprogramme können Sie die SQL-Kommandos natürlich auch über Datenbank-Tools ausführen, zum Beispiel mit
SQuirreL.
Einfache SQL-Kommandos anhand der Tabelle "Personen"
SELECT * FROM Personen
| id | Name | Abteilung | Tel | Plz | Ort |
| 1 | Gabi | Sekr | 100 | | |
| 2 | Tatiana | GF | 202 | | |
| 3 | Manfred | GF | 201 | | |
| 4 | Iris | MK | 401 | | |
| 5 | René | PM | 501 | | |
| 6 | Elena | MM | 301 | | |
| 7 | Aidar | MM | 301 | | |
| 8 | Oleg | MM | 301 | | |
| 9 | Andreas | Entw | 610 | 52525 | Heinsberg |
| 10 | Arthur | Entw | 612 | 52499 | Baesweiler |
| 11 | Gregor | Entw | 611 | 52351 | Düren |
| 12 | Michael | Entw | 616 | 50859 | Köln |
| 13 | Norbert | Entw | 614 | 52134 | Herzogenrath |
| 14 | Roland | Entw | 601 | 52134 | Herzogenrath |
| 15 | Stefan | Entw | 613 | 52062 | Aachen |
| 16 | Torsten | Entw | 601 | 52072 | Aachen |
| 17 | Werner | Entw | 615 | 52076 | Aachen |
| 18 | FAX | | 101 | | |
| 19 | Konferenzraum | | 700 | | |
|
|
"SELECT * FROM ..." zeigt den kompletten Inhalt der genannten Tabelle,
allerdings ist die Reihenfolge der Zeilen nicht unbedingt reproduzierbar.
Deshalb sollten normalerweise hinter "ORDER BY" eine oder mehrere Spaltentitel angegeben werden, nach denen sortiert wird, wie es die unteren beiden Beispiele zeigen.
Die untere linke Tabelle ist zuerst nach Abteilungsname sortiert und bei gleichem Abteilungsnamen in zweiter Priorität nach dem Namen.
Ähnlich die untere rechte Tabelle, aber hier ist der Abteilungsname in absteigender Reihenfolge sortiert ("DESC" = descent) und innerhalb der gleichen Abteilung der Name weiterhin in aufsteigender Reihenfolge.
|
SELECT * FROM Personen ORDER BY Abteilung, Name
| id | Name | Abteilung | Tel | Plz | Ort |
| 18 | FAX | | 101 | | |
| 19 | Konferenzraum | | 700 | | |
| 9 | Andreas | Entw | 610 | 52525 | Heinsberg |
| 10 | Arthur | Entw | 612 | 52499 | Baesweiler |
| 11 | Gregor | Entw | 611 | 52351 | Düren |
| 12 | Michael | Entw | 616 | 50859 | Köln |
| 13 | Norbert | Entw | 614 | 52134 | Herzogenrath |
| 14 | Roland | Entw | 601 | 52134 | Herzogenrath |
| 15 | Stefan | Entw | 613 | 52062 | Aachen |
| 16 | Torsten | Entw | 601 | 52072 | Aachen |
| 17 | Werner | Entw | 615 | 52076 | Aachen |
| 3 | Manfred | GF | 201 | | |
| 2 | Tatiana | GF | 202 | | |
| 4 | Iris | MK | 401 | | |
| 7 | Aidar | MM | 301 | | |
| 6 | Elena | MM | 301 | | |
| 8 | Oleg | MM | 301 | | |
| 5 | René | PM | 501 | | |
| 1 | Gabi | Sekr | 100 | | |
|
|
SELECT * FROM Personen ORDER BY Abteilung DESC, Name
| id | Name | Abteilung | Tel | Plz | Ort |
| 1 | Gabi | Sekr | 100 | | |
| 5 | René | PM | 501 | | |
| 7 | Aidar | MM | 301 | | |
| 6 | Elena | MM | 301 | | |
| 8 | Oleg | MM | 301 | | |
| 4 | Iris | MK | 401 | | |
| 3 | Manfred | GF | 201 | | |
| 2 | Tatiana | GF | 202 | | |
| 9 | Andreas | Entw | 610 | 52525 | Heinsberg |
| 10 | Arthur | Entw | 612 | 52499 | Baesweiler |
| 11 | Gregor | Entw | 611 | 52351 | Düren |
| 12 | Michael | Entw | 616 | 50859 | Köln |
| 13 | Norbert | Entw | 614 | 52134 | Herzogenrath |
| 14 | Roland | Entw | 601 | 52134 | Herzogenrath |
| 15 | Stefan | Entw | 613 | 52062 | Aachen |
| 16 | Torsten | Entw | 601 | 52072 | Aachen |
| 17 | Werner | Entw | 615 | 52076 | Aachen |
| 18 | FAX | | 101 | | |
| 19 | Konferenzraum | | 700 | | |
|
SELECT Name, Ort FROM Personen WHERE Ort = 'aaCHen'
| Name | Ort |
| Stefan | Aachen |
| Torsten | Aachen |
| Werner | Aachen |
|
|
Statt "SELECT *" (mit Stern) zeigt "SELECT ..., ..." (ohne Stern) nur die genannten Spalten.
Mit "WHERE" wird eine Bedingung definiert, welche einschränkt, welche Zeilen angezeigt werden sollen.
SQL-Kommandos sind normalerweise nicht Case-sensitiv, Groß-/Kleinschreibung spielt keine Rolle (deshalb wird 'Aachen' auch mit 'aaCHen' gefunden).
|
SELECT * FROM Personen WHERE Abteilung = 'Entw' AND (Ort = 'Düren' OR Ort = 'Köln')
| id | Name | Abteilung | Tel | Plz | Ort |
| 11 | Gregor | Entw | 611 | 52351 | Düren |
| 12 | Michael | Entw | 616 | 50859 | Köln |
|
|
Die "WHERE"-Bedingung kann mit einer Verknüpfung logischer Operationen gebildet werden (hier mit "AND" und "OR").
|
SELECT * FROM Personen WHERE Abteilung <> 'Entw'
| id | Name | Abteilung | Tel | Plz | Ort |
| 1 | Gabi | Sekr | 100 | | |
| 2 | Tatiana | GF | 202 | | |
| 3 | Manfred | GF | 201 | | |
| 4 | Iris | MK | 401 | | |
| 5 | René | PM | 501 | | |
| 6 | Elena | MM | 301 | | |
| 7 | Aidar | MM | 301 | | |
| 8 | Oleg | MM | 301 | | |
|
|
Als Ungleichheitszeichen wird "<>" verwendet.
Einige Datenbanken verstehen zusätzlich auch das in Java übliche "!=", aber "<>" ist standardkonformer.
|
SELECT * FROM Personen WHERE Ort LIKE '%zog%'
| id | Name | Abteilung | Tel | Plz | Ort |
| 13 | Norbert | Entw | 614 | 52134 | Herzogenrath |
| 14 | Roland | Entw | 601 | 52134 | Herzogenrath |
|
|
Mit "LIKE" kann eine ungefähre Übereinstimmung gefordert werden.
Das Prozentzeichen ("%") dient dabei als Platzhalter für beliebig viele Zeichen.
|
SELECT * FROM Personen WHERE Tel LIKE '__0'
| id | Name | Abteilung | Tel | Plz | Ort |
| 1 | Gabi | Sekr | 100 | | |
| 9 | Andreas | Entw | 610 | 52525 | Heinsberg |
| 19 | Konferenzraum | | 700 | | |
|
|
Der Unterstrich ("_") dient in "LIKE"-Bedingungen als Platzhalter für genau ein Zeichen.
|
SELECT * FROM Personen WHERE Plz BETWEEN 52351 AND 52499
| id | Name | Abteilung | Tel | Plz | Ort |
| 10 | Arthur | Entw | 612 | 52499 | Baesweiler |
| 11 | Gregor | Entw | 611 | 52351 | Düren |
|
|
Mit "BETWEEN" kann ein nummerischer Wertebereich definiert werden.
|
SELECT * FROM Personen WHERE Abteilung IS NULL
| id | Name | Abteilung | Tel | Plz | Ort |
| 18 | FAX | | 101 | | |
| 19 | Konferenzraum | | 700 | | |
|
|
Mit "IS NULL" (bzw. mit "IS NOT NULL") werden leere Einträge abgefragt.
Achtung, es gibt zweierlei zu beachten:
1.) Leere Strings werden nicht einheitlich behandelt.
In einigen Datenbanken (z.B. Oracle) gibt es keine Leerstrings, ein leerer String würde als "NULL"-Wert gespeichert.
Aber in anderen Datenbanken (z.B. MySQL) gibt es sowohl "NULL"-Werte als auch leere Strings (mit Länge 0).
Um datenbankunabhängig zu programmieren, sollte mit beidem gerechnet werden.
2.) Anders als zum Beispiel bei Java kann es auch bei nummerischen Werten "NULL"-Werte geben.
Diese Werte bedeuten nicht die Zahl "0", sondern hier wurde nichts (oder explizit "NULL") eingetragen.
Bei der Umwandlung in einen nummerischen Wert ist deshalb eine Sonderbehandlung erforderlich (wenn die Spalte beim Anlegen der Tabelle nicht explizit als "NOT NULL" definiert wurde).
|
SELECT DISTINCT Abteilung FROM Personen WHERE Abteilung IS NOT NULL
| Abteilung |
| Sekr |
| GF |
| MK |
| PM |
| MM |
| Entw |
|
|
"DISTINCT" kummuliert mehrere Zeilen mit gleichen Spaltenwerten zu einer Zeile.
Man erhält also nur unterschiedliche Einträge, es gibt keine doppelten Einträge.
Hier im Beispiel sind die vielen Zeilen zum Beispiel zur Abteilung "Entw" zu einer Zeile zusammengefasst.
|
SELECT COUNT(*) FROM Personen WHERE Abteilung = 'Entw'
|
|
|
"COUNT(*)" zählt die Zahl der Zeilen, die die Bedingung erfüllen.
Ohne WHERE-Bedingung würde gezählt, wie viele Zeilen die Tabelle beinhaltet.
Allerdings sind solche Zahlen mit Vorsicht zu gebrauchen, da wenige Sekunden später vielleicht eine andere Anwendung eine zusätzliche Zeile hinzugefügt oder eine andere entfernt haben könnte.
|
SELECT Abteilung, COUNT(*) "Anzahl Personen pro Abteilung" FROM Personen GROUP BY Abteilung
| Abteilung | Anzahl Personen pro Abteilung |
| | 2 |
| Entw | 9 |
| GF | 2 |
| MK | 1 |
| MM | 3 |
| PM | 1 |
| Sekr | 1 |
|
|
"GROUP BY" gruppiert die Ergebniszeilen.
Ähnlich wie bei DISTINCT werden Zeilen mit gleichem Gruppierungswert zu einer Zeile zusammengefasst.
Bei "GROUP BY"-Kommandos machen hinter "SELECT" nur Tabellenspalten Sinn,
die entweder in der Gruppierungsbedingung enthalten sind (im Beispiel die Spalte "Abteilung")
oder Aggregatfunktionen (im Beispiel "COUNT(*)").
Hier im Beispiel gibt "COUNT(*)" an, wie viele Zeilen pro Gruppierung zusammengefasst wurden, was gleichbedeutend ist mit der Anzahl Personen pro Abteilung.
Wie das Beispiel zeigt, kann die Spaltenüberschrift durch einen direkt nach dem Spaltennamen (bzw. der Aggregatfunktion)
folgenden in doppelten Hochkommas ("Gänsefüsschen") eingeschlossenen Text ("...") ersetzt werden,
der dann als Spaltentitel gilt, wodurch die Verständlichkeit erhöht werden kann. Leider weicht die Syntax zur Spaltentitelübersetzung bei einigen Datenbanken etwas von der gezeigten ab.
|
SELECT Abteilung, COUNT(*) FROM Personen GROUP BY Abteilung HAVING COUNT(*) >= 3
| Abteilung | COUNT(*) |
| Entw | 9 |
| MM | 3 |
|
|
Die mit "GROUP BY" ermittelte Menge an Zeilen kann eingeschränkt werden durch eine "HAVING"-Bedingung.
|
Aggregatfunktionen anhand der Tabelle "Speisen"
SELECT * FROM Speisen ORDER BY id
| id | Gericht | Preis | Zutaten |
| 101 | Pizza Diabolo | 5.5 | Teufelsohren |
| 102 | Pizza Vulkano | 6 | Teig, Käse, Vesuvtomaten |
| 103 | Pizza Feuro | 6.5 | Pepperoni |
| 104 | Lasagno | 6 | Nudeln, Hackfleisch |
| 105 | Salat Eskimo | 4.5 | Eiswürfel |
|
|
Die Tabelle "Speisen" ist unsere zweite Beispieltabelle.
Die beiden Tabellen "Personen" und "Speisen" werden später über die Tabelle "Bestellung" verknüpft.
|
SELECT MIN(PREIS), MAX(PREIS), AVG(PREIS), SUM(PREIS), COUNT(PREIS) FROM Speisen
| MIN(PREIS) | MAX(PREIS) | AVG(PREIS) | SUM(PREIS) | COUNT(PREIS) |
| 4.5 | 6.5 | 5.7 | 28.5 | 5 |
|
|
"MIN()", "MAX()", "AVG()", "SUM()" und "COUNT()" sind sogenannte Aggregatfunktionen.
Sie fassen Werte aus mehreren Zeilen zu einem Wert zusammen.
|
Joins anhand der Tabelle "Bestellung"
SELECT * FROM Bestellung ORDER BY id
| id | id_Kunde | id_Speise |
| 1 | 9 | 105 |
| 2 | 11 | 103 |
| 3 | 12 | 103 |
| 4 | 14 | 103 |
| 5 | 15 | 101 |
| 6 | 15 | 102 |
| 7 | 15 | 103 |
| 8 | 16 | 104 |
| 9 | 17 | 103 |
|
|
Die Mitarbeiter einer Firma bestellen Gerichte beim Italiener.
Da die Kundendaten bereits aus früheren und für zukünftige Bestellungen gesondert erfasst wurden und die Speisen natürlich ebenfalls in einer Tabelle abgelegt sind,
genügt für die Aufnahme der Bestellung eine Tabelle, die lediglich Verweise auf die Kunden und Speisen enthält.
"id_Kunde" und "id_Speise" sind sogenannte "Foreign Keys" (Fremdschlüssel), da sie Werte enthalten,
die in einer anderen Tabelle als "Primary Key" (Primärschlüssel) definiert sind und so eindeutig Zeilen in der anderen Tabelle spezifizieren.
"id_Kunde" enthält nur "id"-Werte aus der Tabelle "Personen" und
"id_Speise" enthält nur "id"-Werte aus der Tabelle "Speisen".
Die Tabelle ist datenbanktechnisch so korrekt und enthält keinerlei redundanten Daten,
allerdings ist sie für den Menschen so schwer verständlich, weshalb wir die Darstellung erweitern wollen.
Die untere Tabelle zeigt einen Join dreier Tabellen, der eine korrekte Verknüpfung zwischen den drei Tabellen bildet,
allerdings sehr unübersichtlich, da er einfach alle Spalten anzeigt.
|
SELECT * FROM Bestellung, Personen, Speisen
WHERE id_Kunde = Personen.id AND id_Speise = Speisen.id
| id | id_Kunde | id_Speise | id | Name | Abteilung | Tel | Plz | Ort | id | Gericht | Preis | Zutaten |
| 1 | 9 | 105 | 9 | Andreas | Entw | 610 | 52525 | Heinsberg | 105 | Salat Eskimo | 4.5 | Eiswürfel |
| 2 | 11 | 103 | 11 | Gregor | Entw | 611 | 52351 | Düren | 103 | Pizza Feuro | 6.5 | Pepperoni |
| 3 | 12 | 103 | 12 | Michael | Entw | 616 | 50859 | Köln | 103 | Pizza Feuro | 6.5 | Pepperoni |
| 4 | 14 | 103 | 14 | Roland | Entw | 601 | 52134 | Herzogenrath | 103 | Pizza Feuro | 6.5 | Pepperoni |
| 5 | 15 | 101 | 15 | Stefan | Entw | 613 | 52062 | Aachen | 101 | Pizza Diabolo | 5.5 | Teufelsohren |
| 6 | 15 | 102 | 15 | Stefan | Entw | 613 | 52062 | Aachen | 102 | Pizza Vulkano | 6 | Teig, Käse, Vesuvtomaten |
| 7 | 15 | 103 | 15 | Stefan | Entw | 613 | 52062 | Aachen | 103 | Pizza Feuro | 6.5 | Pepperoni |
| 8 | 16 | 104 | 16 | Torsten | Entw | 601 | 52072 | Aachen | 104 | Lasagno | 6 | Nudeln, Hackfleisch |
| 9 | 17 | 103 | 17 | Werner | Entw | 615 | 52076 | Aachen | 103 | Pizza Feuro | 6.5 | Pepperoni |
|
|
|
SELECT Name, Gericht, Preis
FROM Bestellung, Personen, Speisen
WHERE id_Kunde = Personen.id AND id_Speise = Speisen.id
ORDER BY Name
| Name | Gericht | Preis |
| Andreas | Salat Eskimo | 4.5 |
| Gregor | Pizza Feuro | 6.5 |
| Michael | Pizza Feuro | 6.5 |
| Roland | Pizza Feuro | 6.5 |
| Stefan | Pizza Diabolo | 5.5 |
| Stefan | Pizza Vulkano | 6 |
| Stefan | Pizza Feuro | 6.5 |
| Torsten | Lasagno | 6 |
| Werner | Pizza Feuro | 6.5 |
|
|
Anders als obige Tabelle zeigt die links abgebildete Tabelle nur die relevanten Spalten.
Ein Join kann zwei oder auch sehr viele Tabellen verknüpfen.
Wichtig:
Ein Join über n Tabellen benötigt n-1 Verknüpfungsbedingungen zwischen den Tabellen.
Für unsere drei Tabellen "Bestellung", "Personen" und "Speisen" benötigen wir die beiden Verknüpfungsbedingungen
"id_Kunde = Personen.id" und "id_Speise = Speisen.id".
Beachten:
Der Spaltenname "id" kommt in den beiden Tabellen "Personen" und "Speisen" vor und ist deshalb nicht eindeutig.
In allen nicht eindeutigen Fällen muss der Tabellenname durch einen Punkt abgetrennt vorangestellt werden (im Beispiel: "Personen.id" und "Speisen.id").
Der Einfachheit halber empfiehlt es sich, bei Joins den Tabellennamen immer voranzustellen.
|
SELECT Name, COUNT(*), SUM(Preis)
FROM Bestellung, Personen, Speisen
WHERE id_Kunde = Personen.id AND id_Speise = Speisen.id
GROUP BY Name ORDER BY Name
| Name | COUNT(*) | SUM(Preis) |
| Andreas | 1 | 4.5 |
| Gregor | 1 | 6.5 |
| Michael | 1 | 6.5 |
| Roland | 1 | 6.5 |
| Stefan | 3 | 18 |
| Torsten | 1 | 6 |
| Werner | 1 | 6.5 |
|
|
Dieser Join ermittelt, wer wie viele Gerichte bestellt hat und wie viel jeder einzelne bezahlen muss.
|
SELECT Gericht, COUNT(*), SUM(Preis)
FROM Bestellung, Speisen
WHERE id_Speise = Speisen.id
GROUP BY Gericht ORDER BY Gericht
| Gericht | COUNT(*) | SUM(Preis) |
| Lasagno | 1 | 6 |
| Pizza Diabolo | 1 | 5.5 |
| Pizza Feuro | 5 | 32.5 |
| Pizza Vulkano | 1 | 6 |
| Salat Eskimo | 1 | 4.5 |
|
|
Dieser Join ermittelt für den Pizzabäcker, weches Gericht wie oft geliefert werden muss.
|
Weitere Themen: andere TechDocs
| SQL-Themen
| SQL-Grundlagen
| Vererbung und Polymorphie
| SQL mit Java
| O/R-M mit Hibernate
| MySQL
| PostgreSQL
© 1998-2007 Torsten Horn, Aachen