Einfache SQL-Hilfe von Christoph Reeg
|
zurück |
SQL-Befehle
SELECT [DISTINCT | ALL] select_expression,... FROM tables ... [WHERE where_definition] [GROUP BY feld_name,...] [ORDER BY feld_name [ASC | DESC] ,...] [LIMIT [offset,] rows] Die kürzestmögliche SELECT-Anweisung lautet: SELECT * FROM table Es sollen z.B. alle Mitarbeiter ausgegeben werden: mysql> select * from Mitarbeiter; +-----+------+-------+----------------+------------+--------------+ | MNr | VNr | AbtNr | Name | GebDat | Telefon | +-----+------+-------+----------------+------------+--------------+ | 1 | NULL | 3 | Christoph Reeg | 1979-05-13 | NULL | | 2 | 1 | 1 | junetz.de | 1998-03-05 | 069/764758 | | 3 | 1 | 1 | Uli | NULL | NULL | | 4 | 3 | 1 | JCP | NULL | 069/764758 | | 5 | 1 | 2 | Maier | NULL | 06196/671797 | | 6 | 5 | 2 | Meier | NULL | 069/97640232 | +-----+------+-------+----------------+------------+--------------+ 6 rows in set (0.00 sec) mysql> DISTINCT und ALL sind exklusive, optionale Parameter; soll heißen, es kann immer nur einer, muß aber keiner benutzt werden. DISTINCT sorgt dafür, daß jede identische Zeile nur einmal ausgegeben wird. Mit ALL werden die sich wiederholenden Werte auch mehrmals ausgegeben. Ohne Parameter verhält sich das DBMS normalerweise, als ob man ALL angeben würde. Es sollen alle Telefonnummern aus der Mitarbeiter-Tabelle ausgeben werden: mysql> SELECT Telefon from Mitarbeiter; +--------------+ | Telefon | +--------------+ | NULL | | 069/764758 | | NULL | | 069/764758 | | 06196/671797 | | 069/97640232 | +--------------+ 6 rows in set (0.01 sec) mysql> SELECT ALL Telefon from Mitarbeiter; +--------------+ | Telefon | +--------------+ | NULL | | 069/764758 | | NULL | | 069/764758 | | 06196/671797 | | 069/97640232 | +--------------+ 6 rows in set (0.00 sec) mysql> SELECT DISTINCT Telefon from Mitarbeiter; +--------------+ | Telefon | +--------------+ | NULL | | 06196/671797 | | 069/764758 | | 069/97640232 | +--------------+ 4 rows in set (0.05 sec) mysql>
Als Beispiel alle Mitarbeiter, nach Namen sortiert: mysql> SELECT * from Mitarbeiter ORDER BY Name; +-----+------+-------+----------------+------------+--------------+ | MNr | VNr | AbtNr | Name | GebDat | Telefon | +-----+------+-------+----------------+------------+--------------+ | 1 | NULL | 3 | Christoph Reeg | 1979-05-13 | NULL | | 4 | 3 | 1 | JCP | NULL | 069/764758 | | 2 | 1 | 1 | junetz.de | 1998-03-05 | 069/764758 | | 5 | 1 | 2 | Maier | NULL | 06196/671797 | | 6 | 5 | 2 | Meier | NULL | 069/97640232 | | 3 | 1 | 1 | Uli | NULL | NULL | +-----+------+-------+----------------+------------+--------------+ 6 rows in set (0.00 sec) mysql> SELECT * from Mitarbeiter ORDER BY Name ASC; +-----+------+-------+----------------+------------+--------------+ | MNr | VNr | AbtNr | Name | GebDat | Telefon | +-----+------+-------+----------------+------------+--------------+ | 1 | NULL | 3 | Christoph Reeg | 1979-05-13 | NULL | | 4 | 3 | 1 | JCP | NULL | 069/764758 | | 2 | 1 | 1 | junetz.de | 1998-03-05 | 069/764758 | | 5 | 1 | 2 | Maier | NULL | 06196/671797 | | 6 | 5 | 2 | Meier | NULL | 069/97640232 | | 3 | 1 | 1 | Uli | NULL | NULL | +-----+------+-------+----------------+------------+--------------+ 6 rows in set (0.01 sec) mysql> SELECT * from Mitarbeiter ORDER BY Name DESC; +-----+------+-------+----------------+------------+--------------+ | MNr | VNr | AbtNr | Name | GebDat | Telefon | +-----+------+-------+----------------+------------+--------------+ | 3 | 1 | 1 | Uli | NULL | NULL | | 6 | 5 | 2 | Meier | NULL | 069/97640232 | | 5 | 1 | 2 | Maier | NULL | 06196/671797 | | 2 | 1 | 1 | junetz.de | 1998-03-05 | 069/764758 | | 4 | 3 | 1 | JCP | NULL | 069/764758 | | 1 | NULL | 3 | Christoph Reeg | 1979-05-13 | NULL | +-----+------+-------+----------------+------------+--------------+ 6 rows in set (0.00 sec) mysql> Als letztes soll nach dem Geburtsdatum sortiert werden. mysql> SELECT * from Mitarbeiter ORDER BY GebDat; +-----+------+-------+----------------+------------+--------------+ | MNr | VNr | AbtNr | Name | GebDat | Telefon | +-----+------+-------+----------------+------------+--------------+ | 3 | 1 | 1 | Uli | NULL | NULL | | 4 | 3 | 1 | JCP | NULL | 069/764758 | | 5 | 1 | 2 | Maier | NULL | 06196/671797 | | 6 | 5 | 2 | Meier | NULL | 069/97640232 | | 1 | NULL | 3 | Christoph Reeg | 1979-05-13 | NULL | | 2 | 1 | 1 | junetz.de | 1998-03-05 | 069/764758 | +-----+------+-------+----------------+------------+--------------+ 6 rows in set (0.01 sec) mysql>Die ersten vier Mitarbeiter haben kein Geburtsdatum eingetragen. Um sie dennoch irgendwie zu sortieren, ist bei ihnen ein zweites Sortierkriterium notwendig. Das kann einfach mit einem Komma getrennt hinter ORDER BY geschrieben werden. Um zum Beispiel nach Geburtsdatum und, wenn das nicht eindeutig ist, dann nach Namen zu sortieren, ist folgende Anweisung notwendig: mysql> SELECT * from Mitarbeiter ORDER BY GebDat,Name; +-----+------+-------+----------------+------------+--------------+ | MNr | VNr | AbtNr | Name | GebDat | Telefon | +-----+------+-------+----------------+------------+--------------+ | 4 | 3 | 1 | JCP | NULL | 069/764758 | | 5 | 1 | 2 | Maier | NULL | 06196/671797 | | 6 | 5 | 2 | Meier | NULL | 069/97640232 | | 3 | 1 | 1 | Uli | NULL | NULL | | 1 | NULL | 3 | Christoph Reeg | 1979-05-13 | NULL | | 2 | 1 | 1 | junetz.de | 1998-03-05 | 069/764758 | +-----+------+-------+----------------+------------+--------------+ 6 rows in set (0.00 sec) mysql>
Ein kleines Beispiel:
mysql> SELECT count(*), AbtNr from Mitarbeiter GROUP BY AbtNr; +----------+-------+ | count(*) | AbtNr | +----------+-------+ | 3 | 1 | | 2 | 2 | | 1 | 3 | +----------+-------+ 3 rows in set (0.00 sec) mysql>Die sechs Tupel (Datensätze), die wir in der Mitarbeiter-Tabelle haben, werden zu drei Gruppen zusammengefaßt; anschließend wird die Anzahl der Tupel pro Gruppe ausgeben. Eigentlich dürfen in der select_expression nur Spalten angegeben werden, die in GROUP BY auftauchen, MySQL ignoriert dies allerdings. Folgende Anweisung wäre eigentlich unzulässig, zudem ist sie völlig sinnlos - was besagt schon die Spalte `Name`? mysql> SELECT Name,count(*),AbtNr from Mitarbeiter GROUP BY AbtNr; +----------------+----------+-------+ | Name | count(*) | AbtNr | +----------------+----------+-------+ | junetz.de | 3 | 1 | | Maier | 2 | 2 | | Christoph Reeg | 1 | 3 | +----------------+----------+-------+ 3 rows in set (0.00 sec) mysql>
mysql> select * from table LIMIT 5,10; # gibt die Zeilen 6-15 zur�ck mysql> select * from table LIMIT 5; # gibt die ersten 5 Zeilen zur�ck mysql> select * from table LIMIT 0,5; # dasselbe nochmal
Im Normalfall werden die benötigten Spalten durch Kommas getrennt angegeben. Sobald die Spaltennamen nicht mehr eindeutig sind, weil mehrere Tabellen angegeben wurden, muß der Tabellenname, gefolgt von einem Punkt, vorangestellt werden; es können dabei auch sog. Aliase verwendet werden. Mehr dazu weiter unten. Neben den reinen Spaltenwerten können auch Werte, die aus den Spaltenwerten berechnet oder durch sonstige Funktionen erstellt wurden, ausgegeben werden. Funktionen werden im Kapitel Funktionen ausführlich beschrieben. Als Beispiel sollen der Mitarbeitername und die Telefonnummer ausgegeben werden. Die beiden Ausgaben sind äquivalent, wie man unschwer erkennen kann. Solange nur aus einer Tabelle ausgelesen wird, ist die erstere allerdings eher empfehlenswert, da nicht zu umständlich. mysql> select Name, Telefon from Mitarbeiter; +----------------+--------------+ | Name | Telefon | +----------------+--------------+ | Christoph Reeg | NULL | | junetz.de | 069/764758 | | Uli | NULL | | JCP | 069/764758 | | Maier | 06196/671797 | | Meier | 069/97640232 | +----------------+--------------+ 6 rows in set (0.02 sec) mysql> select Mitarbeiter.Name, Mitarbeiter.Telefon from Mitarbeiter; +----------------+--------------+ | Name | Telefon | +----------------+--------------+ | Christoph Reeg | NULL | | junetz.de | 069/764758 | | Uli | NULL | | JCP | 069/764758 | | Maier | 06196/671797 | | Meier | 069/97640232 | +----------------+--------------+ 6 rows in set (0.00 sec) mysql>
Tabellen-Alias Tabellen-Aliase können sowohl bei der select_expression als auch bei der `where_definition` zur eindeutigen Spaltenbeschreibung anstelle des Tabellennamens verwendet werden. Aliase werden verwendet, weil sie in der Regel kürzer sind als der Spaltenname. Aliase werden bei tables mit einer Leerstelle getrennt hinter dem Tabellennamen eingegeben. Die folgenden zwei Anweisungen sind völlig identisch, abgesehen davon, daß erstere kürzer ist. Der einzige Unterschied liegt in den ersten beiden Zeilen. Im ersten Beispiel wird bei der FROM-Anweisung ein Alias definiert, welches in der ersten Zeile bei der select_expression benutzt wird. mysql> select M.Name, M.Telefon, M.AbtNr -> FROM Mitarbeiter M -> WHERE M.AbtNr = 1; +-----------+------------+-------+ | Name | Telefon | AbtNr | +-----------+------------+-------+ | junetz.de | 069/764758 | 1 | | Uli | NULL | 1 | | JCP | 069/764758 | 1 | +-----------+------------+-------+ 3 rows in set (0.00 sec) mysql> select Mitarbeiter.Name, Mitarbeiter.Telefon, -> Mitarbeiter.AbtNr -> FROM Mitarbeiter -> WHERE Mitarbeiter.AbtNr = 1; +-----------+------------+-------+ | Name | Telefon | AbtNr | +-----------+------------+-------+ | junetz.de | 069/764758 | 1 | | Uli | NULL | 1 | | JCP | 069/764758 | 1 | +-----------+------------+-------+ 3 rows in set (0.01 sec) mysql>
Zum Umbenennen der Spalten wird einfach hinter den Spaltennamen bzw. Ausdruck der Aliasname geschrieben. Alternativ kann auch AS aliasname benutzt werden.
Ein kleines Beispiel:
mysql> SELECT count(*) -> FROM Mitarbeiter; +----------+ | count(*) | +----------+ | 6 | +----------+ 1 row in set (0.00 sec) mysql>Das einzige störende ist, daß die Spalte ,,count(*)`` heißt. Viel schöner wäre es doch, wenn sie z.B. ,,Anzahl`` heißen würde: mysql> SELECT count(*) Anzahl -> FROM Mitarbeiter; +--------+ | Anzahl | +--------+ | 6 | +--------+ 1 row in set (0.00 sec) mysql> SELECT count(*) AS Anzahl -> FROM Mitarbeiter; +--------+ | Anzahl | +--------+ | 6 | +--------+ 1 row in set (0.00 sec) mysql>Wie man unschwer erkennen kann, ist das AS optional.
Die `where_definition` wird auch beim Löschen (DELETE) und Ändern (UPDATE) von ausgewählten Datensätzen gebraucht. Eine Bedingung kann aus mehreren Teilbedingungen, die mit AND und OR verknüpft werden müssen, bestehen. Eine Teilbedingung besteht aus einem Spaltennamen, einem Operator sowie entweder einer Konstanten, einer weiteren Spalte oder einer Funktion. Die Teilbedingungen können auch mit NOT verneint werden. Schreibfaule können an Stelle von NOT auch einfach ! verwenden; das Ergebnis ist dasselbe. Die Reihenfolge der Teilbedingungen kann durch Klammern beeinflußt werden. Als Operatoren stehen die Vergleichsoperatoren sowie die Operatoren `LIKE`, `BETWEEN` und `IN` zur Auswahl. Alle Vergleichsoperatoren aus der Tabelle der Vergleichsoperatoren stehen zur Verfügung. Bei Vergleichen mit Strings (=VARCHAR) wird im Normalfall nicht auf die Groß-/Kleinschreibung geachtet. Wenn man jedoch unterscheiden will, so muß beim Anlegen der Tabelle bei VARCHAR die Option BINARY angegeben werden.
Es sollen alle Mitarbeiter ausgegeben werden, bei denen die Abteilungsnummer größer als 2 ist: mysql> SELECT Name, AbtNr -> FROM Mitarbeiter -> WHERE AbtNr > 2; +----------------+-------+ | Name | AbtNr | +----------------+-------+ | Christoph Reeg | 3 | +----------------+-------+ 1 row in set (0.00 sec) mysql> SELECT Name, AbtNr -> FROM Mitarbeiter -> WHERE NOT (AbtNr < 3); +----------------+-------+ | Name | AbtNr | +----------------+-------+ | Christoph Reeg | 3 | +----------------+-------+ 1 row in set (0.00 sec) mysql> Es sollen alle Mitarbeiter ausgegeben werden, die der Abteilung 1 angehören und als Vorgesetztennummer ebenfalls die 1 haben. mysql> SELECT Name, AbtNr, VNr -> FROM Mitarbeiter -> WHERE AbtNr = 1 -> AND VNr = 1; +-----------+-------+------+ | Name | AbtNr | VNr | +-----------+-------+------+ | junetz.de | 1 | 1 | | Uli | 1 | 1 | +-----------+-------+------+ 2 rows in set (0.02 sec) mysql> Es sollen alle Mitarbeiter ausgegeben werden, die keinen Vorgesetzten haben oder der Abteilung 1 angehören: mysql> SELECT Name, AbtNr, VNr -> FROM Mitarbeiter -> WHERE AbtNr = 1 -> OR VNr IS NULL; +----------------+-------+------+ | Name | AbtNr | VNr | +----------------+-------+------+ | Christoph Reeg | 3 | NULL | | junetz.de | 1 | 1 | | Uli | 1 | 1 | | JCP | 1 | 3 | +----------------+-------+------+ 4 rows in set (0.01 sec) mysql> SELECT Name, AbtNr, VNr -> FROM Mitarbeiter -> WHERE NOT (AbtNr <> 1) -> OR VNr IS NULL; +----------------+-------+------+ | Name | AbtNr | VNr | +----------------+-------+------+ | Christoph Reeg | 3 | NULL | | junetz.de | 1 | 1 | | Uli | 1 | 1 | | JCP | 1 | 3 | +----------------+-------+------+ 4 rows in set (0.00 sec) mysql> SELECT Name, AbtNr, VNr -> FROM Mitarbeiter -> WHERE NOT (AbtNr <> 1 AND VNr IS NOT NULL); +----------------+-------+------+ | Name | AbtNr | VNr | +----------------+-------+------+ | Christoph Reeg | 3 | NULL | | junetz.de | 1 | 1 | | Uli | 1 | 1 | | JCP | 1 | 3 | +----------------+-------+------+ 4 rows in set (0.00 sec) mysql>Bei der Überprüfung auf keinen Vorgesetzten ist IS NULL verwendet worden, da bei Vergleichen mit NULL-Werten nicht mit den normalen Operatoren gearbeitet werden kann. Statt dessen ist nur IS NULL oder, verneint, IS NOT NULL möglich. Es gibt mit Sicherheit noch 1001 andere Möglichkeiten, auf diese Lösung zu kommen. Da der erste Korrekturleser mir das nicht glauben wollte, hier noch ein paar Möglichkeiten mehr: mysql> SELECT Name, AbtNr, VNr -> FROM Mitarbeiter -> WHERE NOT (AbtNr < 1 OR AbtNr > 1) -> OR VNr IS NULL; +----------------+-------+------+ | Name | AbtNr | VNr | +----------------+-------+------+ | Christoph Reeg | 3 | NULL | | junetz.de | 1 | 1 | | Uli | 1 | 1 | | JCP | 1 | 3 | +----------------+-------+------+ 4 rows in set (0.00 sec) mysql> SELECT Name, AbtNr, VNr -> FROM Mitarbeiter -> WHERE (AbtNr <= 1 AND AbtNr >= 1) -> OR VNr IS NULL; +----------------+-------+------+ | Name | AbtNr | VNr | +----------------+-------+------+ | Christoph Reeg | 3 | NULL | | junetz.de | 1 | 1 | | Uli | 1 | 1 | | JCP | 1 | 3 | +----------------+-------+------+ 4 rows in set (0.01 sec) mysql> SELECT Name, AbtNr, VNr -> FROM Mitarbeiter -> WHERE AbtNr & 1 = 1 -> OR VNr IS NULL; +----------------+-------+------+ | Name | AbtNr | VNr | +----------------+-------+------+ | Christoph Reeg | 3 | NULL | | junetz.de | 1 | 1 | | Uli | 1 | 1 | | JCP | 1 | 3 | +----------------+-------+------+ 4 rows in set (0.00 sec) mysql> SELECT Name, AbtNr, VNr -> FROM Mitarbeiter -> WHERE POW(13,AbtNr) = 13 -> OR POW(VNr,42) IS NULL; +----------------+-------+------+ | Name | AbtNr | VNr | +----------------+-------+------+ | Christoph Reeg | 3 | NULL | | junetz.de | 1 | 1 | | Uli | 1 | 1 | | JCP | 1 | 3 | +----------------+-------+------+ 4 rows in set (0.02 sec) mysql>Es sind noch nicht 1001 Möglichkeiten, aber wenn ich vieeel Zeit habe, werde ich daran weiterarbeiten ;-). Wer sich die beiden letzten Lösungen genau angesehen hat, wird feststellen, daß dort unbekannte Befehle verwendet werden; in Kapitel Funktionen werden diese noch genauer beschrieben. Bei der letzten Möglichkeit sieht man, was passiert, wenn mit NULL-Werten gerechnet wird: Das Ergebnis ist NULL.
Es sollen alle Mitarbeiter ausgegeben werden, bei denen die Telefon-Vorwahl auf ,, 96`` endet. Falls du eine Möglichkeit findest, das mit Vergleichsoperatoren (und ohne Funktionen) zu lösen, schicke mir bitte eine E-Mail an die Adresse dsp@reeg.net; ich bevorzuge übrigens den Operator LIKE.
mysql> SELECT Name, Telefon -> FROM Mitarbeiter -> WHERE Telefon LIKE '%96/%'; +-------+--------------+ | Name | Telefon | +-------+--------------+ | Maier | 06196/671797 | +-------+--------------+ 1 row in set (0.00 sec) mysql> Es soll ein Mitarbeiter mit Namen ,,Meier`` ausgegeben werden. Allerdings ist unbekannt, ob er sich mit ,,ei`` oder ,,ai`` schreibt. Es sollen also alle Möglichkeiten ausgegeben werden.
mysql> SELECT Name -> FROM Mitarbeiter -> WHERE Name LIKE 'M_ier'; +-------+ | Name | +-------+ | Maier | | Meier | +-------+ 2 rows in set (0.00 sec) mysql>
Wie wir sehen, gibt es zwei Jokerzeichen:
Beispiel: Es sollen alle Mitarbeiter ausgewählt werden, deren Abteilungs-Nummer zwischen 2 und 5 liegt. Mit dem bisherigen Wissen würde man folgende Anweisung nehmen: mysql> SELECT * FROM Mitarbeiter -> WHERE AbtNr >= 2 AND AbtNr <=5; +-----+------+-------+----------------+------------+--------------+ | MNr | VNr | AbtNr | Name | GebDat | Telefon | +-----+------+-------+----------------+------------+--------------+ | 1 | NULL | 3 | Christoph Reeg | 1979-05-13 | NULL | | 5 | 1 | 2 | Maier | NULL | 06196/671797 | | 6 | 5 | 2 | Meier | NULL | 069/97640232 | +-----+------+-------+----------------+------------+--------------+ 3 rows in set (0.01 sec) mysql>Man kann es aber noch etwas vereinfachen: mysql> SELECT * FROM Mitarbeiter -> WHERE AbtNr BETWEEN 2 AND 5; +-----+------+-------+----------------+------------+--------------+ | MNr | VNr | AbtNr | Name | GebDat | Telefon | +-----+------+-------+----------------+------------+--------------+ | 1 | NULL | 3 | Christoph Reeg | 1979-05-13 | NULL | | 5 | 1 | 2 | Maier | NULL | 06196/671797 | | 6 | 5 | 2 | Meier | NULL | 069/97640232 | +-----+------+-------+----------------+------------+--------------+ 3 rows in set (0.00 sec) mysql>BETWEEN kann bei Textspalten, Datumsspalten und numerischen Spalten verwendet werden.
Zur Verdeutlichung: Es sollen alle Mitarbeiter ausgegeben werden, deren Telefonnummer ,,06196/671797`` oder ,,069/764758`` ist. Mit den bisherigen Operatoren würde sich folgende Abfrage ergeben: mysql> SELECT * FROM Mitarbeiter -> WHERE Telefon = '06196/671797' OR Telefon = '069/764758'; +-----+------+-------+-----------+------------+--------------+ | MNr | VNr | AbtNr | Name | GebDat | Telefon | +-----+------+-------+-----------+------------+--------------+ | 2 | 1 | 1 | junetz.de | 1998-03-05 | 069/764758 | | 4 | 3 | 1 | JCP | NULL | 069/764758 | | 5 | 1 | 2 | Maier | NULL | 06196/671797 | +-----+------+-------+-----------+------------+--------------+ 3 rows in set (0.00 sec) mysql>Das funktioniert zwar, aber da diese Möglichkeit bei großen Mengen von Werten sehr umständlich und unübersichtlich wird, hier das ganze nochmal mit dem IN-Operator: mysql> SELECT * FROM Mitarbeiter -> WHERE Telefon IN ('06196/671797','069/764758'); +-----+------+-------+-----------+------------+--------------+ | MNr | VNr | AbtNr | Name | GebDat | Telefon | +-----+------+-------+-----------+------------+--------------+ | 2 | 1 | 1 | junetz.de | 1998-03-05 | 069/764758 | | 4 | 3 | 1 | JCP | NULL | 069/764758 | | 5 | 1 | 2 | Maier | NULL | 06196/671797 | +-----+------+-------+-----------+------------+--------------+ 3 rows in set (0.00 sec) mysql>Der IN-Operator kann bei Textspalten, Datumsspalten und numerischen Spalten verwendet werden. Die Verneinung des IN-Operators ist NOT IN. Als Beispiel sollen alle Mitarbeiter ausgegeben werden, deren Telefonnummer nicht ,,06196/671797`` oder ,,069/97640232`` ist. Erst umständlich mit OR und dann elegant... mysql> SELECT * FROM Mitarbeiter -> WHERE NOT (Telefon = '06196/671797' OR Telefon = '069/764758'); +-----+------+-------+----------------+------------+--------------+ | MNr | VNr | AbtNr | Name | GebDat | Telefon | +-----+------+-------+----------------+------------+--------------+ | 1 | NULL | 3 | Christoph Reeg | 1979-05-13 | NULL | | 3 | 1 | 1 | Uli | NULL | NULL | | 6 | 5 | 2 | Meier | NULL | 069/97640232 | +-----+------+-------+----------------+------------+--------------+ 3 rows in set (0.00 sec) mysql> SELECT * FROM Mitarbeiter -> WHERE Telefon NOT IN ('06196/671797','069/764758'); +-----+------+-------+----------------+------------+--------------+ | MNr | VNr | AbtNr | Name | GebDat | Telefon | +-----+------+-------+----------------+------------+--------------+ | 1 | NULL | 3 | Christoph Reeg | 1979-05-13 | NULL | | 3 | 1 | 1 | Uli | NULL | NULL | | 6 | 5 | 2 | Meier | NULL | 069/97640232 | +-----+------+-------+----------------+------------+--------------+ 3 rows in set (0.00 sec) mysql>
Es wäre zum Beispiel Schwachsinn, zu versuchen, den Betrag von allen Stellenanzahlen auf einmal zu berechnen; bei der Summe paßt das schon eher.
Eine Auswahl der mathematischen Funktionen ist in Tabelle 6.4 aufgeführt.
In PHP gibt es auch eine Datum-Formatierungsfunktion. Ob man nun mit der MySQL-Funktion das Datum formatiert und dann mit PHP ausgibt oder mit Hilfe der PHP-Funktion das Datum formatiert, ist häufig egal. Teilweise ist es praktischer, mit Hilfe der MySQL-Funktion das Datum zu formatieren, weil man dann die Formatierungsanweisung in der SQL-Abfrage hat und mit PHP nur ausgeben muß. Andererseits kann es aber auch praktischer sein, mit PHP zu formatieren, wenn man zum Beispiel dasselbe Datum an mehreren Stellen auf der Seite verschieden formatiert haben will. Wie gesagt, es kommt auf den Einzelfall und die Vorlieben des Programmierers an.
In Verbindung mit Gruppenfunktionen darf streng genommen kein Spaltenname mehr mit in der select_expression stehen. Die einzige Ausnahme ist dann gegeben, wenn der Spaltenname in der GROUP BY-Anweisung steht. MySQL sieht das etwas lockerer und gibt keine Fehlermeldung bei Verwendung von Spaltennamen in der select_expression aus, allerdings hat dies im Normalfall wenig Sinn. In Tabelle 6.10 sind ein Teil der verfügbaren Gruppenfunktionen aufgeführt.
Für `expr` ist immer der Name der Spalte einzusetzen, mit der diese Operation erfolgen soll. Beispiel: Es soll ausgegeben werden, wie viele Mitarbeiter ihren Geburtstag angegeben haben.
mysql> SELECT count(GebDat) -> FROM Mitarbeiter; +---------------+ | count(GebDat) | +---------------+ | 2 | +---------------+ 1 row in set (0.27 sec) mysql>
mysql> SELECT m.Name, m.AbtNr, a.Name, a.AbtNr -> FROM Mitarbeiter m, Abteilung a; +----------------+-------+------------+-------+ | Name | AbtNr | Name | AbtNr | +----------------+-------+------------+-------+ | Christoph Reeg | 3 | EDV | 1 | | junetz.de | 1 | EDV | 1 | | Uli | 1 | EDV | 1 | | JCP | 1 | EDV | 1 | | Maier | 2 | EDV | 1 | | Meier | 2 | EDV | 1 | | Christoph Reeg | 3 | Verwaltung | 2 | | junetz.de | 1 | Verwaltung | 2 | | Uli | 1 | Verwaltung | 2 | | JCP | 1 | Verwaltung | 2 | | Maier | 2 | Verwaltung | 2 | | Meier | 2 | Verwaltung | 2 | | Christoph Reeg | 3 | Chefetage | 3 | | junetz.de | 1 | Chefetage | 3 | | Uli | 1 | Chefetage | 3 | | JCP | 1 | Chefetage | 3 | | Maier | 2 | Chefetage | 3 | | Meier | 2 | Chefetage | 3 | +----------------+-------+------------+-------+ 18 rows in set (0.07 sec) mysql>
mysql> SELECT m.Name, m.AbtNr, a.Name, a.AbtNr -> FROM Mitarbeiter m, Abteilung a -> WHERE m.AbtNr = a.AbtNr; +----------------+-------+------------+-------+ | Name | AbtNr | Name | AbtNr | +----------------+-------+------------+-------+ | junetz.de | 1 | EDV | 1 | | Uli | 1 | EDV | 1 | | JCP | 1 | EDV | 1 | | Maier | 2 | Verwaltung | 2 | | Meier | 2 | Verwaltung | 2 | | Christoph Reeg | 3 | Chefetage | 3 | +----------------+-------+------------+-------+ 6 rows in set (0.00 sec) mysql>Vor den Spaltennamen muß jeweils die entsprechende Tabelle genannt werden, da die Namen nicht eindeutig sind. Um nicht jedes Mal den kompletten Tabellennamen benutzen zu müssen, wurden Aliase verwendet (siehe Kapitel Tabellenalias). Über die AbtNr entsteht die Verbindung zwischen den beiden Tabellen. Falls bei der Verknüpfung von mehreren Tabellen nicht das gewünschte Ergebnis erscheint, fehlt häufig eine WHERE-Bedingung, so daß bei einigen Tabellen das kartesische Produkt entsteht. In solchen Fällen kann man einfach nachzählen: Wenn n Tabellen miteinander verknüpft werden sollen, werden (n-1) WHERE-Bedingungen benötigt. Diese Art der Verbindung wird Equi-Join genannt.
mysql> SELECT m.Name, m.VNr, v.Name, v.MNr -> FROM Mitarbeiter m, Mitarbeiter v -> WHERE m.VNr = v.MNr; +-----------+------+----------------+-----+ | Name | VNr | Name | MNr | +-----------+------+----------------+-----+ | junetz.de | 1 | Christoph Reeg | 1 | | Uli | 1 | Christoph Reeg | 1 | | Maier | 1 | Christoph Reeg | 1 | | JCP | 3 | Uli | 3 | | Meier | 5 | Maier | 5 | +-----------+------+----------------+-----+ 5 rows in set (0.13 sec) mysql> Die Tabelle `Mitarbeiter` muß zwei Mal innerhalb der FROM-Anweisung auftauchen. Um nachher die Spalten eindeutig bezeichnen zu können, müssen Tabellen-Aliase vergeben werden. Der einzige Schönheitsfehler bei der Abfrage ist, daß der Mitarbeiter ,,Christoph Reeg`` nicht aufgelistet wird. Im Prinzip ist das logisch, da er keinen Vorgesetzten hat. Dumm ist es trotzdem, und deshalb kommen wir zur nächsten Form des Joins: dem Outer-Join.
Die Syntax unter MySQL lautet (wo sonst die Tabellennamen stehen): haupttabelle LEFT JOIN tabelle2 ON bedingung oder haupttabelle LEFT JOIN tabelle2 USING (spalte)Bei der unteren Möglichkeit müssen die Spaltennamen in den beiden Tabellen, über die die Verbindung entsteht, gleich sein. Bei der oberen Möglichkeit muß an die Stelle, wo ` bedingung` steht, das eingesetzt werden, was man beim Equi-Join als ` where_condition` schreiben würde. In beiden Fällen kann auch LEFT OUTER JOIN anstelle von LEFT JOIN geschrieben werden - das OUTER ist optional und nur aus Gründen der SQL-Kompatibilität erlaubt. Um beim oben gezeigten Beispiel zu bleiben: Es sollen alle Mitarbeiter mit deren Vorgesetzten (sofern vorhanden) angezeigt werden. Da die Spaltennamen ungleich sind (in der Haupttabelle `VNr` und in der nachgeordneten Tabelle `MNr`), muß die obere Syntax benutzt werden. mysql> SELECT m.Name, m.VNr, v.Name, v.MNr -> FROM Mitarbeiter m LEFT JOIN Mitarbeiter v ON m.VNr = v.MNr; +----------------+------+----------------+------+ | Name | VNr | Name | MNr | +----------------+------+----------------+------+ | Christoph Reeg | NULL | NULL | NULL | | junetz.de | 1 | Christoph Reeg | 1 | | Uli | 1 | Christoph Reeg | 1 | | JCP | 3 | Uli | 3 | | Maier | 1 | Christoph Reeg | 1 | | Meier | 5 | Maier | 5 | +----------------+------+----------------+------+ 6 rows in set (0.03 sec) mysql> Die Mitarbeitertabelle mit dem Alias ,,m`` ist in unserem Fall die Haupttabelle. Wie man unschwer erkennen kann, wird bei den Attributen, bei denen keine Werte existieren (in diesem Beispiel die beiden rechten Spalten in der ersten Zeile), NULL als Wert genommen. Übrigens: Man muß natürlich nicht sowohl VNr als auch MNr abfragen (also zwischen SELECT und FROM angeben), da deren Werte wegen der ON-Bedingung (in der sie wiederum stehen müssen) immer gleich sind. Wenn man nur wissen möchte, in welcher Beziehung die einzelnen Mitarbeiter zu den Vorgesetzten stehen, kann man sogar ganz auf das Abfragen der Nummern verzichten. Um nicht völlig den Überblick zu verlieren, vergeben wir dabei noch Aliase:
mysql> SELECT m.Name AS Mitarb, v.Name as Vorges -> FROM Mitarbeiter m LEFT JOIN Mitarbeiter v ON m.VNr = v.MNr; +----------------+----------------+ | Mitarb | Vorges | +----------------+----------------+ | Christoph Reeg | NULL | | junetz.de | Christoph Reeg | | Uli | Christoph Reeg | | JCP | Uli | | Maier | Christoph Reeg | | Meier | Maier | +----------------+----------------+ 6 rows in set (0.03 sec) mysql>
Ein neues Beispiel:
mysql> SELECT a.Name, p.Kennzeichen, p.Typ -> FROM Abteilung a, PKW p -> WHERE a.AbtNr = p.AbtNr; +-----------+-------------+---------+ | Name | Kennzeichen | Typ | +-----------+-------------+---------+ | Chefetage | MTK-CR 1 | RR | | EDV | F-JN 1 | VW-Golf | +-----------+-------------+---------+ 2 rows in set (0.04 sec) mysql>Wie man sieht, führt der Equi-Join nicht zum gewünschten Ergebnis. Also das ganze nochmal als Outer-Join. Da die Schlüsselspalten denselben Namen haben, können in diesem Fall beide Syntaxvarianten verwendet werden:
mysql> SELECT a.Name, p.Kennzeichen, p.Typ -> FROM Abteilung a LEFT JOIN PKW p ON a.AbtNr = p.AbtNr; +------------+-------------+---------+ | Name | Kennzeichen | Typ | +------------+-------------+---------+ | EDV | F-JN 1 | VW-Golf | | Verwaltung | NULL | NULL | | Chefetage | MTK-CR 1 | RR | +------------+-------------+---------+ 3 rows in set (0.00 sec) mysql> SELECT a.Name, p.Kennzeichen, p.Typ -> FROM Abteilung a LEFT JOIN PKW p USING (AbtNr); +------------+-------------+---------+ | Name | Kennzeichen | Typ | +------------+-------------+---------+ | EDV | F-JN 1 | VW-Golf | | Verwaltung | NULL | NULL | | Chefetage | MTK-CR 1 | RR | +------------+-------------+---------+ 3 rows in set (0.00 sec) mysql>Als kleine Herausforderung hätte ich jetzt gerne die Abteilungen, die keinen PKW haben. Die Lösung ist eigentlich einfach. Wenn man sich das obige Ergebnis ansieht, stellt man fest (wie auch etwas weiter oben schon beschrieben), daß bei der Abteilung ohne PKW (nämlich ,,Verwaltung``) `Kennzeichen` und `Typ` NULL sind. mysql> SELECT a.Name, p.Kennzeichen, p.Typ -> FROM Abteilung a LEFT JOIN PKW p USING (AbtNr) -> WHERE Typ IS NULL; +------------+-------------+------+ | Name | Kennzeichen | Typ | +------------+-------------+------+ | Verwaltung | NULL | NULL | +------------+-------------+------+ 1 row in set (0.03 sec) mysql>
|
Test