3. Grundlegende SQL-Befehle

SQL steht für Structured Query Language (strukturierte Anfragesprache). Es handelt sich dabei um die geläufigste Methode, mit Datenbankservern zu kommunizieren, und wird von fast allen Datenbanksystemen unterstützt. In diesem Kapitel erfahren Sie etwas über relationale Datenbanken und die wichtigsten SQL-Befehle.

3.1. Relationale Datenbanken

Wie bereits in Abschnitt 1.1 erwähnt, ist der Sinn und Zweck einer Datenbank das schnelle Speichern und Abrufen von Daten. Heutzutage sind die meisten Datenbanken relationale Datenbanken. Der Begriff relationale Datenbank hat zwar einen mathematischen Ursprung, bedeutet jedoch in der Praxis, dass alle in der Datenbank gespeicherten Daten in einer konstanten Struktur angeordnet sind.

In Abbildung 3.1 sehen Sie einen Datenbankserver mit Zugriff auf drei Datenbanken: demo, finance und test.

Abbildung 3.1: Datenbanken

Wenn Sie den Befehl psql finance eingeben, werden Sie mit der Datenbank finance verbunden. Informationen dazu haben Sie bereits in Kapitel 2 erhalten. In psql stellt der Befehl psql test eine Verbindung zur Datenbank test her. Wenn Sie eine Liste der verfügbaren Datenbanken sehen möchten, geben Sie psql -l ein. In der ersten Spalte sind die Datenbanknamen aufgeführt. Möglicherweise dürfen Sie jedoch nicht zu allen Datenbanken eine Verbindung aufbauen.

Was bedeuten die schwarzen Rechtecke in den Datenbanken? Dabei handelt es sich um Tabellen. Tabellen bilden die Grundlage von relationalen Datenbank-Managementsystemen (RDBMS). In ihnen sind die in der Datenbank gespeicherten Daten enthalten. Jede Tabelle hat einen Namen, der ihr von der Person, die die Tabelle erstellt hat, gegeben wurde.

Schauen wir uns die in Tabelle 3.1 abgebildete einzelne Tabelle mit dem Namen friend an. Hier können Sie sehen, wie Tabellen zum Speichern von Daten benutzt werden. Jeder Freund (friend) ist in einer eigenen Zeile in der Tabelle aufgeführt. Die Tabelle enthält folgende Informationen: Vorname (firstname), Nachname (lastname), Stadt ­(city), US-Bundesstaat (state) und Alter (age).1

Tabelle 3.1: Die Tabelle friend

FirstName

LastName

City

State

Age

Mike

Nichols

Tampa

FL

19

Cindy

Anderson

Denver

CO

23

Sam

Jackson

Allentown

PA

22

Jeder Eintrag für einen Freund hat eine eigene Zeile; jede Spalte enthält denselben Informationstyp. Diese Struktur macht relationale Datenbanken so erfolgreich. Damit können bestimmte Datenzeilen, Datenspalten oder einzelne Zellen ausgewählt werden. Sie könnten die gesamte Zeile für Mike, die gesamte Spalte für City oder eine bestimmte Zelle wie etwa Denver auswählen.

Für die Begriffe »Tabelle«, »Zeile« und »Spalte« gibt es Synonyme. »Tabelle« wird formal als Relation oder Klasse bezeichnet, »Zeile« als Datensatz oder Tupel und »Spalte« als Feld oder Attribut.

3.2. Tabellen erstellen

Erstellen wir eine eigene Tabelle mit dem Namen friend. In Abbildung 3.2 sehen Sie den entsprechenden psql-Befehl. Sie brauchen den Befehl nicht genauso einzugeben. Sie können alles klein schreiben oder in eine lange Zeile tippen, das Ergebnis ist dasselbe.

Abbildung 3.2: Anlegen der Tabelle friend

