Vorlesungsteil SQL Grundlagen -1/8- SQL SQL = Structured Query Language, ist eine standardisierte Sprache zum Gebrauch im Zusammenhang mit Datenbanken. Auf einem Server (Rechner im Netz, der Dienste für Clients bereit stellt) läuft ein Serverprogramm für ein Datenbank Management System. Serversoftware: Adabas, Firebird, InterBase, Microsoft SQL Server, MySQL, Oracle, PostgreSQL, SESAM (Siemens), Sybase, ... Clients (Rechner im Netz, die Dienste von Servern in Anspruch nehmen) greifen dann mit Programmen auf den Server zu. MySQL Als freie Software (unter der GPL = GNU General Public License stehend, Lizenzbedingungen für freie Software) ist MySQL weit verbreitet. Die MySQL Serversoftware (würde im Prinzip allein genügen) ist eingebettet in eine Rechnerumgebung, um das Arbeiten mit ihr zu erleichtern, zum Beispiel Aufbau von Webseiten im Moment des Aufrufs am Client über den Browser, die den Seiteninhalt aktuell aus der Datenbank abrufen (sog. dynamische Webseiten) - Webseiten von Online Shops, Spielplänen von Theatern, usw. LAMP = Linux, Apache, MySQL, PHP (und Perl). MAMP = Macintosh, Apache, MySQL und PHP. WAMP = Windows, Apache, MySQL und PHP. XAMPP = Windows, Apache, MySQL, PHP, Perl. Linux, Macintosh, MS-Windows: Betriebssystem. Apache: Apache Webserver. MySQL: MySQL SQL Server. PHP (PHP: Hypertext Preprocessor), Perl: Perl Scriptsprachen u.a. zu Erstellung dynamischer Webseiten. PHP ist der Programmiersprache C/C++ ähnlich. MySQL Clients Konsolen Client mysql (Bestandteil von MySQL): # mysql -u kubi -p --default-character-set=cp850 Enter password: ********* Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 1 Server version: 5.1.37 Source distribution Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> use demo_DB; Database changed mysql> show tables; +-------------------+ | Tables_in_demo_db | +-------------------+ | tbl_itu_laender | | tbl_itu_regionen | | tbl_krankenstand | | tbl_personal | +-------------------+ 4 rows in set (0.00 sec) mysql> quit Bye Hinweise: Hinter -u folgt der SQL Benutzername, -p sorgt für die Abfrage des SQL Passwortes des Benutzers und --default-character-set=cp850 teilt dem Server mit, daß die MS-DOS / MS-Windows Eingabeaufforderung im Zeichencode cp850 arbeitet (ansonsten sind deutsche Umlaute nicht richtig darstellbar, da normalerweise ein MySQL Server im UTF-8 Zeichencode läuft). Zum Logout dient quit. EDV 21. Dez. 2008 BHT / Dr. J. Kubiak Vorlesungsteil SQL Grundlagen -2/8- Client MySQLQueryBrowser: MySQLQueryBrowser Webbrowser als Client (via phpMyAdmin): phpMyAdmin) MS Access als Client: Client EDV 21. Dez. 2008 BHT / Dr. J. Kubiak Vorlesungsteil SQL Grundlagen -3/8- OpenOffice.org-Base als Client: Client Auch MS Excel, OpenOffice.org-Calc, MS Word (Serienbriefe), OpenOffice.org-Writer (Serienbriefe), ... können mit dem Server verbunden werden. Die SQL SELECT Anweisung Die wichtige SELECT Anweisung dient dazu, Datensätze aus einer oder mehreren Tabellen auszuwählen. Als Anfänger beim Arbeiten mit Access fallen einem diese Anweisungen sicher sehr oft auf, obwohl man sie nicht direkt eingegeben hat. Abfrage aller Felder: SELECT * FROM tbl_personal; Stern * ist ein Platzhalter für alle Attribute, hinter FROM steht der/die Tabellenname(n). Hinweis: Im Bild der entsprechende Abfrageentwurf in Access.Access ergänzt noch den Tabellennamen vor dem Feld: SELECT tbl_personal.* FROM tbl_personal; Dies ist aber nicht nötig, wie man sich überzeugen kann, wenn man im SQL Bearbeitungsfenster von Access diesen vor dem Stern entfernt (dann zeigt Access jedoch es nicht mehr grafisch an - obwohl die Abfrage korrekt in Access ausgeführt werden kann). +-------------+--------------+-------------+---------+---------+--------------+ | ID_Personal | txt_Nachname | txt_Vorname | txt_PLZ | txt_Ort | txt_Strasse | +-------------+--------------+-------------+---------+---------+--------------+ | 3 | Bern | Bernd | 10581 | Berlin | Ostseestr. 5 | | 5 | Rustol | Simone | 10622 | Berlin | Waldstr. 16 | | 8 | Folkres | Holger | 10622 | Berlin | Wildstr. 3 | | 13 | Meier | Sabine | 10551 | Berlin | Ringweg 7 | | 17 | Meier | Anton | 10551 | Berlin | Am Walde 36 | | 22 | Bonga | Ramona | 16321 | Bernau | Forststr. 6a | | 23 | Bern | Beate | 10584 | Berlin | Seeufer 57 | | 27 | Tomate | Tanja | 10584 | Berlin | Gemüseweg 8 | | 57 | Neklit | Jasmin | 10584 | Berlin | Badstr. 64 | | 78 | Idelt | Robert | 14547 | Beelitz | Blumstr. 11 | | 111 | Rauka | Anna | 14547 | Beelitz | Rundweg 12b | | 129 | Bila | Horst | 16356 | Eiche | Höhenweg 9 | +-------------+--------------+-------------+---------+---------+--------------+ Abfrage bestimmter Felder: SELECT txt_Nachname, txt_Vorname FROM tbl_personal; Die Feldnamen sind als Liste mit Komma getrennt hinter SELECT aufzuführen. EDV 21. Dez. 2008 +--------------+-------------+ | txt_Nachname | txt_Vorname | +--------------+-------------+ | Bern | Bernd | | Rustol | Simone | | Folkres | Holger | | Meier | Sabine | | Meier | Anton | | Bonga | Ramona | | Bern | Beate | | Tomate | Tanja | | Neklit | Jasmin | | Idelt | Robert | | Rauka | Anna | | Bila | Horst | +--------------+-------------+ BHT / Dr. J. Kubiak Vorlesungsteil SQL Grundlagen -4/8- Beschriftung Spalten: SELECT txt_Nachname AS Nachname, txt_Vorname AS Vorname FROM tbl_personal; Mit AS wird hinter einem Feldnamen die Beschriftung der Tabellenüberschrift angegeben. Abfrage mit Sortierung: SELECT txt_Nachname, txt_Vorname FROM tbl_personal ORDER BY txt_Nachname; Die Sortierung wird durch ORDER BY eingeleitet. Dahinter ist der Feldname anzugeben, nach dessen Werten sortiert wird. Standardmäßig wird aufsteigend sortiert. SELECT txt_Nachname, txt_Vorname FROM tbl_personal ORDER BY txt_Nachname DESC; Soll abwärts sortiert werden, muß hinter dem Feldnamen DESC geschrieben werden. SELECT txt_Nachname, txt_Vorname FROM tbl_personal ORDER BY txt_Nachname, txt_Vorname; Wird nach mehreren Kriterien sortiert, wird nach ORDER BY eine Liste von Feldnamen angegeben (Komma getrennt). Priorität beim Sortieren ist von links nach recht in der Liste. EDV 21. Dez. 2008 +----------+---------+ | Nachname | Vorname | +----------+---------+ | Bern | Bernd | | Rustol | Simone | | Folkres | Holger | | Meier | Sabine | | Meier | Anton | | Bonga | Ramona | | Bern | Beate | | Tomate | Tanja | | Neklit | Jasmin | | Idelt | Robert | | Rauka | Anna | | Bila | Horst | +----------+---------+ +--------------+-------------+ | txt_Nachname | txt_Vorname | +--------------+-------------+ | Bern | Bernd | | Bern | Beate | | Bila | Horst | | Bonga | Ramona | | Folkres | Holger | | Idelt | Robert | | Meier | Anton | | Meier | Sabine | | Neklit | Jasmin | | Rauka | Anna | | Rustol | Simone | | Tomate | Tanja | +--------------+-------------+ +--------------+-------------+ | txt_Nachname | txt_Vorname | +--------------+-------------+ | Tomate | Tanja | | Rustol | Simone | | Rauka | Anna | | Neklit | Jasmin | | Meier | Sabine | | Meier | Anton | | Idelt | Robert | | Folkres | Holger | | Bonga | Ramona | | Bila | Horst | | Bern | Beate | | Bern | Bernd | +--------------+-------------+ +--------------+-------------+ | txt_Nachname | txt_Vorname | +--------------+-------------+ | Bern | Beate | | Bern | Bernd | | Bila | Horst | | Bonga | Ramona | | Folkres | Holger | | Idelt | Robert | | Meier | Anton | | Meier | Sabine | | Neklit | Jasmin | | Rauka | Anna | | Rustol | Simone | | Tomate | Tanja | +--------------+-------------+ BHT / Dr. J. Kubiak Vorlesungsteil SQL Grundlagen Abfragen mit Auswahl: SELECT txt_Nachname, txt_Vorname FROM tbl_personal WHERE txt_Nachname>="M" AND txt_Nachname<"N"; Die Auswahl bestimmter Datensätze wird mit WHERE eingeleitet, dem ein Vergleich oder mit logischen Operatoren (AND, OR) zusammengesetzte Vergleiche folgen. -5/8+--------------+-------------+ | txt_Nachname | txt_Vorname | +--------------+-------------+ | Meier | Sabine | | Meier | Anton | +--------------+-------------+ Abfragen mit Gruppierung: SELECT txt_Ort FROM tbl_personal GROUP BY txt_Ort; Eine Abfrage mit Gruppierung wird durch die GROUP BY Klausel realisiert. Eine gruppierte Abfrage liefert immer eine sortierte Ausgabe (standardmäßig aufsteigend. Verwenden Sie GROUP BY txt_Ort DESC für absteigende Sortierung), bei der kein Eintrag mehrfach ausgegeben wird, sondern immer nur ein Mal, egal wie häufig er in der Tabelle vorkommt. +---------+ | txt_Ort | +---------+ | Beelitz | | Berlin | | Bernau | | Eiche | +---------+ Abfragen über mehrere Tabellen. Diese beiden Tabellen liegen vor ... 1. Tabelle tbl_personal: +-------------+--------------+-------------+---------+---------+--------------+ | ID_Personal | txt_Nachname | txt_Vorname | txt_PLZ | txt_Ort | txt_Strasse | +-------------+--------------+-------------+---------+---------+--------------+ | 3 | Bern | Bernd | 10581 | Berlin | Ostseestr. 5 | | 5 | Rustol | Simone | 10622 | Berlin | Waldstr. 16 | | 8 | Folkres | Holger | 10622 | Berlin | Wildstr. 3 | | 13 | Meier | Sabine | 10551 | Berlin | Ringweg 7 | | 17 | Meier | Anton | 10551 | Berlin | Am Walde 36 | | 22 | Bonga | Ramona | 16321 | Bernau | Forststr. 6a | | 23 | Bern | Beate | 10584 | Berlin | Seeufer 57 | | 27 | Tomate | Tanja | 10584 | Berlin | Gemüseweg 8 | | 57 | Neklit | Jasmin | 10584 | Berlin | Badstr. 64 | | 78 | Idelt | Robert | 14547 | Beelitz | Blumstr. 11 | | 111 | Rauka | Anna | 14547 | Beelitz | Rundweg 12b | | 129 | Bila | Horst | 16356 | Eiche | Höhenweg 9 | +-------------+--------------+-------------+---------+---------+--------------+ 2. Tabelle tbl_krankenstand: +-------------+-----------------+ | ID_Personal | int_Krankentage | +-------------+-----------------+ | 3 | 0 | | 5 | 2 | | 8 | 4 | | 13 | 0 | | 17 | 3 | | 22 | 1 | | 23 | 3 | | 27 | 4 | | 57 | 0 | | 78 | 0 | | 111 | 2 | | 129 | 5 | +-------------+-----------------+ EDV 21. Dez. 2008 BHT / Dr. J. Kubiak Vorlesungsteil SQL Grundlagen -6/8- Abfrage verknüpfter Tabellen (EQUI EQUI JOIN): JOIN SELECT txt_Nachname, txt_Vorname, int_Krankentage FROM tbl_Personal, tbl_Krankenstand WHERE tbl_Personal.ID_Personal = tbl_Krankenstand.ID_Personal; Da in beiden Tabellen die Schlüsselfelder den gleichen Feldnamen besitzen, müssen sie genauer bezeichnet werden: Tabellenname.Feldname Fragt man beide Tabellen ohne die WHERE Klausel ab, erhält man nicht das gewünschte Ergebnis, sondern das sogenannte kartesische (Kreuz-) Produkt mit 144 Ergebniszeilen: Jeder Eintrag der 1. Tabelle mit jedem Eintrag der 2.Tabelle. Tabellen Alias: SELECT txt_Nachname, txt_Vorname, int_Krankentage FROM tbl_Personal P, tbl_Krankenstand K WHERE P.ID_Personal = K.ID_Personal; Ein Tabellen Alias ist nützlich, um Tipparbeit in einer SQL Anweisung zu sparen, wenn ein und der gleiche Tabellenname mehrmals in der Anweisung nötig ist. Ein Tabellen Alias wird festgelegt, indem man ihn hinter dem jeweiligen Tabellennamen bei FROM setzt. +--------------+-------------+-----------------+ | txt_Nachname | txt_Vorname | int_Krankentage | +--------------+-------------+-----------------+ | Bern | Bernd | 0 | | Rustol | Simone | 2 | | Folkres | Holger | 4 | | Meier | Sabine | 0 | | Meier | Anton | 3 | | Bonga | Ramona | 1 | | Bern | Beate | 3 | | Tomate | Tanja | 4 | | Neklit | Jasmin | 0 | | Idelt | Robert | 0 | | Rauka | Anna | 2 | | Bila | Horst | 5 | +--------------+-------------+-----------------+ +--------------+-------------+-----------------+ | txt_Nachname | txt_Vorname | int_Krankentage | +--------------+-------------+-----------------+ | Bern | Bernd | 0 | | Rustol | Simone | 2 | | Folkres | Holger | 4 | | Meier | Sabine | 0 | | Meier | Anton | 3 | | Bonga | Ramona | 1 | | Bern | Beate | 3 | | Tomate | Tanja | 4 | | Neklit | Jasmin | 0 | | Idelt | Robert | 0 | | Rauka | Anna | 2 | | Bila | Horst | 5 | +--------------+-------------+-----------------+ Abfrage verknüpfter Tabellen (INNER INNER JOIN): JOIN SELECT txt_Nachname, txt_Vorname, int_Krankentage FROM tbl_Personal P INNER JOIN tbl_Krankenstand K ON P.ID_Personal = K.ID_Personal; INNER JOIN ist eine Alternative zu EQUI JOIN mit dem gleichen Ergebnis. EDV +--------------+-------------+-----------------+ | txt_Nachname | txt_Vorname | int_Krankentage | +--------------+-------------+-----------------+ | Bern | Bernd | 0 | | Rustol | Simone | 2 | | Folkres | Holger | 4 | | Meier | Sabine | 0 | | Meier | Anton | 3 | | Bonga | Ramona | 1 | | Bern | Beate | 3 | | Tomate | Tanja | 4 | | Neklit | Jasmin | 0 | | Idelt | Robert | 0 | | Rauka | Anna | 2 | | Bila | Horst | 5 | +--------------+-------------+-----------------+ 21. Dez. 2008 BHT / Dr. J. Kubiak Vorlesungsteil SQL Grundlagen -7/8- Abfrage verknüpfter Tabellen (LEFT LEFT JOIN, JOIN RIGHT JOIN): JOIN SELECT txt_Nachname, txt_Vorname, int_Krankentage FROM tbl_Personal P LEFT JOIN tbl_Krankenstand K ON P.ID_Personal = K.ID_Personal; SELECT txt_Nachname, txt_Vorname, int_Krankentage FROM tbl_Personal P RIGHT JOIN tbl_Krankenstand K ON P.ID_Personal = K.ID_Personal; +--------------+-------------+-----------------+ Bei den beiden vorliegenden Tabellen liefern LEFT JOIN und RIGHT JOIN die gleichen Ergebnisse, wie EQUI JOIN und INNER JOIN, da es zu jedem Datensatz der einen Tabelle einen zugehörigen Datensatz der anderen Tabelle gibt. Die Unterschiede werden erst deutlich, wenn dies nicht mehr vorliegt. | txt_Nachname | txt_Vorname | int_Krankentage | +--------------+-------------+-----------------+ | Bern | Bernd | 0 | | Rustol | Simone | 2 | | Folkres | Holger | 4 | | Meier | Sabine | 0 | | Meier | Anton | 3 | | Bonga | Ramona | 1 | | Bern | Beate | 3 | | Tomate | Tanja | 4 | | Neklit | Jasmin | 0 | | Idelt | Robert | 0 | | Rauka | Anna | 2 | | Bila | Horst | 5 | +--------------+-------------+-----------------+ Geht man nun von den folgenden beiden Tabellen aus ... 1. Tabelle tbl_personal (es wurde der letzte Datensatz gelöscht): +-------------+--------------+-------------+---------+---------+--------------+ | ID_Personal | txt_Nachname | txt_Vorname | txt_PLZ | txt_Ort | txt_Strasse | +-------------+--------------+-------------+---------+---------+--------------+ | 3 | Bern | Bernd | 10581 | Berlin | Ostseestr. 5 | | 5 | Rustol | Simone | 10622 | Berlin | Waldstr. 16 | | 8 | Folkres | Holger | 10622 | Berlin | Wildstr. 3 | | 13 | Meier | Sabine | 10551 | Berlin | Ringweg 7 | | 17 | Meier | Anton | 10551 | Berlin | Am Walde 36 | | 22 | Bonga | Ramona | 16321 | Bernau | Forststr. 6a | | 23 | Bern | Beate | 10584 | Berlin | Seeufer 57 | | 27 | Tomate | Tanja | 10584 | Berlin | Gemüseweg 8 | | 57 | Neklit | Jasmin | 10584 | Berlin | Badstr. 64 | | 78 | Idelt | Robert | 14547 | Beelitz | Blumstr. 11 | | 111 | Rauka | Anna | 14547 | Beelitz | Rundweg 12b | +-------------+--------------+-------------+---------+---------+--------------+ 2. Tabelle tbl_krankenstand (es wurde der erste Datensatz gelöscht): +-------------+-----------------+ | ID_Personal | int_Krankentage | +-------------+-----------------+ | 5 | 2 | | 8 | 4 | | 13 | 0 | | 17 | 3 | | 22 | 1 | | 23 | 3 | | 27 | 4 | | 57 | 0 | | 78 | 0 | | 111 | 2 | | 129 | 5 | +-------------+-----------------+ ... gibt es in jeder Tabelle jeweils einen Datensatz, zu dem in der anderen Tabelle kein zugehörigen Datensatz existiert. EQUI JOIN und INNER JOIN liefern nur die Datensätze, bei denen in beiden Tabellen verknüpfte Datensätze existieren. in beiden Fällen erhält man das gleiche Ergebnis: EDV 21. Dez. 2008 BHT / Dr. J. Kubiak Vorlesungsteil SQL Grundlagen -8/8- SELECT P.ID_Personal, txt_Nachname, txt_Vorname, int_Krankentage FROM tbl_Personal P, tbl_Krankenstand K WHERE P.ID_Personal = K.ID_Personal; SELECT P.ID_Personal, txt_Nachname, txt_Vorname, int_Krankentage FROM tbl_Personal P INNER JOIN tbl_Krankenstand K ON P.ID_Personal = K.ID_Personal; +-------------+--------------+-------------+-----------------+ | ID_Personal | txt_Nachname | txt_Vorname | int_Krankentage | +-------------+--------------+-------------+-----------------+ | 5 | Rustol | Simone | 2 | | 8 | Folkres | Holger | 4 | | 13 | Meier | Sabine | 0 | | 17 | Meier | Anton | 3 | | 22 | Bonga | Ramona | 1 | | 23 | Bern | Beate | 3 | | 27 | Tomate | Tanja | 4 | | 57 | Neklit | Jasmin | 0 | | 78 | Idelt | Robert | 0 | | 111 | Rauka | Anna | 2 | +-------------+--------------+-------------+-----------------+ LEFT JOIN und RIGHT JOIN liefern ein anderes Ergebnis als EUQI JOIN und INNER JOIN zuvor. Das Ergebnis von LEFT JOIN unterscheidet sich zudem vom Ergebnis von RIGHT JOIN: SELECT P.ID_Personal, txt_Nachname, txt_Vorname, int_Krankentage FROM tbl_Personal P LEFT JOIN tbl_Krankenstand K ON P.ID_Personal = K.ID_Personal; Die Datensätze der links von LEFT JOIN stehenden Tabelle (tbl_Personal) werden immer komplett ausgegeben, auch wenn kein passender Datensatz in der anderen Tabelle (tbl_Krankenstand) vorhanden ist. +-------------+--------------+-------------+-----------------+ | ID_Personal | txt_Nachname | txt_Vorname | int_Krankentage | +-------------+--------------+-------------+-----------------+ | 3 | Bern | Bernd | NULL | | 5 | Rustol | Simone | 2 | | 8 | Folkres | Holger | 4 | | 13 | Meier | Sabine | 0 | | 17 | Meier | Anton | 3 | | 22 | Bonga | Ramona | 1 | | 23 | Bern | Beate | 3 | | 27 | Tomate | Tanja | 4 | | 57 | Neklit | Jasmin | 0 | | 78 | Idelt | Robert | 0 | | 111 | Rauka | Anna | 2 | +-------------+--------------+-------------+-----------------+ SELECT K.ID_Personal, txt_Nachname, txt_Vorname, int_Krankentage FROM tbl_Personal P RIGHT JOIN tbl_Krankenstand K ON P.ID_Personal = K.ID_Personal; Die Datensätze der rechts von RIGHT JOIN stehenden Tabelle (tbl_Krankenstand) werden immer komplett ausgegeben, auch wenn kein passender Datensatz in der anderen Tabelle (tbl_Personal) vorhanden ist. EDV +-------------+--------------+-------------+-----------------+ | ID_Personal | txt_Nachname | txt_Vorname | int_Krankentage | +-------------+--------------+-------------+-----------------+ | 5 | Rustol | Simone | 2 | | 8 | Folkres | Holger | 4 | | 13 | Meier | Sabine | 0 | | 17 | Meier | Anton | 3 | | 22 | Bonga | Ramona | 1 | | 23 | Bern | Beate | 3 | | 27 | Tomate | Tanja | 4 | | 57 | Neklit | Jasmin | 0 | | 78 | Idelt | Robert | 0 | | 111 | Rauka | Anna | 2 | | 129 | NULL | NULL | 5 | +-------------+--------------+-------------+-----------------+ 21. Dez. 2008 BHT / Dr. J. Kubiak