test=> CREATE TABLE friend (
test(>              firstname CHAR(15),
test(>              lastname  CHAR(20),
test(>              city      CHAR(15),
test(>              state     CHAR(2),
test(>              age       INTEGER
test(> );
CREATE

Betrachten wir die Anweisung von vorne nach hinten. Die Wörter CREATE TABLE haben für den Datenbankserver eine spezielle Bedeutung. Sie weisen darauf hin, dass die nächste Benutzeranfrage die Erzeugung einer Tabelle sein wird. Die meisten SQL-Anfragen können durch die ersten Wörter leicht identifiziert werden. Der Rest der Anfrage hat ein besonderes Format, das vom Datenbankserver verstanden wird. Groß-/Kleinschreibung und Abstände sind optional, das Format muss jedoch genau eingehalten werden. Sonst gibt der Datenbankserver eine Fehlermeldung aus wie etwa parser: parse error at or near "pencil", was bedeutet, dass der Datenbankserver in der Umgebung des Wortes pencil einen Fehler gefunden hat. In diesem Fall lesen Sie die Dokumentation zum Befehl und geben die Anfrage erneut im richtigen Format ein. Das Handbuch zu PostgreSQL finden Sie in Anhang D.

Der Befehl CREATE TABLE hat ein bestimmtes Format: Zunächst die beiden Wörter CREATE TABLE, gefolgt vom Tabellennamen, anschließend eine öffnende Klammer, gefolgt von einer Liste mit Spaltennamen und ihren Typen sowie einer schließenden Klammer. Der wichtige Teil der Anfrage befindet sich zwischen den Klammern. In Abbildung 3.2 sehen Sie fünf Zeilen. Die erste Zeile, firstname CHAR(15), stellt die erste Spalte der zu erstellenden Tabelle dar. Diese Spalte heißt firstname; der Text CHAR(15) gibt Datentyp und Länge der Spalte an. CHAR(15) heißt, dass die Spalte maximal 15 Zeichen enthalten kann. Die zweite Spalte heißt lastname und enthält maximal 20 Zeichen. Spalten vom Typ CHAR() enthalten so viele Zeichen wie angegeben. Vom Benutzer eingegebene Zeichenketten,2 die den Platz nicht ausfüllen, werden rechts mit Leerzeichen ergänzt. Ähnliches gilt für die Spalten city und state. Die Spalte age hat jedoch einen anderen Typ. Es ist keine CHAR()-Spalte, sondern eine INTEGER-Spalte, die ganze Zahlen statt Zeichen enthält. Auch wenn die Tabelle 5.000 Freunde enthielte, können Sie sicher sein, dass in der Spalte age keine Namen, sondern nur Zahlen erscheinen. Diese konsistente Struktur führt dazu, dass Datenbanken schnell und zuverlässig sind.

PostgreSQL unterstützt nicht nur die Spaltentypen CHAR() und INTEGER; allerdings verwenden wir in diesem Kapitel nur diese beiden. Die Abschnitte 4.1 und 9.2 gehen detailliert auf weitere Spaltentypen ein.

Erstellen Sie nun selbst einige Tabellen. Verwenden Sie zunächst nur Buchstaben für die Namen Ihrer Tabellen und Spalten. Benutzen Sie keine Zahlen, Satz- oder Leer­zeichen.

Mit dem Befehl \d können Sie sich Informationen zu einer speziellen Tabelle oder eine Liste aller Tabellennamen in der aktuellen Datenbank anzeigen lassen. Für Informationen über eine bestimmte Tabelle geben Sie \d gefolgt von dem Tabellennamen ein. Um zum Beispiel die Spaltennamen und -typen der Tabelle friend in psql zu sehen, geben Sie \d friend ein (Abbildung 3.3). Wenn Sie \d ohne Tabellennamen verwenden, sehen Sie eine Liste aller Tabellennamen in der Datenbank.

Abbildung 3.3: Beispiel mit \d

test=> \d friend
         Table "friend"
 Attribute |   Type   | Modifier 
-----------+----------+----------
 firstname | char(15) | 
 lastname  | char(20) | 
 city      | char(15) | 
 state     | char(2)  | 
 age       | integer  | 

3.3. Daten mit INSERT hinzufügen

Fahren wir damit fort, eine Tabelle zu erstellen, die genauso aussieht wie die Tabelle friend in Abbildung 3.1. Bisher haben wir die Tabelle zwar angelegt, aber sie enthält noch keine Freunde. Mit dem Befehl INSERT kann man Zeilen zu einer Tabelle hinzufügen. So wie auch der Befehl CREATE TABLE ein bestimmtes Format hat, muss auch INSERT einem Format folgen. Abbildung 3.4 zeigt dieses Format.

Abbildung 3.4: Mit INSERT Daten in friend einfügen

test=> INSERT INTO friend VALUES (
test(>                            'Mike', 
test(>                            'Nichols', 
test(>                            'Tampa',
test(>                            'FL',
test(>                            19
test(> );
INSERT 19053 1

Die Zeichenketten müssen in einfachen Anführungszeichen stehen. Doppelte Anführungszeichen funktionieren nicht. Leerzeichen und Groß-/Kleinschreibung sind optional, allerdings nicht zwischen einfachen Anführungszeichen. Dort wird der Text wörtlich genommen, so dass auch Groß-/Kleinschreibung in der Datenbank so gespeichert wird, wie Sie es eingeben. Wenn Sie zu viele Anführungszeichen eingeben, funktionieren die Backslash-Befehle möglicherweise irgendwann nicht mehr. Das Promptzeichen wechselt dann zu test'>. Beachten Sie das einfache Anführungszeichen vor dem Größer-als-Symbol. Geben Sie ein weiteres einfaches Anführungszeichen ein, um diesen Modus zu verlassen, verwenden Sie \r, um den Anfragepuffer zu löschen, und beginnen Sie von vorne. Beachten Sie auch, dass die Zahl 19 nicht in Anführungszeichen steht, da die Spalte nummerisch ist. Wenn Sie den Befehl INSERT verwenden, vergewissern Sie sich, dass die Daten mit dem übereinstimmen, was in den jeweiligen Spalten erwartet wird. Abbildung 3.5 zeigt die weiteren INSERT-Befehle, damit die Tabelle friend mit der in Tabelle 3.1 übereinstimmt.

Abbildung 3.5: Weitere INSERT-Befehle für friend

test=> INSERT INTO friend VALUES (
test(>                            'Cindy', 
test(>                            'Anderson', 
test(>                            'Denver',
test(>                            'CO',
test(>                            23
test(> );
INSERT 19054 1
test=> INSERT INTO friend VALUES (
test(>                            'Sam', 
test(>                            'Jackson', 
test(>                            'Allentown',
test(>                            'PA',
test(>                            22
test(> );
INSERT 19055 1

3.4. Daten mit SELECT anzeigen

Sie haben gerade gesehen, wie man Daten in der Datenbank speichert. Als Nächstes wollen wir die Daten abfragen. Erstaunlicherweise gibt es nur einen Befehl, mit dem Daten aus der Datenbank geholt werden können, und zwar den Befehl SELECT. Diesen Befehl haben Sie schon in Ihrer ersten Datenbankanfrage verwendet (siehe Abbildung 2.2). Wir werden ihn nun zur Anzeige der Zeilen in der Tabelle friend benutzen. Wie in Abbildung 3.6 dargestellt, erscheint die gesamte Anfrage in einer Zeile. Wenn wir später längere Anfragen verwenden, ist es einfacher, sie in mehrere Zeilen zu unterteilen.

Abbildung 3.6: Die erste SELECT-Anweisung

test=> SELECT * FROM friend;
    firstname    |       lastname       |      city       | state | age 
-----------------+----------------------+-----------------+-------+-----
 Mike            | Nichols              | Tampa           | FL    |  19
 Cindy           | Anderson             | Denver          | CO    |  23
 Sam             | Jackson              | Allentown       | PA    |  22
(3 rows)

Schauen wir uns dieses Beispiel genauer an. Zunächst haben wir das Wort SELECT, gefolgt von einem Stern (*), dann das Wort FROM, den Tabellennamen friend und schließlich ein Semikolon, um die Anfrage auszuführen. SELECT startet den Befehl. Der Befehl sagt der Datenbank, was als Nächstes folgt. Der * teilt dem Server mit, dass wir alle Spalten der Tabelle benötigen. FROM friend zeigt an, welche Tabelle wir sehen wollen. Somit haben wir gesagt, dass wir alle (*) Spalten der Tabelle friend sehen wollen. Diese werden dann auch angezeigt – dieselben Daten, die in Tabelle 3.1 dargestellt sind.

Der Befehl SELECT hat viele Varianten, von denen wir uns jetzt einige ansehen werden. Nehmen wir an, Sie wollten nur eine Spalte der Tabelle friend holen. Wahrscheinlich vermuten Sie nun schon richtig, dass der Stern (*) geändert werden muss. Wenn Sie ihn durch einen der Spaltennamen ersetzen, wird nur diese Spalte angezeigt. Versuchen Sie folgende Eingabe: SELECT city FROM friend. Die Spalte ist beliebig wählbar. Es ist sogar möglich, mehrere Spalten zu wählen, indem Sie die einzelnen Spaltennamen durch Komma trennen. Wenn Sie also zum Beispiel nur Vor- und Nachnamen sehen wollen, verwenden Sie SELECT firstname, lastname FROM friend. Probieren Sie einige weitere SELECT-Befehle aus, um damit vertraut zu werden.

Wenn Sie einen Namen angeben, der kein gültiger Spaltenname ist, wird eine Fehlermeldung ausgegeben, zum Beispiel: ERROR: attribute 'meinespalte' not found. Wenn Sie eine Tabelle angeben, die nicht existiert, wird zum Beispiel folgende Fehlermeldung angezeigt: Relation 'meinetabelle' does not exist. PostgreSQL verwendet in diesen Fehlermeldungen die formalen Begriffe Relation und Attribut.

3.5. Einzelne Zeilen mit WHERE auswählen

Gehen wir einen Schritt weiter mit dem Befehl SELECT. Im letzten Abschnitt haben Sie gesehen, wie man nur bestimmte Spalten aus einer Tabelle auswählt. Nun werden wir sehen, wie man nur bestimmte Zeilen auswählt. Dafür benötigen wir die WHERE-Klausel. Ohne WHERE-Klausel wird jede Zeile zurückgegeben.

Die WHERE-Klausel steht direkt hinter der FROM-Klausel. Mit der WHERE-Klausel geben Sie die Zeilen an, die ausgegeben werden sollen – wie in Abbildung 3.7 dargestellt. Diese Anfrage gibt die Zeilen aus, die eine age-Spalte mit dem Wert 23 haben. Abbildung 3.8 zeigt eine etwas komplexere Anfrage, die zwei Zeilen zurückgibt.

Abbildung 3.7: Die erste WHERE-Klausel

test=> SELECT * FROM friend WHERE age = 23;
    firstname    |       lastname       |      city       | state | age 
-----------------+----------------------+-----------------+-------+-----
 Cindy           | Anderson             | Denver          | CO    |  23
(1 row)

Abbildung 3.8: Etwas komplexere WHERE-Klausel

test=> SELECT * FROM friend WHERE age <= 22;
    firstname    |       lastname       |      city       | state | age 
-----------------+----------------------+-----------------+-------+-----
 Mike            | Nichols              | Tampa           | FL    |  19
 Sam             | Jackson              | Allentown       | PA    |  22
(2 rows)

Die Beschränkungen für Zeilen und Spalten können auch in einer einzigen Anfrage kombiniert werden. Somit können Sie jede einzelne Zelle oder einen Zellenblock auswählen (siehe die Abbildungen 3.9 und 3.10).

Abbildung 3.9: Eine einzelne Zelle

test=> SELECT lastname FROM friend WHERE age = 22;
       lastname       
----------------------
 Jackson             
(1 row)

Abbildung 3.10: Ein Zellenblock

test=> SELECT city, state FROM friend WHERE age => 21;
      city       | state  
-----------------+--------
 Denver          | CO    
 Allentown       | PA    
(2 rows)

Bisher haben wir nur für die Spalte age Vergleiche durchgeführt. Diese Spalte hat einen INTEGER-Wert. Die anderen Spalten haben CHAR()-Werte, so dass Sie die Vergleichswerte in einfache Anführungszeichen setzen müssen. Außerdem ist die Groß-/Kleinschreibung zu beachten (siehe Abbildung 3.11). Wenn Sie die Spalte firstname mit 'SAM' oder 'sam' angegeben hätten, würde als Ergebnis keine einzige Zeile zurückgegeben. Probieren Sie einige Vergleiche aus, bis Sie mit dieser Anweisung vertraut sind.

Abbildung 3.11: Vergleich von Zeichenkettenfeldern

test=> SELECT * FROM friend WHERE firstname = 'Sam';
    firstname    |       lastname       |      city       | state | age 
-----------------+----------------------+-----------------+-------+-----
 Sam             | Jackson              | Allentown       | PA    |  22
(1 row)

3.6. Daten mit DELETE löschen

Sie wissen jetzt, wie Daten zur Datenbank hinzugefügt werden; nun lernen Sie, wie Daten gelöscht werden. Das Löschen ist einfach. Mit dem Befehl DELETE können Sie einige oder alle Zeilen aus einer Tabelle schnell entfernen. Der Befehl DELETE FROM friend zum Beispiel löscht alle Zeilen aus der Tabelle friend. Der Befehl DELETE FROM friend WHERE age = 19 löscht nur die Zeilen, in denen die Spalte age den Wert 19 hat.

Machen Sie folgende Übung: Verwenden Sie INSERT, um eine Zeile in die Tabelle friend einzufügen; überprüfen Sie mit SELECT, ob die Zeile wirklich hinzugefügt wurde; dann löschen Sie die Zeile wieder mit DELETE. Somit können Sie alle Befehle üben, die Sie in den vorangegangenen Abschnitten gelernt haben. In Abbildung 3.12 finden Sie ein Beispiel.

Abbildung 3.12: Beispiel für DELETE

test=> SELECT * FROM friend;
    firstname    |       lastname       |      city       | state | age 
-----------------+----------------------+-----------------+-------+-----
 Mike            | Nichols              | Tampa           | FL    |  19
 Cindy           | Anderson             | Denver          | CO    |  23
 Sam             | Jackson              | Allentown       | PA    |  22
(3 rows)

test=> INSERT INTO friend VALUES ('Jim', 'Barnes', 'Ocean City','NJ', 25);
INSERT 19056 1
test=> SELECT * FROM friend;
    firstname    |       lastname       |      city       | state | age 
-----------------+----------------------+-----------------+-------+-----
 Mike            | Nichols              | Tampa           | FL    |  19
 Cindy           | Anderson             | Denver          | CO    |  23
 Sam             | Jackson              | Allentown       | PA    |  22
 Jim             | Barnes               | Ocean City      | NJ    |  25
(4 rows)

test=> DELETE FROM friend WHERE lastname = 'Barnes';
DELETE 1
test=> SELECT * FROM friend;
    firstname    |       lastname       |      city       | state | age 
-----------------+----------------------+-----------------+-------+-----
 Mike            | Nichols              | Tampa           | FL    |  19
 Cindy           | Anderson             | Denver          | CO    |  23
 Sam             | Jackson              | Allentown       | PA    |  22
(3 rows)

3.7. Daten mit UPDATE ändern

Wie können Daten geändert werden, die sich bereits in der Datenbank befinden? Mit DELETE können Sie eine Zeile löschen und mit INSERT eine neue hinzufügen. Diese Vorgehensweise ist jedoch nicht sehr effizient. Mit dem Befehl UPDATE können Sie Daten ändern, die sich bereits in der Datenbank befinden. Das Format ähnelt dem der bisher behandelten Befehle.

Betrachten wir wieder unsere Tabelle friend. Nehmen wir an, dass Mike Geburtstag gehabt hätte, so dass wir das Alter aktualisieren müssen. Das Beispiel in Abbildung 3.13 zeigt das Wort UPDATE, den Tabellennamen friend, gefolgt von SET, dem Spaltennamen, dem Gleichheitszeichen (=) und dem neuen Wert.

Abbildung 3.13: Das erste UPDATE

test=> UPDATE friend SET age = 20 WHERE firstname = 'Mike';
UPDATE 1
test=> SELECT * FROM friend;
    firstname    |       lastname       |      city       | state | age 
-----------------+----------------------+-----------------+-------+-----
 Cindy           | Anderson             | Denver          | CO    |  23
 Sam             | Jackson              | Allentown       | PA    |  22
 Mike            | Nichols              | Tampa           | FL    |  20
(3 rows)

Wie schon bei der DELETE-Anweisung gibt die WHERE-Klausel an, welche Zeilen durch die UPDATE-Anweisung betroffen sind. Ohne WHERE-Klausel würden alle Zeilen geändert.

Beachten Sie, dass die Zeile mit Mike an das Ende der Liste gerutscht ist. Im nächsten Abschnitt erfahren Sie, wie Sie die Reihenfolge der angezeigten Daten beeinflussen können.

3.8. Daten mit ORDER BY sortieren

Eine Anfrage mit SELECT zeigt die Zeilen in ungeordneter Reihenfolge an. Wenn die Zeilen in einer bestimmten Ordnung erscheinen sollen, müssen Sie die ORDER BY-Klausel am Ende der SELECT-Anweisung verwenden. In Abbildung 3.14 ist dargestellt, wie ORDER BY benutzt wird.

Abbildung 3.14: Die Verwendung von ORDER BY

test=> SELECT * FROM friend ORDER BY state;
    firstname    |       lastname       |      city       | state | age 
-----------------+----------------------+-----------------+-------+-----
 Cindy           | Anderson             | Denver          | CO    |  23
 Mike            | Nichols              | Tampa           | FL    |  20
 Sam             | Jackson              | Allentown       | PA    |  22
(3 rows)

SELECTDie Reihenfolge kann umgekehrt werden, wenn Sie wie in Abbildung 3.15 DESC hinzufügen. Wenn die Anfrage auch eine WHERE-Klausel verwendet, erscheint ORDER BY nach der WHERE-Klausel, wie in Abbildung 3.16 gezeigt.

Abbildung 3.15: Umgekehrte Reihenfolge bei ORDER BY

test=> SELECT * FROM friend ORDER BY age DESC;
    firstname    |       lastname       |      city       | state | age 
-----------------+----------------------+-----------------+-------+-----
 Cindy           | Anderson             | Denver          | CO    |  23
 Sam             | Jackson              | Allentown       | PA    |  22
 Mike            | Nichols              | Tampa           | FL    |  20
(3 rows)

Sie können nach mehreren Spalten sortieren, indem Sie mehrere durch Komma getrennte Spaltennamen angeben. Der Befehl sortiert dann nach der ersten angegebenen Spalte. Dieser Ansatz ist in unserem Beispiel nicht besonders sinnvoll, da alle Spaltenwerte gleich sind.

Abbildung 3.16: Umgekehrte Reihenfolge bei ORDER BY

test=> SELECT * FROM friend WHERE AGE >= 21 ORDER BY firstname;
    firstname    |       lastname       |      city       | state | age 
-----------------+----------------------+-----------------+-------+-----
 Cindy           | Anderson             | Denver          | CO    |  23
 Sam             | Jackson              | Allentown       | PA    |  22
(2 rows)

3.9. Tabellen löschen

Das Kapitel wäre nicht vollständig, wenn Sie nicht erführen, wie Tabellen gelöscht werden. Diese Aufgabe wird mit dem Befehl DROP TABLE ausgeführt. Der Befehl DROP TABLE friend zum Beispiel löscht die Tabelle friend.

Sowohl die Tabellenstruktur als auch die Tabellendaten werden gelöscht. Da wir jedoch das Beispiel friend auch im nächsten Kapitel verwenden wollen, sollten Sie diese Tabelle jetzt nicht löschen. Aber vergessen Sie nicht: Wenn Sie nur die Daten aus einer Tabelle löschen wollen, ohne die Tabellenstruktur zu entfernen, verwenden Sie den Befehl DELETE.

3.10. Zusammenfassung

In diesem Kapitel haben Sie die grundlegenden Datenbankoperationen kennen gelernt:

In diesem Kapitel wurden die Befehle in ihrer einfachsten Form dargestellt. Reale Anfragen sind jedoch weitaus komplexer. In den nächsten Kapiteln erfahren Sie, wie man diese einfachen Befehle zur Bewältigung auch sehr komplizierter Aufgaben einsetzen kann.

1 In einer realen Datenbank würde man nicht das Alter einer Person, sondern ihr Geburtsdatum speichern. Nach jedem Geburtstag muss sonst das Alter einer Person aktualisiert werden; es kann jedoch aus dem Geburtsdatum berechnet werden.

2 Eine Zeichenkette (engl. character string) ist eine Gruppe verketteter Zeichen.