5 Zugriffsmöglichkeiten el r n e n Man kann auf vielerlei Wegen auf die Daten eines MySQL-Servers zugreifen. Bisher haben wir immer das Client-Programm mysql genutzt. Natürlich ist das aber kein sinnvoller Weg für Endbenutzer. Für diese Gruppe schreibt man im Allgemeinen ein eigenes Programm, welches über eine der angebotenen Schnittstellen mit dem MySQL-Server kommuniziert. Zudem gibt es einige Programme, die einen Administrator bei seiner Arbeit mit dem MySQL-Server unterstützen, sei es grafisch oder textuell ausgerichtet. Um die Daten „am Stück“ aus dem Server heraus- und in einen anderen wieder hineinzubekommen, kann man auch verschiedene Wege beschreiten. 5.1 Was Sie in diesem Kapitel lernen Zunächst wollen wir uns mit den verschiedenen Tools auseinandersetzen, die Zugriff auf den MySQL-Server bzw. die von ihm verwalteten Daten gewähren. Das wichtigste ist dabei natürlich mysql, es gibt aber noch einige weitere, die eher der Administration dienen. Danach werden wir phpMyAdmin vorstellen, ein von Dritten programmiertes Tool, das dem Benutzer eine grafische Oberfläche präsentieren kann, welche den Dialog mit dem Server hübscher verpackt als dies Textprogramme ermöglichen (welche dafür natürlich andere Vorteile haben). Zudem läuft es unter einer Web-Oberfläche und kann somit mit jedem Browser bedient werden. Zum Dritten wollen wir uns mit dem Im- und Export von Daten kümmern. Damit kann man Datenbanken von einem zum anderen Rechner verschieben, aber auch Daten aus anderen Quellen in MySQL importieren. :DV 6LH LQ GLHVHP .DSLWHO OHUQHQ Schließlich befassen wir uns mit den Programmierschnittstellen von MySQL. Man kann aus den verschiedensten Programmiersprachen heraus auf den Server zugreifen, aber auch sprachunabhängige Schnittstellen wie ODBC nutzen. 5.2 Admin-Tools zu MySQL Mit MySQL werden schon viele Tools direkt mitgeliefert. Diese sollen dem Administrator die Arbeit mit dem MySQL-Server erleichtern. Das am häufigsten verwendete dürfte natürlich mysql sein. Wir haben die ganze Zeit damit gearbeitet und werden hier noch ein paar ergänzende Möglichkeiten erwähnen. Weiterhin stehen für den Zugriff auf den MySQL-Server weitere Tools bereit. Im Folgenden werden wir mysqladmin und mysqlshow besprechen. Die Tools mysqldump und mysqlimport werden wir detaillierter in Kapitel 5.4 behandeln, da sie zum Im- und Exportieren von Daten genutzt werden. mysqlhotcopy dient zum Sichern von Daten und wird im nächsten Kapitel besprochen, ebenso wie myisamchk und mysqlcheck, welche zum Prüfen und Reparieren von Tabellen und Datenbanken dienen. 5.2.1 mysql mysql ist das Tool, mit dem man vermutlich außerhalb des eigentlichen Programms für die Endbenutzer am häufigsten arbeiten wird. Wir haben schon sehr viel damit gemacht und werden hier nur noch auf einige weitere Punkte eingehen, die das Leben einfacher machen können. TEE / NOTEE TEE Mit dem Befehl TEE kann man dafür sorgen, dass die Ausgabe neben dem Bildschirm gleichzeitig auch in eine Datei geschrieben wird. Als Parameter gibt man den Pfad und Namen einer Datei an. Diese Datei wird als Ziel genommen, um die Ein- und Ausgaben, die man auch auf dem Bildschirm sieht, abzuspeichern. Dabei wird immer an das Ende der Datei angehängt, so dass auch nach einem Neustart die alten Daten nicht verloren sind. Mit NOTEE beendet man das Protokollieren. Ein Beispiel für eine solche Log-Datei wäre: Logging to file 'd:/temp/test.txt' mysql> SELECT * FROM raum; =XJULIIVP|JOLFKNHLWHQ +---------+-----------+-------+----------+ | raum_id | raum_name | etage | personen | +---------+-----------+-------+----------+ | 1 | A5.33 | 5 | 4 | | 2 | B2.02 | 2 | 20 | | 3 | C4.16 | 4 | 11 | | 4 | A5.21 | 5 | 6 | | 5 | A5.23 | 5 | 6 | +---------+-----------+-------+----------+ 5 rows in set (0.00 sec) mysql> UPDATE schueler SET nachname = 'Meier' WHERE schueler_id = 11; Query OK, 0 rows affected (0.02 sec) Rows matched: 0 Changed: 0 Warnings: 0 mysql> NOTEE Direkt vor dem „Logging to file…“ wurde der Befehl TEE d:/temp/test.txt aufgerufen (übrigens wieder ohne Semikolon). Ruft man nach einem NOTEE den Befehl TEE erneut auf, ohne aber einen Dateinamen angegeben zu haben, wird in die letzte Datei protokolliert, die verwendet wurde. STATUS Mit diesem Befehl kann man sich Statusinformationen über den Server, den Client und die Verbindung anzeigen lassen. Auch er wird ohne Semikolon aufgerufen: STATUS mysql> STATUS -------------D:\mysql\bin\mysql.exe Ver 11.18 Distrib 3.23.51, for Win95/Win98 (i32) Connection id: Current database: Current user: Server version: Protocol version: Connection: Client characterset: Server characterset: TCP port: Uptime: 1 musikschule ODBC@localhost 3.23.51-nt 10 localhost via TCP/IP german1 german1 3306 12 hours 37 min 35 sec Threads: 1 Questions: 66 Slow queries: 0 Opens: 24 Flush tables: 1 Open tables: 2 Queries per second avg: 0.001 -------------- Zunächst folgt eine Angabe des aktuellen Programms mit seinem Stand und der Distribution. Die Connection id gibt dann die Kennung an, über die das Client-Programm aktuell mit dem Server verbunden ist. Sie kann genutzt werden, um unter anderem mit mysqladmin Clients „abzuschießen“, die sich aufgehängt haben oder anderen Ärger bereiten. Die Current database gibt natürlich an, welche Datenbank gerade ausgewählt ist, und der Current user zeigt, wer man gerade ist. Server version und Protocol version geben Informationen über den Stand des Servers und die Protokollversion. Connection sagt, wie man mit dem Server verbunden ist, Client characterset und Server characterset informieren über den genutzten Zeichensatz, der TCP port steht für den Port, über den der MySQL-Server kommuniziert und die Uptime steht für die Laufzeit, die der Server schon ohne Unterbrechung läuft. Am Ende finden sich noch ein paar Informationen zur Statistik. Umleiten der Ein- und Ausgabe Redirection Hat man mehrere Befehle in einer festen Reihenfolge zu verarbeiten, kann man diese in einer Textdatei speichern (gerne mit der Endung .sql) und entweder in mysql mit dem Befehl SOURCE ausführen lassen (wie schon weiter oben behandelt), oder direkt beim Aufruf per Umleitung der Eingabe mitgeben. Speichern wir zum Beispiel die folgenden Befehle in einer Datei namens mycommand.sql: SHOW DATABASES; USE musikschule; SELECT * FROM raum; SELECT * FROM instrument; Wenn man nun mysql diese Datei als Eingabe mitgibt, erhält man folgende Ausgabe: prompt>mysql < mycommands.sql Database musikschule mysql test raum_id raum_name etage 1 A5.33 5 4 2 B2.02 2 20 3 C4.16 4 11 4 A5.21 5 6 5 A5.23 5 6 =XJULIIVP|JOLFKNHLWHQ personen instrument_id instr_name instr_gruppe 1 Querflöte Holzbläser 2 Klarinette Holzbläser 3 Violine Streicher 4 Viola Streicher 5 Posaune Blechbläser 6 Trompete Blechbläser 7 Klavier Tasten 8 Keyboard Tasten Wie man sieht, werden keine weiteren Informationen neben den Daten selber und den Spaltenüberschriften mitgegeben. Getrennt werden die Daten mit dem Tabulatorzeichen. Dieses Ausgabeformat wird dann verwendet, wenn MySQL im sogenannten Batch-Modus läuft. Das Verhalten lässt sich auch erzwingen oder verhindern, dazu benötigt man die im nächsten Abschnitt beschriebenen Kommandozeilen-Parameter. Die Ausgabe lässt sich natürlich auch direkt in eine Datei umleiten. Das erreicht man mit folgendem Aufruf: prompt>mysql < mycommands.sql > myresult.txt Kommandozeilen-Parameter Es gibt (neben -h, -u und -p) einige Parameter, die man beim Starten von mysql angeben kann und die in manchen Situationen helfen können. Fünf möchte ich hier aufführen, es gibt aber noch diverse mehr. • -? oder --help Dieser Parameter dürfte der wichtigste sein… Er gibt die möglichen Kommandozeilen-Parameter aus und beendet das Programm dann wieder. Das Ergebnis sehen Sie hier: prompt>mysql -? mysql Ver 11.18 Distrib 3.23.51, for Win95/Win98 (i32) Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB This software comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to modify and redistribute it under the GPL license Usage: mysql [OPTIONS] [database] -?, --help Display this help and exit. -A, --no-auto-rehash No automatic rehashing. One has to use 'rehash' to get table and field completion. This gives a quicker start of mysql and disables rehashing on reconnect. -B, --batch Print results with a tab as separator, each row on a new line. Doesn't use history file. --character-sets-dir=... Directory where character sets are located. -C, --compress Use compression in server/client protocol. -D, --database=.. Database to use. --default-character-set=... Set the default character set. -e, --execute=... Execute command and quit. (Output like with --batch) -E, --vertical Print the output of a query (rows) vertically. -f, --force Continue even if we get an sql error. -g, --no-named-commands Named commands are disabled. Use \* form only, or use named commands only in the beginning of a line ending with a semicolon (;) Since version 10.9 the client now starts with this option ENABLED by default! Disable with '-G'. Long format commands still work from the first line. -G, --enable-named-commands Named commands are enabled. Opposite to -g. -i, --ignore-spaces Ignore spaces after function names. -h, --host=... Connect to host. -H, --html Produce HTML output. --local-infile=[1|0] Enable/disable LOAD DATA LOCAL INFILE -L, --skip-line-numbers Don't write line number for errors. --no-tee Disable outfile. See interactive help (\h) also. -n, --unbuffered Flush buffer after each query. -N, --skip-column-names Don't write column names in results. -O, --set-variable var=option Give a variable an value. --help lists variables. -o, --one-database Only update the default database. This is useful for skipping updates to other database in the update log. -p[password], --password[=...] Password to use when connecting to server If password is not given it's asked from the tty. -W, --pipe Use named pipes to connect to server -P, --port=... -q, --quick -r, --raw Port number to use for connection. Don't cache result, print it row by row. This may slow down the server if the output is suspended. Doesn't use history file. Write fields without conversion. Used with --batch =XJULIIVP|JOLFKNHLWHQ -s, --silent -S --socket=... -t, --table -T, --debug-info --tee=... -u, -U, -v, -V, -w, Be more silent. Socket file to use for connection. Output in table format. Print some debug info at exit. Append everything into outfile. See interactive help (\h) also. Does not work in batch mode. --user=# User for login if not current user. --safe-updates[=#], --i-am-a-dummy[=#] Only allow UPDATE and DELETE that uses keys. --verbose Write more. (-v -v -v gives the table output format) --version Output version information and exit. --wait Wait and retry if connection is down. Default options are read from the following files in the given order: D:\WINNT\my.ini C:\my.cnf The following groups are read: mysql client The following options may be given as the first argument: --print-defaults Print the program argument list and exit --no-defaults Don't read default options from any options file --defaults-file=# Only read default options from the given file # --defaults-extra-file=# Read this file after the global files are read Possible variables for option connect_timeout current max_allowed_packet current net_buffer_length current select_limit current max_join_size current --set-variable (-O) are: value: 0 value: 16777216 value: 16384 value: 1000 value: 1000000 • -e oder --execute Mit diesem Parameter kann man einzelne Befehle ausführen lassen. Das Programm wird dann direkt danach beendet. Der Befehl muss in Anführungszeichen stehen. Damit kann man sich einzelne Tabelleninhalte oder andere Informationen ausgeben lassen, ohne erst aufwändiger eine Befehlsdatei zu erstellen. Ein Beispiel dafür ist: prompt>mysql -e "SELECT * FROM raum;" musikschule +---------+-----------+-------+----------+ | raum_id | raum_name | etage | personen | +---------+-----------+-------+----------+ | 1 | A5.33 | 5 | 4 | | 2 | B2.02 | 2 | 20 | | 3 | C4.16 | 4 | 11 | | 4 | A5.21 | 5 | 6 | | 5 | A5.23 | 5 | 6 | +---------+-----------+-------+----------+ Nutzt man die lange Version des Parameters, sieht das Ganze so aus: prompt>mysql --execute="SHOW TABLES;" musikschule +-----------------------+ | Tables_in_musikschule | +-----------------------+ | ausleihe | | fulltexttest | | instrument | | lehrer | | leihinstrument | | orchester | | orchester_tn | | raum | | schueler | | unterricht | | unterricht_tn | | warteliste | +-----------------------+ • -B oder --batch Mit dieser Option kann man dafür sorgen, dass die Ausgabe wie bei umgeleiteter Eingabe geschieht: nur mit Tabulatoren getrennte Werte und keine Rahmen um die Tabellen herum. Das kann nützlich sein, wenn man mysql mit dem Parameter -e aufruft (was ansonsten zu einer „normalen“ Anzeige führt): prompt>mysql -B -e "SELECT * FROM instrument;" musikschule instrument_id instr_name instr_gruppe 1 Querflöte Holzbläser 2 Klarinette Holzbläser 3 Violine Streicher 4 Viola Streicher 5 Posaune Blechbläser 6 Trompete Blechbläser 7 Klavier Tasten 8 Keyboard Tasten Natürlich kann man mysql mit diesem Parameter auch im interaktiven Modus starten, nur hat man dann keinerlei Anzeige und Strukturierung neben den eigentlichen Daten. Im folgenden Beispiel sind zur Verdeutlichung die eingegebenen Zeichen kursiv gedruckt: =XJULIIVP|JOLFKNHLWHQ prompt>mysql -B musikschule SELECT * FROM raum; raum_id raum_name etage personen 1 A5.33 5 4 2 B2.02 2 20 3 C4.16 4 11 4 A5.21 5 6 5 A5.23 5 6 SHOW FIELDS FROM raum; Field Type Null Key Default Extra raum_id smallint(5) unsigned PRI raum_name varchar(10) etage char(3) YES MUL NULL personen mediumint(8) unsigned YES EXIT NULL auto_increment 1 prompt> Wie man sieht, ist dies in den meisten Fällen nicht wirklich sinnvoll. Das Gegenstück dazu ist der Parameter -t. • -H oder --html Diese Option sorgt dafür, dass die Daten anstatt mit |, + und - als HTML-Tabellen formatiert ausgegeben werden. Es wird eine Tabelle mit einer Rahmenstärke von 1 erzeugt, die Spaltennamen sind als <TH>...</TH> formatiert, die Werte selber mit <TD>...</TD> umschlossen. Diese Option kann man dann verwenden, wenn man die Tabelleninhalte schnell und einfach in einer HTML-Datei ausgeben möchte. Allerdings ist zu beachten, dass Umlaute und andere Sonderzeichen nicht gesondert behandelt werden. Möchte man also auf Nummer sicher gehen, sollte man in der HTML-Datei, die drumherum noch entstehen muss, den entsprechenden Zeichensatz angeben. Ein Beispiel für die Ausgabe zusammen mit -e wäre das folgende: D:\TEMP>mysql -H -e "SELECT * FROM instrument;" musikschule <TABLE BORDER=1><TR><TH>instrument_id</TH><TH>instr_name</ TH><TH>instr_gruppe</TH></TR><TR><TD>1</TD><TD>Querflöte</ TD><TD>Holzbläser</TD></TR><TR><TD>2</TD><TD>Klarinette</ TD><TD>Holzbläser</TD></TR><TR><TD>3</TD><TD>Violine</TD><TD>Streicher</ TD></TR><TR><TD>4</TD><TD>Viola</TD><TD>Streicher</TD></TR><TR><TD>5</ TD><TD>Posaune</TD><TD>Blechbläser</TD></TR><TR><TD>6</TD><TD>Trompete</ TD><TD>Blechbläser</TD></TR><TR><TD>7</TD><TD>Klavier</TD><TD>Tasten</ TD></TR><TR><TD>8</TD><TD>Keyboard</TD><TD>Tasten</TD></TR></TABLE> Sehr gut lesbar, oder? Aber für eine Web-Seite genau das Richtige (vielleicht abgesehen von den fehlenden Zeilenumbrüchen, die aber auch nur den Quelltext lesbarer machen). Ein etwas komplexeres Bei- spiel wäre das folgende, wobei wir die folgende SQL-Anfrage in einer Datei namens unterricht.sql speichern: SELECT CONCAT(LEFT(vorname, 1), '. ', nachname) AS Lehrer, instr_name AS "Instr.", raum_name AS Raum, CASE wochentag WHEN 0 THEN 'Mo' WHEN 1 THEN 'Di' WHEN 2 THEN 'Mi' WHEN 3 THEN 'Do' WHEN 4 THEN 'Fr' WHEN 5 THEN 'Sa' WHEN 6 THEN 'So' END AS Tag, CONCAT(TIME_FORMAT(uhrzeit_von, '%H:%i'), '-', TIME_FORMAT(uhrzeit_bis, '%H:%i')) AS Zeit, kosten AS Preis, IF(einzel, 'X', ' ') AS Einzel FROM unterricht AS u, lehrer AS l, instrument AS i, raum AS r WHERE u.lehrer_id = l.lehrer_id AND u.instrument_id = i.instrument_id AND u.raum_id = r.raum_id; Sie finden die Datei unterricht.sql auch auf der beiliegenden CD-ROM im Verzeichnis Beispiel. Mit diesem Aufruf erzeugt man nun eine HTML-Tabelle in unterricht_ tab.html: prompt>mysql -H musikschule < unterricht.sql > unterricht_tab.html Diese Datei kann man nun als Grundlage für eine vollständige HTML-Datei nutzen. Klemmt man noch die notwendigsten Codes drumherum (<HTML><BODY> am Anfang und </BODY></HTML> am Ende), erhält man eine Ausgabe wie in Abbildung 5.1. Abbildung 5.1: Ausgabe einer Tabelle im HTML-Format Die ergänzte Ergebnisdatei unterricht_tab.html ist ebenfalls auf der CDROM im Verzeichnis Beispiel zu finden. =XJULIIVP|JOLFKNHLWHQ Diese Ausgabe kann man also als Grundlage für die Anzeige von Daten auf Web-Seiten nutzen, allerdings sind andere Wege (zum Beispiel über PHP, siehe weiter unten) deutlich flexibler. Man kann übrigens auch diesen Parameter im interaktiven Modus nutzen, allerdings sind die Ausgaben dann nicht sehr leserlich (wie man oben gesehen hat)… • -N oder --skip-column-names Mit -N kann man die Ausgabe der Spaltennamen unterdrücken. Dies kann dann nützlich sein, wenn man die Daten in Dateien speichern möchte und die Spaltennamen dabei eher hinderlich sind (man sollte dann ja sowieso wissen, wie die Spaltenanordnung ist). Ein Beispiel dafür ist: prompt>mysql -N 1 A5.33 2 B2.02 3 C4.16 4 A5.21 5 A5.23 -B -e "SELECT * FROM raum;" musikschule 5 4 2 20 4 11 5 6 5 6 • -t oder --table Mit dieser Option kann man sich auch dann die Daten in der üblichen Tabellenform (mit Rahmen) ausgeben lassen, wenn man sich eigentlich im Batch-Modus befindet (zum Beispiel bei Verwendung der Ein- und Ausgabeumleitung): prompt>mysql musikschule < unterricht.sql Lehrer Instr. Raum Tag Zeit Preis Einzel G. Mosler Posaune A5.23 Mi 19:15-20:00 25.00 H. Knarer Querflöte C4.16 Fr 17:00-17:45 K. Hansen Violine B2.02 Do 15:35-16:20 20.00 K. Hansen Viola B2.02 Do 16:30-17:15 20.00 P. Ottbein Klavier A5.33 Sa 10:00-11:00 35.00 30.00 X X prompt>mysql -t musikschule < unterricht.sql +------------+-----------+-------+------+-------------+-------+--------+ | Lehrer | Instr. | Raum | Tag | Zeit | Preis | Einzel | +------------+-----------+-------+------+-------------+-------+--------+ | G. Mosler | Posaune | A5.23 | Mi | 19:15-20:00 | 25.00 | | | H. Knarer | Querflöte | C4.16 | Fr | 17:00-17:45 | 30.00 | X | | K. Hansen | Violine | B2.02 | Do | 15:35-16:20 | 20.00 | | | K. Hansen | Viola | B2.02 | Do | 16:30-17:15 | 20.00 | | | P. Ottbein | Klavier | A5.33 | Sa | 10:00-11:00 | 35.00 | X | +------------+-----------+-------+------+-------------+-------+--------+ 5.2.2 mysqladmin mysqladmin Mit mysqladmin kann man viele Verwaltungsaufgaben einfacher erledigen als mit mysql. Dabei nutzt man die folgende Syntax: mysqladmin [options] command command ... Die möglichen Optionen ähneln denen von mysql, in Tabelle 5.1 gibt es zu jeder eine kurze Beschreibung. Kurze Version Lange Version Beschreibung -# --debug=... Ausgabe von Debug-Informationen -f --force Beim Löschen von Datenbanken nicht nachfragen. Werden mehrere Befehle angegeben, werden die folgenden auch bei einem Fehler des aktuellen Befehls abgearbeitet. -? --help Ausgabe der Hilfe --charactersets-dir=... Angabe des Verzeichnisses mit den Zeichensatzinformationen -C --compress Komprimierung bei der Kommunikation zwischen Client und Server nutzen -h --host=... Angabe des Hosts -p --password[=...] Angabe des Kennworts oder Nachfragen, falls nicht angegeben -W --pipe Verwendung von Named Pipes bei der Verbindung zum Server -P --port=... Angabe des Ports für die Verbindung -i --sleep=... wiederholtes Ausführen der Befehle mit einer Pause der angegebenen Zeit (in Sekunden) -r --relative zeigt bei Nutzung von -i nur den Unterschied zur vorigen Ausführung (funktioniert nur mit extended-status, siehe unten). -E --vertical Ausgabe wie bei -r, allerdings in vertikaler Richtung -s --silent Keine Fehlermeldung, wenn es Verbindungsprobleme zum Server gibt. -S --socket=... Angabe der Socket-Datei für die Verbindung -u --user=... Angabe des Benutzers, mit dem sich das Programm anmelden soll -v --verbose Ausgabe von mehr Informationen -V --version Nur Ausgabe der Versionsnummer und Beenden des Programms. -w --wait=... Falls die Verbindung nicht möglich ist, die angegebene Anzahl an Versuchen wiederholen, anstatt direkt abzubrechen. Tabelle 5.1: Optionen für mysqladmin =XJULIIVP|JOLFKNHLWHQ Bei den Befehlen gibt es insgesamt 21 Möglichkeiten. Allen ist gemein, dass man sie soweit abkürzen kann, wie sie noch eindeutig sind. create db_name zum Beispiel kann man mit c db_name abkürzen, status hingegen muss mindestens stat heißen. • create db_name Dieser Befehl legt eine Datenbank mit dem Namen db_name an. Er entspricht dem Befehl CREATE DATABASE db_name in mysql. • drop db_name Mit diesem Befehl wird eine Datenbank wieder gelöscht. Dabei gibt es eine Kontrollabfrage (sofern man nicht die Option -f nutzt), da danach unwiderruflich auch alle Tabellen und Daten dieser Datenbank gelöscht sind: prompt>mysqladmin create mytest prompt>mysqladmin drop mytest Dropping the database is potentially a very bad thing to do. Any data stored in the database will be destroyed. Do you really want to drop the 'mytest' database [y/N] y Database "mytest" dropped • extended-status Dieser Befehl gibt eine Statusübersicht aus, die man unter mysql mit SHOW STATUS erhalten würde. Nutzt man den Parameter -r zusammen mit -i werden beim ersten Mal die „normalen“ Werte ausgegeben, danach aber nur noch die Differenzen zur Vorversion. Dies kann man nutzen, wenn man nur die Veränderungen der Werte beobachten möchte. Der folgende Befehl gibt die Statusliste alle 60 Sekunden aus, zeigt dabei aber (nach dem ersten Mal) nur die Differenzen an: prompt>mysqladmin -i 60 -r extended-status • flush-hosts leert den Host-Cache. Dies kann nützlich sein, wenn sich die IPAdresse eines Hosts geändert hat oder wenn ein Host geblockt ist. Unter mysql kann man dafür den Befehl FLUSH HOSTS nutzen. • flush-logs schließt alle Log-Dateien und öffnet sie neu. Damit ist sichergestellt, dass alle Änderungen auch auf Festplatte abgelegt sind. Dies entspricht dem Befehl FLUSH LOGS unter mysql. • flush-tables schließt alle offenen Tabellen und sorgt dafür, dass alle Tabellen, die gerade in Benutzung sind, möglichst bald geschlossen werden. Dies entspricht dem Befehl FLUSH TABLES unter mysql. • flush-privileges lädt die Berechtigungen erneut aus den entsprechenden Tabellen. Dies entspricht dem Befehl FLUSH PRIVILEGES unter mysql. • kill id, id, ... Mit diesem Befehl kann man Threads im MySQL-Server beenden, die einen Client bedienen. Die entsprechende ID wird beim Anmelden mit mysql ausgegeben, kann aber auch mit SHOW PROCESSLIST ermittelt werden. Ein Thread wird normalerweise nicht sofort beendet, sondern erhält nur eine Markierung. Diese wird erst in bestimmten Situationen berücksichtigt. • password new_pwd ändert das bestehende Kennwort ab und setzt es auf new_pwd. • ping prüft, ob der MySQL-Server erreichbar ist und reagiert: prompt>mysqladmin ping mysqld is alive • processlist gibt die aktuelle Prozessliste aus. Dies kann auch mit SHOW PROCESSLIST in mysql erreicht werden. Wie in Abbildung 5.2 zu sehen, erhält man neben den angemeldeten Benutzern auch die gerade verwendete Datenbank und eine Information über die aktuelle Tätigkeit. Auch der Aufruf von mysqladmin ist hier (indirekt) vermerkt, er wird auf ein SHOW PROCESSLIST abgebildet. Prompt>mysqladmin processlist +----+------+-----------+-------------+---------+------+-------+------------------+ | Id | User | Host | db | Command | Time | State | Info | +----+------+-----------+-------------+---------+------+-------+------------------+ | 8 | ODBC | localhost | musikschule | Sleep | 1 | | | | 10 | ODBC | localhost | | Query | 0 | | show processlist | +----+------+-----------+-------------+---------+------+-------+------------------+ Abbildung 5.2: Ausgabe von mysqladmin processlist • reload lädt die Berechtigungstabellen erneut. Dies ist identisch zu flushprivileges. =XJULIIVP|JOLFKNHLWHQ • refresh schließt alle Tabellen und Log-Dateien und öffnet diese erneut. • shutdown Dieser Befehl fährt den Server herunter. Somit lässt sich der Server auch „aus der Ferne“ beenden, ohne, dass man sich direkt auf dem Rechner anmelden muss. • status Mit diesem Befehl kann man sich eine kurze Status-Information ausgeben lassen: prompt>mysqladmin status Uptime: 35750 Threads: 2 Questions: 19 Slow queries: 0 Opens: 7 Flush tables: 1 Open tables: 0 Queries per second avg: 0.001 • start-slave startet einen Slave in einer verteilten Umgebung • stop-slave beendet einen Slave in einer verteilten Umgebung • variables Dieser Befehl gibt die aktuellen Variablen des MySQL-Servers aus und entspricht einem SHOW VARIABLES unter mysql. • version Mit diesem Befehl kann man sich – anders als bei der Option -V – nicht nur die Version von mysqladmin ausgeben lassen, sondern auch die Versionsinfo des MySQL-Servers auslesen. Zudem werden auch die Informationen angezeigt, die man mit status erhält: prompt>mysqladmin version mysqladmin Ver 8.23 Distrib 3.23.51, for Win95/Win98 on i32 Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB This software comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to modify and redistribute it under the GPL license Server version Protocol version Connection TCP port Uptime: 3.23.51-nt 10 localhost via TCP/IP 3306 9 hours 59 min 36 sec Threads: 2 Questions: 26 Slow queries: 0 Opens: 7 Flush tables: 1 Open tables: 0 Queries per second avg: 0.001 5.2.3 mysqlshow mysqlshow Das Programm mysqlshow dient als einfaches Interface zum Anzeigen von Strukturdaten. Es lassen sich Datenbanken, Tabellen und Spalten ausgeben. Alle Informationen erhält man auch über den SHOW-Befehl in mysql. Der Aufruf sieht wie folgt aus: mysqlshow [OPTIONS] [database [table [column]]] Als Optionen stehen die (zum Teil bekannten) Varianten aus Tabelle 5.2 zur Verfügung. Kurze Version Lange Version Beschreibung -# --debug=... Ausgabe von Debug-Informationen -? --help Ausgabe der Hilfe -c --charactersets-dir=... Angabe des Verzeichnisses mit den Zeichensatzinformationen -C --compress Komprimierung bei der Kommunikation zwischen Client und Server nutzen -h --host=... Angabe des Hosts -i –status Ausgabe von zusätzlichen Tabelleninformationen -k --keys Angabe der Schlüssel für die Tabelle -p --password[=...] Angabe des Kennworts oder Nachfragen, falls nicht angegeben -W --pipe Verwendung von Named Pipes bei der Verbindung zum Server -P --port=... Angabe des Ports für die Verbindung -S --socket=... Angabe der Socket-Datei für die Verbindung -u --user=... Angabe des Benutzers, mit dem sich das Programm anmelden soll -v --verbose Ausgabe von mehr Informationen -V --version nur Ausgabe der Versionsnummer und Beenden des Programms Tabelle 5.2: Optionen für mysqlshow Wird keine Datenbank angegeben, werden alle verfügbaren Datenbanken angezeigt: prompt>mysqlshow +-------------+ | Databases | +-------------+ | musikschule | | mysql | | test | +-------------+ =XJULIIVP|JOLFKNHLWHQ Mit Angabe einer Datenbank werden die dort enthaltenen Tabellen angegeben: prompt>mysqlshow musikschule Database: musikschule +----------------+ | Tables | +----------------+ | ausleihe | | fulltexttest | | instrument | | lehrer | | leihinstrument | | orchester | | orchester_tn | | raum | | schueler | | unterricht | | unterricht_tn | | warteliste | +----------------+ Mit dem zusätzlichen Parameter -i erhält man eine sehr umfangreiche Ausgabe wie bei SHOW TABLE STATUS, siehe auch Abbildung 5.3. prompt>mysqlshow -i musikschule Database: musikschule +----------------+--------+------------+------+----------------+-------------+-----------------+--------------+-----------+| Type | Row_format | Rows | Avg_row_length | Data_length | Max_data_length | Index_length | Data_free | | Name +----------------+--------+------------+------+----------------+-------------+-----------------+--------------+-----------+| | 0 | 1024 | 81604378623 | 0 | 0 | 0 | MyISAM | Fixed | ausleihe | | 0 | 11264 | 4294967295 | 3632 | 16 | 227 | fulltexttest | MyISAM | Dynamic | | 0 | 2048 | 4294967295 | 236 | 29 | 8 | MyISAM | Dynamic | instrument | | 0 | 2048 | 4294967295 | 496 | 124 | 4 | MyISAM | Dynamic | lehrer | | 0 | 2048 | 4294967295 | 136 | 34 | 4 | leihinstrument | MyISAM | Dynamic | | 0 | 1024 | 4294967295 | 0 | 0 | 0 | MyISAM | Dynamic | orchester | | 0 | 1024 | 73014444031 | 0 | 0 | 0 | orchester_tn | MyISAM | Fixed | | 0 | 3072 | 4294967295 | 100 | 5 | 20 | MyISAM | Dynamic | raum | | 0 | 4096 | 4294967295 | 468 | 117 | 4 | MyISAM | Dynamic | schueler | | 0 | 2048 | 133143986175 | 155 | 31 | 5 | MyISAM | Fixed | unterricht | | 0 | 2048 | 55834574847 | 52 | 13 | 4 | unterricht_tn | MyISAM | Fixed | | 0 | 1024 | 68719476735 | 0 | 0 | 0 | MyISAM | Fixed | warteliste +----------------+--------+------------+------+----------------+-------------+-----------------+--------------+-----------+- Fortsetzung +----------------+---------------------+---------------------+---------------------+----------------+---------+ | Create_options | Comment | | Check_time | Update_time | Auto_increment | Create_time +----------------+---------------------+---------------------+---------------------+----------------+---------+ | | | | 2002-09-19 21:49:54 | 2002-09-19 21:49:54 | | 1 | | | | 2002-10-03 14:53:01 | 2002-10-03 15:04:05 | | | | | | 2002-09-19 21:49:54 | 2002-09-19 22:13:37 | | 9 | | | | 2002-09-19 21:49:54 | 2002-09-21 17:00:18 | | 5 | | | | 2002-09-19 21:49:54 | 2002-09-19 22:13:37 | | 5 | | | | 2002-09-19 21:49:54 | 2002-09-19 21:49:54 | | 1 | | | | 2002-09-19 21:49:54 | 2002-09-19 21:49:54 | | 1 | | | 2002-09-24 21:38:22 | 2002-09-24 21:38:22 | 2002-09-24 21:38:22 | | 6 | | | 2002-09-28 21:50:55 | 2002-09-28 21:50:55 | 2002-10-03 13:57:10 | | 5 | | | | 2002-09-19 21:49:54 | 2002-09-19 22:13:37 | | 6 | | | | 2002-09-19 21:49:54 | 2002-09-19 22:13:37 | | 5 | | | | 2002-09-19 21:49:54 | 2002-09-19 21:49:54 | | 1 +----------------+---------------------+---------------------+---------------------+----------------+---------+ Abbildung 5.3: Ausgabe von mysqlshow -i musikschule Gibt man Datenbank und Tabelle an, werden Informationen über die Spalten der Tabelle ausgegeben (siehe Abbildung 5.4). Diese Ausgabe erreicht man auch mit SHOW FULL COLUMNS FROM ... prompt>mysqlshow musikschule raum Database: musikschule Table: raum Rows: 5 +-----------+-----------------------+------+-----+---------+----------------+---------------------------------+ | Field | Type | Null | Key | Default | Extra | Privileges | +-----------+-----------------------+------+-----+---------+----------------+---------------------------------+ | raum_id | smallint(5) unsigned | | PRI | | auto_increment | select,insert,update,references | | raum_name | varchar(10) | | | | | select,insert,update,references | | etage | char(3) | YES | MUL | | | select,insert,update,references | | personen | mediumint(8) unsigned | YES | | 1 | | select,insert,update,references | +-----------+-----------------------+------+-----+---------+----------------+---------------------------------+ Abbildung 5.4: Ausgabe von mysqlshow musikschule raum Nutzt man zusätzlich den Parameter -k, werden auch noch Informationen über die Schlüssel der Tabelle ausgegeben, wie in Abbildung 5.5 zu sehen. Dies ist eine Kombination von SHOW FULL COLUMNS FROM ... mit SHOW INDEX FROM ... prompt>mysqlshow -k musikschule raum Database: musikschule Table: raum Rows: 5 +-----------+-----------------------+------+-----+---------+----------------+---------------------------------+ | Field | Type | Null | Key | Default | Extra | Privileges | +-----------+-----------------------+------+-----+---------+----------------+---------------------------------+ | raum_id | smallint(5) unsigned | | PRI | | auto_increment | select,insert,update,references | | raum_name | varchar(10) | | | | | select,insert,update,references | | etage | char(3) | YES | MUL | | | select,insert,update,references | | personen | mediumint(8) unsigned | YES | | 1 | | select,insert,update,references | +-----------+-----------------------+------+-----+---------+----------------+---------------------------------+ +-------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+---------+ | Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Comment | +-------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+---------+ | raum | 0 | PRIMARY | 1 | raum_id | A | 5 | | | | | raum | 1 | idx_etage | 1 | etage | A | 2 | | | | +-------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+---------+ Abbildung 5.5: Ausgabe von mysqlshow -k musikschule raum Gibt man auf einer der beschriebenen Ebenen einen Platzhalter an (wobei hier auch die Betriebssystem-Platzhalter * und ? zugelassen sind), werden diese wie ein LIKE ... umgesetzt: prompt>mysqlshow musikschule u* Database: musikschule Wildcard: u% +---------------+ | Tables | +---------------+ | unterricht | | unterricht_tn | +---------------+ Dies kann allerdings zu Problemen führen, wenn man zum Beispiel die Spalten der Tabelle unterricht_tn angezeigt bekommen möchte: prompt>mysqlshow musikschule unterricht_tn Database: musikschule Wildcard: unterricht_tn +---------------+ | Tables | +---------------+ | unterricht_tn | +---------------+ =XJULIIVP|JOLFKNHLWHQ Leider interpretiert mysqlshow die letzte Angabe als Angabe eines Filters mit Platzhaltern (wegen des Unterstrichs) und gibt nur alle Tabellen aus, die diesem Filter entsprechen. Umgehen kann man das Problem, indem man in solch einem Fall als zusätzlichen Wert noch ein einzelnes Prozentzeichen anfügt: prompt>mysqlshow musikschule unterricht_tn % Database: musikschule Table: unterricht_tn Rows: 4 Wildcard: % +------------------+------------------+------+-----+---------+-------... | Field | Type | Null | Key | Default | Extra ... +------------------+------------------+------+-----+---------+-------... | unterricht_tn_id | int(10) unsigned | | PRI | | | unterricht_id | int(10) unsigned | | | 0 | | schueler_id | int(10) unsigned | | | 0 | +------------------+------------------+------+-----+---------+-------... Damit wird die Angabe der Tabelle nicht mehr als Filter interpretiert, sondern nur die Angabe für die Spalten. Bei denen bewirkt das % aber natürlich, dass alle Spalten ausgegeben werden – also unser gewünschtes Ergebnis. 5.3 phpMyAdmin phpMyAdmin ist kein direktes Programm. Es handelt sich vielmehr um eine Sammlung von PHP-Seiten für einen Web-Server, mit denen sich MySQL-Server (auch aus der Ferne) administrieren und die Daten anzeigen lassen. Er bietet unter einer übersichtlichen Oberfläche viele Funktionen, die bei der Verwaltung von MySQL nützlich sind. phpMyAdmin Um phpMyAdmin nutzen zu können, benötigt man einen laufenden Web-Server mit PHP-Unterstützung. Dabei kann es sich um den Apache oder auch andere Server handeln. Der Server muss nicht mit dem MySQL-Server identisch sein, solange er Zugriff auf ihn bietet. Zum Einrichten eines Apache-Servers mit PHP-Unterstützung sei auf das spätere Kapitel über LAMP/WAMP verwiesen. Zur Installation lädt man sich am besten von http://www.phpmyadmin.net die entsprechenden Dateien herunter. Die Installationsdateien sind auch auf der beiliegenden CD-ROM enthalten. Im Unterverzeichnis phpMyAdmin finden Sie die Dateien phpMyAdmin-2.3.3pl1-php.zip für Windows und phpMyAdmin-2.3.3pl1php.tar.gz. SKS0\$GPLQ Es reicht, die Daten auszupacken (wobei auf die Verzeichnisstruktur Rücksicht genommen werden sollte) und an eine Stelle zu kopieren, auf die der Web-Server zugreifen kann. Unter Apache kann man die Daten zum Beispiel in das entsprechende Verzeichnis htdocs in ein Unterverzeichnis phpMyAdmin kopieren. In der dort vorhandenen Datei config.inc.php müssen nun noch einige wenige Eintragungen zum MySQLServer und den Anmeldeparametern vorgenommen werden. • $cfg['Servers'][$i]['host'] = 'hostname'; Hier wird der Name oder die IP-Adresse des MySQL-Servers eingetragen. • $cfg['Servers'][$i]['port'] = 'portnumber'; Falls sich der Port, unter dem der MySQL-Server läuft, von der Standardvorgabe 3306 unterscheidet, kann man hier die korrekte Portnummer angeben. Ansonsten kann man den Eintrag leer lassen. • $cfg['Servers'][$i]['user'] = 'username'; Angabe des Benutzernamens, mit dem sich phpMyAdmin am MySQL-Server anmelden soll. • $cfg['Servers'][$i]['password'] = 'password'; Angabe des Kennworts für den angegebenen Benutzer. • $cfg['PmaAbsoluteUri'] = 'url_string'; Dies ist die absolute Angabe der URL für das phpMyAdmin-Verzeichnis, zum Beispiel http://localhost/phpMyAdmin/. Dies ist nicht unbedingt erforderlich, da phpMyAdmin diesen Wert in den meisten Fällen auch automatisch ermitteln kann. Lässt man diesen Eintrag leer, gibt es auf der Startseite eine Warnung, die ausgeschaltet werden kann, wenn es auch automatisch funktioniert. Hat man die notwendigen Einstellungen vorgenommen, kann man die Startseite aufrufen. Befindet man sich direkt auf dem Web-Server und hat phpMyAdmin unter htdocs im Verzeichnis phpMyAdmin installiert, kann man es mit der URL http://localhost/phpMyAdmin/index.php aufrufen und erhält eine Webseite wie in Abbildung 5.6 zu sehen. =XJULIIVP|JOLFKNHLWHQ Abbildung 5.6: Startseite von phpMyAdmin Auf der Startseite kann man verschiedene Dinge erreichen: Im linken Rahmen lässt sich eine Datenbank auswählen. In der linken Spalte des rechten Rahmens gibt es einige Links auf Verwaltungstasks, die unabhängig von einer ausgewählten Datenbank sind (Erstellen einer neuen Datenbank, Informationen über den MySQL-Server oder die Benutzer anzeigen, MySQL-Server neu starten). Rechts lässt sich die Sprache von phpMyAdmin auswählen und man erreicht die Dokumentation. Der in eckigen Klammern angegebene Link auf Dokumentation führt direkt auf die entsprechenden Webseiten von http://www.mysql.com. Klickt man zum Beispiel auf Statistiken über alle Datenbanken, erreicht man die in Abbildung 5.7 dargestellte Seite. Hier lassen sich (wie an fast allen anderen Stellen auch, wo eine tabellarische Übersicht gezeigt wird) die Spaltentitel anklicken. Dadurch wird die Anzeige nach der entsprechenden Spalte sortiert. Klickt man die Überschrift ein zweites Mal an, wird die Tabelle nach dieser Spalte absteigend sortiert. SKS0\$GPLQ Abbildung 5.7: Statistiken über alle Datenbanken in phpMyAdmin Über die Auswahlbox im linken Rahmen gelangt man zu den einzelnen Datenbanken des Servers. Wählt man dort musikschule aus, gelangt man in eine Übersicht über diese Datenbank (siehe Abbildung 5.8). Mit einem Klick auf eine der angezeigten Tabellennamen erhält man eine Übersicht über die Struktur der Tabelle und einige statistische Daten (Abbildung 5.9). Von hier aus kann man eigentlich alles machen, was mit einer Tabelle sinnvoll ist: Ändern der Struktur, Eintragen von Daten, Analysieren der Inhalte, Exportieren, Importieren, Umbenennen und vieles mehr. Klickt man auf den Reiter Anzeigen, erhält man den Inhalt der Tabelle (siehe Abbildung 5.10). Dabei sind ein paar Dinge, die auch an vielen anderen Stellen vorkommen, erwähnenswert: • Es wird der zugrunde liegende SQL-Befehl mit Syntaxhighlighting angezeigt. Dieser Befehl lässt sich über Ändern anpassen. So kann man nebenbei etwas SQL lernen … • Man kann angeben, wie viele Datensätze angezeigt werden sollen. Zudem lässt sich festlegen, ob die Datensätze untereinander oder nebeneinander zu sehen sein sollen. • Für die einzelnen Spalten lassen sich Aktionen durchführen (hier: Ändern, Löschen). • Es gibt eine Druckansicht, die alle „Befehlslinks“ entfernt und eine sinnvoll druckbare Übersicht darstellt (siehe Abbildung 5.11). =XJULIIVP|JOLFKNHLWHQ Abbildung 5.8: Übersicht über die Datenbank musikschule in phpMyAdmin Abbildung 5.9: Übersicht über die Tabelle raum in phpMyAdmin SKS0\$GPLQ Abbildung 5.10: Inhalt der Tabelle raum in phpMyAdmin Abbildung 5.11: Druckansicht der Tabelle raum in phpMyAdmin All diese Optionen sind auch an vielen anderen Stellen vorhanden, so dass man sich schnell zurechtfindet. =XJULIIVP|JOLFKNHLWHQ phpMyAdmin ist ein sehr bequemes Hilfsmittel, um MySQL-Server und -Datenbanken zu administrieren. Fast alles, was man mit einem MySQLServer machen kann, lässt sich auch über diese grafische Oberfläche erreichen, zudem läuft es in (fast) jedem Browser und unter jedem Betriebssystem und ist zudem wunderbar für die Fernwartung nutzbar. 5.4 Import und Export Manchmal ist es notwendig, Daten aus der Datenbank auszulesen, um sie für andere Programme zu verwenden. Oder man möchte Daten aus einer anderen Quelle einlesen, um sie in seinen eigenen Applikationen zu nutzen. Natürlich kann man dafür eigene Programme schreiben, die Satz für Satz aus- bzw. einlesen und wegschreiben bzw. in die Datenbank eintragen. Es gibt allerdings einfachere und schnellere Methoden dafür. Um Daten im Text-Format zu speichern, kann man SELECT ... INTO ... nutzen. Umgekehrt lassen sich mit LOAD DATA INFILE Daten mit hoher Geschwindigkeit aus einer Text-Datei in die Datenbank einlesen. Das Programm mysqldump erzeugt SQL-Befehle, mit denen eine Datenbank oder Tabelle in einem anderen Datenbank-Server wieder angelegt werden kann. In die andere Richtung ist mysqlimport ein Tool, welches das Importieren von Text-Dateien wie mit LOAD DATA INFILE unterstützt. 5.4.1 SELECT ... INTO Um Daten in Textdateien zu exportieren, bietet sich der SELECT-Befehl an, dem als Erweiterung ein Ziel und verschiedene Format-Optionen mitgegeben werden. Die daraus erstellten Daten lassen sich auf ziemlich weitreichende Art anpassen, allerdings haben sie nie eine feste Breite (was man im Notfall allerdings mit einigen Tricks erreichen kann), sondern sind immer durch Trennzeichen unterteilt. SELECT INTO Die Syntax wurde schon weiter oben im Kapitel über SELECT beschrieben, hier nochmals ein Überblick über die Optionen. Prinzipiell geht es um einen normalen SELECT-Befehl, der beliebig kompliziert sein kann. Zusätzlich folgt nach Angabe der Spalten der Abschnitt INTO ... mit seinen Optionen: SELECT ... INTO {OUTFILE | DUMPFILE} 'file_name' [FIELDS [TERMINATED BY 'fielddiv'] [[OPTIONALLY] ENCLOSED BY 'enc_char'] [ESCAPED BY 'esc_char']] [LINES TERMINATED BY 'linedev'] FROM ... Normalerweise wird man SELECT ... INTO OUTFILE ... nutzen. Dies ist die „normale“ Version und sorgt für das Speichern aller selektierten Daten mit den entsprechenden Formatierungsoptionen in der gewünschten Datei. Verwendet man stattdessen SELECT ... INTO DUMPFILE ..., wird nur ein Datensatz in die Datei geschrieben, und zwar ohne Feldbegrenzer, Spaltenüberschriften oder Ähnliches. Man kann dies zum Beispiel dazu nutzen, den Inhalt eines Blob-Feldes direkt in einer Datei zu verewigen. Zu beachten ist, dass die Ergebnismenge auf jeden Fall nur einen Datensatz enthalten darf, ansonsten funktioniert das Ganze nicht. Sichergehen kann man, indem man die Option LIMIT 1 am Ende des SELECT-Befehls nutzt. Als Dateiname wird file_name verwendet. Diese Datei darf aus Sicherheitsgründen noch nicht existieren, sie wird auf jeden Fall neu angelegt. Ist sie schon vorhanden, schlägt der Aufruf fehl. Die Datei wird auf dem Server erstellt. Möchte man die Daten auf dem Client speichern, muss man einen anderen Weg gehen: entweder über mysql -e "SELECT ..." > file_name mit den entsprechend formatierten Spalten (siehe auch Kapitel 5.2.1) oder über das Programm mysqldump (siehe Kapitel 5.4.3). Gibt man nur den Dateinamen an, ohne weitere Formatierungsoptionen festzulegen, werden die Daten durch Tabulatorzeichen getrennt, ohne Anführungszeichen und mit dem Backslash (\) als Fluchtzeichen abgespeichert. Dabei wird pro Zeile ein Datensatz angelegt. Mit folgendem Befehl wird die Datei raum.txt auf dem Server erzeugt (sofern nicht schon vorhanden) und die Raum-Daten dort eingetragen: SELECT * INTO OUTFILE 'raum.txt' FROM raum; Die Datei raum.txt hat dann folgenden Inhalt (wobei zwischen den einzelnen Werten ein Tabulatorzeichen steht): 1 2 3 4 5 A5.33 B2.02 C4.16 A5.21 A5.23 5 2 4 5 5 4 20 11 6 6 Mit den folgenden Formatierungsoptionen lässt sich der Inhalt der Datei in einigen Dingen anpassen. FIELDS ändert das Ausgabeformat bezüglich der Feldwerte, während LINES das Verhalten beim Wechsel von einem Datensatz auf den nächsten festlegt. FIELDS TERMINATED • FIELDS TERMINATED BY 'fielddiv' Hiermit kann man festlegen, wie die Feldwerte untereinander getrennt werden sollen. Üblich sind das Tabulatorzeichen (Standardeinstellung, auch erreichbar durch '\t'), das Komma oder das =XJULIIVP|JOLFKNHLWHQ Semikolon. Man kann durchaus auch mehr als ein Zeichen angeben, es wird dann der gesamte String als Trenner genutzt. Dies ist zum Beispiel dann nützlich, wenn die Ausgabe „leserlicher“ sein soll: Man gibt nicht nur ein Komma an, sondern auch noch ein Leerzeichen danach: SELECT * INTO OUTFILE 'raum2.txt' FIELDS TERMINATED BY ', ' FROM raum; Das Ergebnis sieht dann so aus: 1, 2, 3, 4, 5, A5.33, B2.02, C4.16, A5.21, A5.23, 5, 2, 4, 5, 5, 4 20 11 6 6 • FIELDS [OPTIONALLY] ENCLOSED BY 'enc_char' FIELDS ENCLOSED Alle Feldwerte werden durch den enc_char umschlossen. Üblicherweise wird man hier das einfache oder doppelte Anführungszeichen nutzen, es sind aber auch andere denkbar, durchaus auch mehrere Zeichen (zum Beispiel '#*#'). Was für einen Vorteil hat es, Feldwerte zum Beispiel mit Anführungszeichen zu umschließen? Nun, ein Stringfeld kann alle möglichen Zeichen enthalten, unter anderem auch das Feldtrennzeichen. Ein Tabulatorzeichen ist vielleicht selten, aber wenn man das Komma als Feldtrenner nutzt, kann man schon bei Adressen Probleme bekommen. Das glauben Sie nicht? Dann kommen Sie mal nach Mannheim, dort gibt es in der Innenstadt keine Straßennamen (bis auf Ausnahmen), sondern nur Blöcke: A1, A2, ... A7, B1 usw. bis U7. Noch kein Problem, allerdings wird die Hausnummer meist durch ein Komma getrennt: P3, 6. Was macht das jetzt für Kummer? Geben wir doch einfach mal ein Beispiel aus. Zunächst fügen wir einen Satz mit entsprechender Adresse ein: INSERT INTO schueler (nachname, vorname, geburtsdatum, strasse, plz, ort, geschlecht) VALUES ('Herms', 'Georg', '1960-09-16', 'P3, 6', '68161', 'Mannheim', 0); Nun lassen wir uns eine Liste mit Namen und Adressen der Schüler ausgeben: SELECT nachname, vorname, strasse, plz, ort INTO OUTFILE 'komma.txt' FIELDS TERMINATED BY ',' FROM schueler; Das Ergebnis sieht so aus: Schmidt,Thomas,Hauptstr. 16,28219,Bremen Mayer,Anke,Leher Heerstr. 342,68219,Mannheim Meier,Frank,Waldweg 30,69190,Walldorf Schulze,Friederike,Relaisstr. 432,41564,Kaarst Herms,Georg,P3\, 6,68161,Mannheim Wie man sieht, ist das Komma nun mit einem Fluchtzeichen versehen. Dies ist beim anschließenden Weiterverarbeiten meist recht umständlich, manche Programme können gar nichts damit anfangen. Es kann auch sein, dass man das Fluchtzeichen aus anderen Gründen bewusst weglässt (siehe dazu weiter unten). Und dann wird es schwierig. In diesem Fall wird das verarbeitende Programm nämlich 6 als Postleitzahl und 68161 als Ort ansehen. Dumm, oder? Die Lösung liegt eben in ENCLOSED BY. Das Beispiel von eben, jetzt aber mit Anführungszeichen: SELECT nachname, vorname, strasse, plz, ort INTO OUTFILE 'komma2.txt' FIELDS TERMINATED BY ',' ENCLOSED BY '"' FROM schueler; Als Ergebnis erhält man jetzt: "Schmidt","Thomas","Hauptstr. 16","28219","Bremen" "Mayer","Anke","Leher Heerstr. 342","68219","Mannheim" "Meier","Frank","Waldweg 30","69190","Walldorf" "Schulze","Friederike","Relaisstr. 432","41564","Kaarst" "Herms","Georg","P3, 6","68161","Mannheim" Jeder Wert ist jetzt mit Anführungszeichen umschlossen, das Komma in P3, 6 nicht mehr mit einem Fluchtzeichen versehen. Damit können die meisten Programme etwas anfangen… Nun kann man einwenden, dass bei Zahlen nun wirklich kein Anführungszeichen notwendig ist. Es gibt keine besonders gefährlichen Zeichen, da kostet das nur Platz und macht auch etwas unübersichtlicher. Dazu kann man die Option OPTIONALLY nutzen: Sie sorgt dafür, dass nur String-Felder umschlossen werden: SELECT * INTO OUTFILE 'raum3.txt' FIELDS TERMINATED BY ', ' OPTIONALLY ENCLOSED BY '"' FROM raum; führt zu: 1, 2, 3, 4, 5, "A5.33", "B2.02", "C4.16", "A5.21", "A5.23", "5", "2", "4", "5", "5", 4 20 11 6 6 =XJULIIVP|JOLFKNHLWHQ Die Etage (als jeweils vorletzter Wert) ist hier mit Anführungszeichen umschlossen, da sie als String in der Datenbank abgespeichert ist. Wie man an den letzten Beispielen sieht, kann man bei FIELDS auch mehrere Optionen kombinieren. Es muss nur mindestens eine angegeben sein, sonst muss man auch FIELDS weglassen. • FIELDS ESCAPED BY 'esc_char' FIELDS ESCAPED Mit dieser Option kann man das Fluchtzeichen angeben. Standardmäßig handelt es sich um den Backslash (\), der dann vor allen besonders zu behandelnden Zeichen angegeben wird. Bei diesen Zeichen handelt es sich um den Backslash selber (daher muss er bei eigener Angabe auch als '\\' definiert werden), das Tabulatorzeichen, den Zeilenumbruch und der Feldtrenner innerhalb von Werten (sofern sie nicht durch Anführungszeichen umschlossen sind). Es lassen sich auch mehrere Zeichen angeben, von denen wird aber nur das erste verwendet. Will man das Fluchtzeichen unterdrücken, muss ein leerer String ('') angegeben werden. Dies funktioniert übrigens auch bei den anderen Optionen. • LINES TERMINATED BY 'linedev' LINES Durch diese Option ist es möglich, die einzelnen Datensätze durch besondere Zeichen zu trennen. Üblich ist der Zeilenumbruch ('\n'), man kann aber auch beliebige andere Werte angeben. So würde die Anweisung für einen Datensatztrenner #*# aussehen: TERMINATED SELECT raum_name INTO OUTFILE 'raum4.txt' LINES TERMINATED BY '#*#' FROM raum; Das Ergebnis wäre dann: A5.33#*#B2.02#*#C4.16#*#A5.21#*#A5.23#*# Es handelt sich hier nur um eine Zeile, da die Datensätze nur noch durch #*# getrennt sind, aber nicht mehr durch den Zeilenumbruch. Die Standardeinstellung lautet zusammengefasst wie folgt: FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' Zum Abschluss möchte ich noch ein Beispiel aus dem „richtigen“ Leben präsentieren, bei dem es um die geschickte Kombination von Funktionen, Formatoptionen und der Ausgabe geht: Es hat nichts mit der Musikschule zu tun, sondern basiert auf einer Frage in der Newsgroup de.comp.datenbanken.mysql von André Schleife. Er hatte in einer Tabelle Literaturverweise auf Artikel gespeichert, die er so in einer Datei spei- chern wollte, dass sich aus dieser mittels BibTeX (einem Tool für das Satzsystem LaTeX) ein Literaturverzeichnis erstellen ließ. Gegeben war eine Tabelle article mit dem Schlüssel ikey sowie den Feldern author, title, journal, year, pages, volume, number, URL und keywords. Diese sollten dann als Datei pro Datensatz wie folgt aussehen: @Article{ikey, author = {author}, title = {title}, journal = {journal}, year = {year}, pages = {pages}, volume = {volume}, number = {number}, URL = {URL}, keywords = {keywords} } @Article{ikey, ... Dabei entsprechen die kursiv geschriebenen Worte den Spaltennamen in der Tabelle. Erschwerend kam noch hinzu, dass Felder, die keinen Inhalt haben, nicht auftauchen sollen. Gelöst wurde das Ganze durch den folgenden Befehl: SELECT CONCAT('@Article{',ikey, IFNULL(CONCAT(',\n author = {',author),''), IFNULL(CONCAT('},\n title = {',title),''), IFNULL(CONCAT('},\n journal = {',journal),''), IFNULL(CONCAT('},\n year = {',year),''), IFNULL(CONCAT('},\n pages = {',page),''), IFNULL(CONCAT('},\n volume = {',volume),''), IFNULL(CONCAT('},\n number = {',number),''), IFNULL(CONCAT('},\n URL = {',URL),''), IFNULL(CONCAT('},\n keywords = {',keywords),''),'}\n}\n\n') INTO OUTFILE '/sqltest/literatur.td.bib' FIELDS ESCAPED BY '' FROM article ORDER BY ikey; Mittels CONCAT werden die einzelnen Strings und Felder zusammengesetzt. IFNULL sorgt dafür, dass nur dann eine Zeile entsteht, wenn das Feld auch Inhalt besitzt. Dabei wurde die Eigenschaft ausgenutzt, dass CONCAT immer dann NULL zurückliefert, wenn auch nur ein einzelner Wert der Parameterliste NULL ist. So ist CONCAT(',\n author = {', author) dann komplett NULL, wenn author alleine schon NULL ist. In diesem Fall wird der zweite Parameter von IFNULL zurückgeliefert, der hier ein Leer- =XJULIIVP|JOLFKNHLWHQ string ist. Auf diesem Weg werden überflüssige Leerzeilen vermieden, zugleich wird aber für die einzelnen Elemente nicht NULL, sondern ein leerer String zurückgeliefert. Dies ist deshalb nötig, weil sonst das oberste CONCAT auch NULL zurückgeben würde. FIELDS ESCAPED BY '' sorgt wiederum dafür, dass die per Hand eingefügten Zeilenumbrüche (\n) nicht wieder mit einem Backslash maskiert werden. Als Ergebnis erhält man jetzt folgenden Text, der wunderbar mit BibTeX weiterverarbeitet werden kann: @Article{eppler:92, author = {D. T. Eppler et al.}, title = {Passive Microwave Signatures of Sea Ice}, journal = {Geophysical Monograph}, year = {1992}, pages = {300--302}, volume = {68}, keywords = {microwave signatures} } @Article{fuhrhop:96, author = {R. Fuhrhop and C. Simmer}, title = {SSM/I Brightness Temperature Corrections for Incidence Angle Variantions}, journal = {Journal of Atmospheric and Oceanic Technology}, year = {1996}, pages = {230--235}, volume = {13}, number = {1}, keywords = {temperature corrections} } @Article{hartmann:96, author = {J. Hartmann et al.}, title = {Radiation and Eddy Flux Experiment 1995 (REFLEX III)}, journal = {Berichte zur Polarforschung}, year = {1996}, pages = {147--155}, volume = {218}, URL = {www.awi-bremerhaven.de}, keywords = {REFLEX III} } Setzt man das Ergebnis schließlich in LaTeX um, erhält man die gewünschte Ausgabe in Abbildung 5.12: So konnten Daten aus den verschiedenen jahreszeitlichen Situationen gewonnen werden [2]. Dabei ist zu bedenken, daß alleine dem SSM/I-Sensor schon ein Fehler von etwa 2 K zuzuordnen ist [3]. Aus [1] wurden dann für diesen Eistyp die entsprechenden Emissivitäten ermittelt und in (für MWMOD notwendige) Reflektivitäten umgerechnet. Literatur [1] D. T. Eppler et al. Passive Microwave Signatures of Sea Ice. Geophysical Monograph, 68:300–302, 1992. [2] J. Hartmann et al. Radiation and Eddy Flux Experiment 1995 (REFLEX III). Berichte zur Polarforschung, 218:147–155, 1996. [3] R. Fuhrhop and C. Simmer. SSM/I Brightness Temperature Corrections for Incidence Angle Variantions. Journal of Atmospheric and Oceanic Technology, 13(1):230–235, 1996. Abbildung 5.12: Ausgabe der LaTeX-Datei mit dem Literaturverzeichnis 5.4.2 LOAD DATA INFILE LOAD DATA Für den umgekehrten Weg, das Einlesen von Textdaten in eine MySQLTabelle, gibt es den Befehl LOAD DATA INFILE. Mit ihm kann man Dateien des Typs einlesen, die sich auch mit SELECT ... INTO erzeugen lassen, auch die Parameter sind zum Teil identisch. Seine Syntax lautet: LOAD DATA [LOW_PRIORITY | CONCURRENT] [LOCAL] INFILE 'file_name' [REPLACE | IGNORE] INTO TABLE tbl_name [FIELDS [TERMINATED BY 'fielddiv'] [[OPTIONALLY] ENCLOSED BY 'enc_char'] [ESCAPED BY 'esc_char' ] ] [LINES TERMINATED BY 'linediv'] [IGNORE number LINES] [(col_name,...)] Die kürzeste gültige Variante ist hier LOAD DATA INFILE 'file_name' INTO TABLE tbl_name; Dabei werden die Daten aus der Textdatei file_name in die Tabelle tbl_name eingelesen. Die Feldwerte müssen durch Tabulatoren getrennt =XJULIIVP|JOLFKNHLWHQ werden, dürfen nicht mit Anführungszeichen umschlossen sein und das Fluchtzeichen ist der Backslash (\). Die einzelnen Datensätze sind durch Zeilenumbrüche getrennt. Die solchermaßen eingelesenen Daten wandern dann in die Tabelle tbl_name, wobei alle Felder in der richtigen Reihenfolge schon in der Datei vorhanden sein müssen und auch keine überflüssigen Zeilen am Anfang der Datei existieren dürfen. Die schon existierenden Schlüsselwerte in der Tabelle dürfen in der Datei nicht nochmals vorkommen, da es ansonsten eine Fehlermeldung gibt. Natürlich kann man sehr viele Änderungen am Standardverhalten vornehmen: • LOW_PRIORITY | CONCURRENT Gibt man als Option LOW_PRIORITY an, werden nur dann Daten in die Zieltabelle geschrieben, wenn sonst niemand mehr auf sie zugreift. Umgekehrt kann man mit CONCURRENT dafür sorgen, dass auch während des Einfügens von Daten mittels LOAD DATA INFILE andere Clients auf die Tabelle zugreifen können, was allerdings nur mit MyISAMTabellen möglich ist. • LOCAL Normalerweise sucht MySQL die Datei auf dem Server. Mit der Angabe von LOCAL wird der Client-Rechner als Grundlage genommen. Allerdings muss man sich darüber im Klaren sein, dass das Laden der Daten dann länger dauert, weil schließlich die Textdatei erst an den Server übertragen werden muss. • REPLACE | IGNORE Standardverhalten von LOAD DATA INFILE ist, dass es keine Konflikte zwischen den Schlüsselwerten der neu einzulesenden Daten und denen der schon vorhandenen Daten in der Tabelle geben darf. Passiert dies doch (d.h., ein neu einzutragender Datensatz aus der Datei besitzt einen Schlüssel, der schon in der Tabelle existiert), bricht die Verarbeitung mit einer Fehlermeldung ab. Dies entspricht dem Verhalten von INSERT INTO ... Mittels REPLACE kann man nun dafür sorgen, dass die Daten trotzdem eingetragen werden; bestehende Datensätze mit dem entsprechenden Schlüssel werden dadurch überschrieben. Durch diese Option wird also das Verhalten des Befehls REPLACE INTO ... nachgebildet. Nutzt man stattdessen IGNORE, werden vorhandene Daten nicht überschrieben, es wird aber auch keine Fehlermeldung ausgegeben. Damit bleiben alte Daten bestehen, noch nicht vorhandene werden aber trotzdem eingetragen – wie bei INSERT IGNORE INTO... • FIELDS TERMINATED BY 'fielddiv' [OPTIONALLY] ENCLOSED BY 'enc_char' ESCAPED BY 'esc_char' LINES TERMINATED BY 'linediv' Diese Optionen entsprechen exakt denen bei SELECT ... INTO, bis auf die Ausnahme, dass enc_char und esc_char nur aus jeweils einem einzelnen Zeichen bestehen dürfen (wenn man sie nicht leer lässt). Zudem ist es nicht zulässig, fielddiv und enc_char gleichzeitig leer zu lassen. Dies entspräche einer Textdatei mit festen Spaltenbreiten, was nicht unterstützt wird. • IGNORE number LINES Mit dieser Angabe werden die ersten number Zeilen am Anfang der Datei ignoriert. Damit kann man Zeilen überspringen, die Spaltenüberschriften oder andere Angaben zu den Daten enthalten. • (col_name, ...) Auf diesem Weg kann man die zu befüllenden Spalten der Tabelle in der entsprechenden Reihenfolge angeben, in der sie in der Datei auftauchen. Dies kann dann nützlich sein, wenn man nicht alle Spalten der Tabelle befüllen will oder die Daten in der Datei in der falschen Reihenfolge stehen. Felder, die nicht gefüllt werden – entweder, weil sie in der Spaltenliste nicht mit aufgeführt wurden, oder weil einfach nicht genug Werte pro Datensatz vorhanden sind – erhalten ihren Standardwert. Gibt es hingegen zu viele Werte pro Datensatz in der Datei, werden diese ignoriert und die Anzahl der Warnungen dementsprechend erhöht. Als Beispiel wollen wir unsere Musikschul-Datenbank mit den gültigen Bankleitzahlen ergänzen. Die Daten mögen zwar nicht unbedingt zwingend wichtig sein, sie sind aber ein schönes Beispiel für das Einlesen externer Daten nach MySQL. Zudem kann man die Daten kostenlos im Internet erhalten. Leider handelt es sich dabei um eine Datei mit fester Feldlänge und ohne Feldtrenner. Aber auch dies lässt sich mit Hilfe einer Zwischentabelle lösen. Auf den Web-Seiten der Bundesbank gibt es unter http://www.bundesbank.de/zv/zv_bankleitzahlen.htm einen Link „Download der Bankleitzahlen-Dateien“ zum Herunterladen der Bankleitzahlen. Es gibt verschiedene Varianten, uns interessiert hier aber die PC/Text-Version. Die hier genutzte Datei hat den Namen blz0209pc.exe. Dabei steht 0209 für die Gültigkeit ab September 2002, eventuell gibt es bereits neuere Versionen. Die Datei ist eine selbstentpackende Zip-Datei. Sie kann auch unter Linux mittels unzip ausgepackt werden. Als Ergebnis erhält man eine Text- =XJULIIVP|JOLFKNHLWHQ datei (hier blz0209pc.txt) und ein Word-Dokument mit der Beschreibung über den Aufbau der Daten (satzaufbaupc188.doc). Auch diese Datei lässt sich notfalls unter Linux öffnen, entweder, indem man OpenOffice oder StarOffice nutzt oder sie sich ganz rudimentär mit strings satzaufbaupc188.doc ausgeben lässt. Aus dieser Beschreibung kann man nun den Aufbau der Daten entnehmen. Da es sich allerdings um Felder fester Länge handelt, bleibt uns zunächst nichts anderes übrig, als die Daten „am Stück“ in eine Zwischentabelle zu importieren. Aus dieser Tabelle kann man dann mit den SQLFunktionen die „richtige“ BLZ-Tabelle mit den „richtigen“ Feldern befüllen. Der Dokumentation entnehmen wir, dass die Daten pro Satz insgesamt 188 Zeichen lang sind. Also erzeugen wir eine Tabelle mit einem Feld dieser Länge: CREATE TABLE blz_import (satz CHAR(188)); Nun können wir für den ersten Schritt die Daten importieren. mysql> LOAD DATA INFILE 'blz0209pc.txt' -> INTO TABLE blz_import; Query OK, 21104 rows affected (0.39 sec) Records: 21104 Deleted: 0 Skipped: 0 Warnings: 0 Wie man sieht, geht das Einlesen der Datei wirklich schnell – gerade mal 0,39 Sekunden haben die 21.104 Sätze benötigt. Allerdings sind wir noch nicht fertig, schließlich müssen die Daten noch in die richtige Tabelle kopiert werden. Diese legen wir erst einmal an, wobei als Vorlage für die Felder die Beschreibung der Datenstruktur dient. Dabei nutzen wir nur die Felder, die wir später auch nutzen wollen: die Bankleitzahl selber und der längere Name der Bank. CREATE TABLE bankleitzahl (blz CHAR(8), bank_name VARCHAR(58), INDEX (blz), INDEX (bank_name)); Es wurde kein Primärschlüssel angelegt, da es durchaus mehrfache Kombinationen von BLZ und Name gibt. Nun können wir die Daten aus der Import-Tabelle übertragen: mysql> INSERT INTO bankleitzahl -> (blz, bank_name) -> SELECT DISTINCT LEFT(satz, 8), MID(satz, 28, 58) -> FROM blz_import -> WHERE LEFT(satz, 8) > '00000000'; Query OK, 6401 rows affected (0.56 sec) Records: 6401 Duplicates: 0 Warnings: 0 Durch den Einsatz der Zwischentabelle und den Funktionen LEFT() und MID() haben wir trotz fester Feldlänge die Daten sinnvoll und ziemlich schnell importieren können. Wie man sieht, wurden nun nur noch 6.401 Sätze in die eigentliche BLZ-Tabelle übertragen. Das liegt zum einen daran, dass wir mit der WHERE-Bedingung alle zu löschenden Bankleitzahlen ausgeschlossen haben, zum anderen und vor allem aber daran, dass die diversen einzelnen Geschäftsstellen nicht mit aufgenommen wurden. Durch das DISTINCT wurde verhindert, dass eine Satzkombination mehrfach vorkommt. Man kann nun diese Tabelle dazu nutzen, Bankleitzahlen oder Banknamen automatisch heraussuchen und vorschlagen zu lassen, wenn man Kontodaten in einer Applikation für die Musikschule einträgt. Durch die Indizes auf blz und bank_name ist diese Suche auch ziemlich schnell. 5.4.3 mysqldump mysqldump Um Daten aus einem MySQL-Server zu exportieren, kann man auch das Programm mysqldump nutzen. Es liest die Struktur und die Daten einer oder mehrerer Datenbanken oder Tabellen aus und schreibt sie in eine Datei. Mit dieser kann man die entsprechenden Strukturen danach wieder erneut aufbauen (sei es auf einem anderen Server oder auf dem gleichen Server zum Beispiel nach einer Neuinstallation) und die Daten eintragen lassen. Selbst das Erstellen der Datenbank selber wird auf Wunsch übernommen. Beim Aufruf des Programms kann man eine der drei folgenden SyntaxVarianten nutzen: mysqldump [OPTIONS] database [tables] mysqldump [OPTIONS] --databases [OPTIONS] DB1 [DB2 DB3...] mysqldump [OPTIONS] --all-databases [OPTIONS] In der ersten Variante gibt man eine Datenbank an, dazu die Tabellen, die exportiert werden sollen. Lässt man die Angabe der Tabellen weg, werden alle Tabellen der Datenbank exportiert. Die zweite Variante erlaubt die Auswahl mehrerer Datenbanken, für die alle Tabellen exportiert werden. Zusätzlich werden mit den erzeugten SQL-Befehlen die Datenbanken erstellt und vor dem Anlegen und Befüllen der Tabellen in diese gewechselt. In der dritten Variante schließlich werden alle Datenbanken exportiert. Die Optionen sind in Tabelle 5.3 aufgeführt. =XJULIIVP|JOLFKNHLWHQ Kurze Version Lange Version Beschreibung -A --all-databases Exportiere alle Datenbanken des Servers. -a --all Nutze alle CREATE-Optionen von MySQL. -# --debug=... Ablauf des Programms protokollieren und verfolgen --character-setsdir=... Angabe des Verzeichnisses, in dem die Zeichensatzbeschreibungen abgelegt sind -? --help Ausgabe der Hilfe-Informationen -B --databases Ausgabe mehrerer Datenbanken, die nach den Optionen aufgeführt werden müssen (siehe zweite Syntaxvariante) -c --complete-insert INSERT-Befehle werden komplett mit den Spaltennamen erzeugt. -C --compress Nutzung der Datenkompression bei der Kommunikation zwischen Client und Server --defaultcharacter-set=... Angabe des Standard-Zeichensatzes --extended-insert Nutzung der Angabe mehrerer Datensätze mit einem INSERT-Befehl --add-drop-table Aufnahme des Befehls DROP TABLE vor dem Erstellen der Tabelle --add-locks Hinzufügen von LOCK TABLE vor den INSERTBefehlen und UNLOCK TABLE danach. Dadurch wird das Einfügen von Datensätzen beschleunigt. --allow-keywords Es können Schlüsselwörter als Spaltennamen genutzt werden, indem jedem Spaltenname der Tabellenname vorangestellt wird. --delayed-insert Einfügen von Daten mittels INSERT DELAYED. --master-data Hinzufügen von Ort und Dateiname des Masters bei verteilten Datenbanken -F --flush-logs Wegschreiben der Log-Dateien, bevor mit dem Export begonnen wird -f --force auch bei einem Fehler mit dem Exportieren fortfahren -h --host=... Angabe des MySQL-Servers -l --lock-tables Sperren aller Tabellen vor dem Exportieren --no-autocommit Hinzufügen von Befehlen zum Deaktivieren des Autocommits und dem Bestätigen am Ende der INSERT-Befehle. --disable-keys Deaktivieren der Schlüssel vor dem Eintragen der Daten und nachträgliches Aktivieren. Dies kann das Erstellen der Daten an ihrem neuen Ort beschleunigen. -e -K Tabelle 5.3: Optionen von mysqldump Kurze Version Lange Version Beschreibung -n --no-create-db Die Befehle zum Anlegen der Datenbanken werden nicht mit ausgegeben. -t --no-create-info Die Befehle zum Anlegen der Tabellen werden nicht mit ausgegeben. -d --no-data Es werden nur die Strukturen exportiert. -O --set-variable var=option Setzen von Variablen --opt Schnellstmögliche Variante zum Exportieren und Importieren von Daten. Diese Option entspricht der gemeinsamen Nutzung von --add-drop-table --add-locks --all --quick --extended-insert --lock-tables --disable-keys -p --password[=...] Angabe des Kennworts oder Abfrage -W --pipe Verwendung von Named Pipes für die Kommunikation mit dem Server -P --port=... Angabe des Ports, über den sich der Client mit dem MySQL-Server verbinden soll -q --quick direkte Ausgabe der Befehle ohne Pufferung -Q --quote-names Umschließen von Tabellen- und Spaltennamen mit dem umgekehrten einfachen Anführungszeichen (`) -r --result-file=... Ausgabe in die angegebene Datei statt auf die Standardausgabe -S --socket=... Angabe der zu verwendenden Socket-Datei --tables Überschreiben der Option --databases -T --tab=... Ausgabe der Daten als Textdatei. Für jede Tabelle werden zwei Dateien erstellt: eine SQL-Datei mit den Befehlen zum Anlegen der Struktur und eine Textdatei mit den Daten. Diese können später mit LOAD DATA INFILE eingelesen werden. Erstellt werden die Dateien im angegebenen Verzeichnis. Die Textdateien lassen sich wie bei SELECT INTO formatieren, dazu dienen die entsprechenden Optionen, die am Ende der Tabelle beschrieben sind. -u --user=... Angabe des Benutzers, der sich anmelden soll -v --verbose ausführlichere Ausgabe von Informationen während des Exportierens -V --version Ausgabe der Version und Beenden des Programms -w --where=... Angabe von WHERE-Bedingungen, die für die auszugebenden Datensätze erfüllt sein müssen. Anführungszeichen sind notwendig. Tabelle 5.3: Optionen von mysqldump (Forts.) =XJULIIVP|JOLFKNHLWHQ Kurze Version Lange Version Beschreibung -X --xml Ausgabe der Daten als wohlgeformte XMLDatei -x --first-slave Sperren aller Datensätze in allen Datenbanken (bei verteilten Systemen) --fieldsterminated-by=... Angabe der Feldtrenner bei --tab. Standard ist \t. --fieldsenclosed-by=... Angabe der Quoting-Zeichen bei --tab --fields-optionally-enclosed-by=... Angabe der optionalen Quoting-Zeichen bei --tab --fields-escapedby=... Angabe des Fluchtzeichens bei --tab --linesterminated-by=... Angabe der Datensatztrenner bei --tab. Standard ist \n. Tabelle 5.3: Optionen von mysqldump (Forts.) Standardmäßig werden die SQL-Befehle direkt in die Standardausgabe geschrieben. prompt>mysqldump musikschule -- MySQL dump 8.22 --- Host: localhost Database: musikschule ---------------------------------------------------------- Server version3.23.51-nt --- Table structure for table 'ausleihe' -CREATE TABLE ausleihe ( ausleihe_id int(10) unsigned NOT NULL auto_increment, leihinstrument_id int(10) unsigned NOT NULL default '0', schueler_id int(10) unsigned NOT NULL default '0', datum_von date NOT NULL default '0000-00-00', datum_bis date default NULL, PRIMARY KEY (ausleihe_id) ) TYPE=MyISAM; --- Dumping data for table 'ausleihe' ---- Table structure for table 'instrument' -- CREATE TABLE instrument ( instrument_id int(10) unsigned NOT NULL auto_increment, instr_name varchar(50) NOT NULL default '', instr_gruppe varchar(50) default NULL, PRIMARY KEY (instrument_id) ) TYPE=MyISAM; --- Dumping data for table 'instrument' -- INSERT INSERT INSERT INSERT INSERT INSERT INSERT INSERT ... INTO INTO INTO INTO INTO INTO INTO INTO instrument instrument instrument instrument instrument instrument instrument instrument VALUES VALUES VALUES VALUES VALUES VALUES VALUES VALUES (1,'Querflöte','Holzbläser'); (2,'Klarinette','Holzbläser'); (3,'Violine','Streicher'); (4,'Viola','Streicher'); (5,'Posaune','Blechbläser'); (6,'Trompete','Blechbläser'); (7,'Klavier','Tasten'); (8,'Keyboard','Tasten'); Diese lässt sich natürlich in eine Datei umbiegen: prompt>mysqldump musikschule > musikschule.sql Oder man nutzt die Option -r bzw. --result-file: prompt>mysqldump --result-file=musikschule.sql musikschule Solch eine erzeugte Datei kann man mit mysql auf einem anderen Server wieder einlesen: prompt>mysql musikschule < musikschule.sql Möchte man die Daten später mit mysqlimport wieder einlesen (siehe Kapitel 5.4.4), muss man mit der Option --tab arbeiten. Die Daten werden dann in Dateien geschrieben, die gleich den richtigen Namen besitzen: prompt>mysqldump --tab=musikschule musikschule Damit werden in das Verzeichnis musikschule Dateien für alle Tabellen der Datenbank musikschule geschrieben. Um Daten von einem MySQL-Server auf einen anderen zu verschieben, kann man auch eine andere, elegantere Möglichkeit nutzen. Dazu sollte man sich auf dem Server mit dem Ausgangspunkt der Daten befinden. Dann kann man die Ausgabe des Programms gleich als Eingabe für mysql auf dem Zielserver nutzen: =XJULIIVP|JOLFKNHLWHQ prompt>mysqldump --opt musikschule | mysql --h remotehost -C musikschule Durch --opt wird der schnellstmögliche Weg zum Exportieren gewählt, während -C dafür sorgt, dass die Kommunikation mit dem entfernten Rechner komprimiert vonstatten geht. 5.4.4 mysqlimport Mit dem Programm mysqlimport kann man – genau wie bei LOAD DATA INFILE – Daten aus Textdateien in die Datenbank laden. Im Grunde genom- mysqlimport men stellt mysqlimport nur eine Kommandozeilenschnittstelle für den SQL-Befehl bereit. Viele Optionen sind identisch zu denen von LOAD DATA INFILE. Der Aufruf des Programms geschieht mit der folgenden Syntax: mysqlimport [OPTIONS] database textfile1 [textfile2 ...] Von den angegebenen Textdateien werden alle vorhandenen Erweiterungen abgeschnitten und der eigentliche Dateiname als Name der Tabelle genommen, in die die Daten aus der entsprechenden Datei importiert werden sollen. So würden zum Beispiel die Daten der Datei unterricht.txt in die Tabelle unterricht importiert werden. Die verwendete Datenbank muss auch mit angegeben werden. Als mögliche Optionen stehen die in Tabelle 5.4 aufgeführten bereit. Viele sollten bereits bekannt sein. Kurze Version Lange Version Beschreibung -# --debug[=...] Ablauf des Programms protokollieren und verfolgen -? --help Ausgabe der Hilfe-Informationen –-default-character-set=... Angabe des Standard-Zeichensatzes --character-setsdir=... Angabe des Verzeichnisses mit den Zeichensätzen -c –-columns=... Angabe der Spalten, die für den Import genutzt werden sollen. Diese Option entspricht dem Passus (col_name, ...) in LOAD DATA INFILE. -C –-compress Nutzung der Datenkompression bei der Kommunikation zwischen Client und Server -d –-delete Die zu befüllenden Tabellen werden vor dem Import geleert. -f –-force Der Import soll weitergehen, auch wenn ein Fehler aufgetreten ist. Existiert zum Beispiel eine Tabelle nicht, wird das Programm ohne diese Option abgebrochen. Tabelle 5.4: Optionen von mysqlimport Kurze Version Lange Version Beschreibung -h –-host=... Angabe des MySQL-Servers -i –-ignore Zu importierende Daten mit Schlüsseln, die in der Tabelle schon vorhanden sind, werden ignoriert. Dies entspricht der Option IGNORE bei LOAD DATA INFILE. -l –-lock-tables Sperren aller Tabellen des Servers bevor der Import beginnt. Damit ist sichergestellt, dass alle Tabellen synchron sind. -L –-local Die Dateien werden auf dem Client eingelesen und zum Server übertragen. Ohne diese Angabe werden die Daten auf dem Server gesucht. –-low-priority Die Daten werden mit geringerer Priorität in die Tabellen geschrieben (entspricht LOW_PRIORITY bei LOAD DATA INFILE). -p –-password[=...] Angabe des Kennwortes für den Benutzer oder Abfragen bei Nichtangabe -W –-pipe Nutzung von Named Pipes für die Kommunikation zwischen Client und Server -r –-replace Existieren schon Daten in der Tabelle mit Schlüsseln, die auch in der Datei vorkommen, werden die bestehenden Daten überschrieben. Dies entspricht der Option REPLACE in LOAD DATA INFILE. -s –-silent „Stille“ Arbeitsweise. Es werden nur Fehlermeldungen ausgegeben. -S –-socket=... Angabe der zu verwendenden Socket-Datei -u –-user=... Angabe des Benutzers, der angemeldet werden soll -v –-verbose ausführliche Statusausgaben während des Programmlaufs -V –-version Ausgabe der Versionsangaben und Beenden des Programms --fieldsterminated-by=... Angabe der Feldtrenner. Standard ist \t. --fieldsenclosed-by=... Angabe der Quoting-Zeichen --fields-optionally-enclosed-by=... Angabe der optionalen Quoting-Zeichen --fields-escapedby=... Angabe des Fluchtzeichens --lines-terminated-by=... Angabe der Datensatztrenner. Standard ist \n. Tabelle 5.4: Optionen von mysqlimport (Forts.) =XJULIIVP|JOLFKNHLWHQ Möchte man also nun Daten importieren, kann man wie folgt vorgehen: prompt>cd musikschule prompt>mysqlimport --delete musikschule ausleihe.txt instrument.txt musikschule.ausleihe: Records: 0 Deleted: 0 Skipped: 0 Warnings: 0 musikschule.instrument: Records: 8 Deleted: 0 Skipped: 0 Warnings: 0 Durch --delete oder -d wird dafür gesorgt, dass keine alten Daten in den Tabellen verbleiben. Das möchte man natürlich ab und an gerne haben, in diesem Fall aber geht es eben um den direkten Import der alten Daten. Im Folgenden wird dann für jede Tabelle angegeben, wie viele Datensätze importiert wurden, ob es doppelte gab und ob Warnungen auftraten. Möchte man mehr über den aktuellen Status der Verarbeitung erfahren, kann man die Option --verbose oder -v nutzen: prompt>mysqlimport -d -v musikschule ausleihe.txt instrument.txt Connecting to localhost Selecting database musikschule Deleting the old data from table ausleihe Loading data from file: ausleihe.txt into ausleihe musikschule.ausleihe: Records: 0 Deleted: 0 Skipped: 0 Warnings: 0 Deleting the old data from table instrument Loading data from file: instrument.txt into instrument musikschule.instrument: Records: 8 Deleted: 0 Skipped: 0 Warnings: 0 Disconnecting from localhost 5.5 Schnittstellen Es ist nun sicherlich sehr praktisch, die verschiedensten Programme zur Verfügung zu haben, um auf den MySQL-Server und dessen Daten zugreifen zu können. Allerdings sind dies alles Programme, die nicht unbedingt sinnvoll für einen Endbenutzer sind. Dieser erwartet eine Oberfläche, die die Daten sinnvoll angeordnet anzeigt, Eingabeprüfungen vornimmt und einfache Suchmöglichkeiten anbietet. Zudem sollte die Ablauf- oder Geschäftslogik unter der Oberfläche verborgen sein und nicht vom Benutzer selber beachtet werden müssen („Immer, wenn ein Kunde mehr als _ 10.000 Umsatz pro Jahr macht, erhält er automatisch 3% Rabatt.“). Das Programm kann MySQL einem natürlich nicht zur Verfügung stellen. Dafür ist der Applikationsentwickler selber verantwortlich. Aber um auf die Datenbank zugreifen zu können, benötigt er Schnittstellen. Es gibt sie für die verschiedensten Programmiersprachen. Ich möchte hier die am häufigsten genutzten vorstellen: Perl und C++ sowie allgemeiner und sprachunabhängiger MyODBC. PHP wird auch sehr häufig 6FKQLWWVWHOOHQ für die Anbindung eines Web-Servers an eine MySQL-Datenbank genutzt. Da es dafür aber ein eigenes Kapitel gibt, werde ich hier nicht näher darauf eingehen. 5.5.1 Perl Perl ist eine ideale interpretierende Programmiersprache, um kleine (und auch größere) Skripten zu schreiben. Sie sind schnell erstellt, trotzdem aber auch flexibel und vor allem die Fähigkeiten zur Zeichenkettenverarbeitung sind sehr umfangreich. Die zentrale Stelle für Perl im Internet ist http://www.perl.com. Während unter Linux und anderen Unix-Derivaten Perl meist schon vorhanden ist, muss man es sich unter Windows erst installieren. Dafür findet man unter http://www.activestate.com/ActivePerl quasi die Perl-Version für Windows. Auf der beiliegenden CD-ROM finden Sie im Verzeichnis Perl die MSIInstallationsdatei für ActivePerl unter Windows. Der Dateiname lautet ActivePerl-5.6.1.633-MSWin32-x86.msi. Der Zugriff auf MySQL mit Perl geschieht über die Schnittstelle DBI. Dies ist eine universelle Datenbankschnittstelle für Perl und unterstützt unter anderem auch MySQL. Es gibt noch andere, ältere Zugriffsvarianten, aber mittlerweile sollte man auf jeden Fall DBI nutzen. Falls DBI und der MySQL-Zugriff unter Linux noch nicht vorhanden sind, muss man sich die entsprechenden Module von http:// www.mysql.com/Downloads/Contrib/ herunterladen. Mindestens notwendig sind Data-Dumper, DBI und msql-mysql-modules. Die entsprechenden Dateien Data-Dumper-2.101.tar.gz, DBI-1.18.tar.gz und MsqlMysql_modules-1.2216.tar.gz finden Sie auch auf der beiligenden CDROM im Verzeichnis Perl. Dabei handelt es sich um komprimierte Tar-Archive, die mittels prompt> gunzip < MODULE-VERSION.tar.gz | tar xvf - ausgepackt werden können. MODULE-VERSION steht dabei für eines der aufgeführten Module einschließlich der Versionsbezeichnung. Danach wechselt man in das entsprechende Verzeichnis des Moduls: prompt> cd MODULE-VERSION =XJULIIVP|JOLFKNHLWHQ Dort baut man die Distribution und kompiliert alles: prompt> prompt> prompt> prompt> perl Makefile.PL make make test make install Zu beachten ist noch, dass make test für msql-mysql-modules nur dann erfolgreich funktionieren wird, wenn der MySQL-Server läuft. Um DBI und die Unterstützung für MySQL unter Windows zu installieren, müssen Sie den PPM (Programmer's Package Manager) von ActivePerl aufrufen. Er benötigt eine Internetverbindung oder – falls vorhanden – Zugriff auf ein lokales Repository (wie zum Beispiel die CD von ActiveState). prompt>ppm Nun kann DBI installiert werden: ppm> install DBI Ist dies erfolgreich geschehen, kann man die MySQL-Unterstützung installieren (bitte den folgenden Befehl auf einer Zeile eingeben): ppm> install ftp //ftp.de.uu.net/pub/CPAN/authors/id/JWIED/DBD-mysql-1.2212.x86.ppd Mit ppm> exit wird der PPM beendet und es steht die DBI und der MySQL-Support zur Verfügung. Ein einfaches Perl-Programm, welches auf unsere Datenbank zugreift, sieht so aus: #! /usr/bin/perl # mysql01.pl - Einfaches Beispiel zum Verbinden mit MySQL use DBI; use strict; :my ($dsn) = "DBI:mysql:musikschule"; # Verbindungstyp und Datenbankname my ($user_name); # Benutzername (hier leer) my ($password); # Kennwort (hier leer) my ($dbh, $sth); # Verbindungshandle, Query-Handle my ($query); # SELECT-Befehl my (@ary); # Datensatz 6FKQLWWVWHOOHQ # Verbindung aufbauen $dbh = DBI->connect($dsn, $user_name, $password, {RaiseError => 1}); #SELECT-Befehl definieren $query = "SELECT raum_id, raum_name, etage, personen " ."FROM raum ORDER BY raum_name"; # Anfrage vorbereiten und ausführen $sth = $dbh->prepare($query); $sth->execute(); # Spaltenüberschriften ausgeben print "raum_id\traum_name\tetage\tpersonen\n\n"; # Schleife über alle Datensätze while(@ary = $sth->fetchrow_array()) { # Ausgabe des Datensatzes print join("\t", @ary), "\n"; } # Freigeben des Query-Handles $sth->finish(); # Verbindung beenden $dbh->disconnect(); exit(0); Sie finden das Skript mit dem Dateinamen mysql01.pl auf der beiliegenden CD-ROM. Ich möchte hier nicht die Programmierung mit Perl an sich erklären. Aber anhand dieses Beispielprogramms will ich auf die Elemente eingehen, die für DBI notwendig sind. #! /usr/bin/perl # mysql01.pl - Einfaches Beispiel zum Verbinden mit MySQL Alle Zeichen hinter einem # werden als Kommentar betrachtet und ignoriert. Die erste Zeile dient unter Unix dazu, bei Aufruf von prompt> mysql01.pl direkt den Perl-Interpreter zu starten und das Programm auszuführen. =XJULIIVP|JOLFKNHLWHQ use DBI; use strict; Mit diesen beiden Befehlen wird der Perl-Interpreter dazu gebracht, das Modul DBI zu laden, um es später nutzen zu können. Mit use strict wird dafür gesorgt, dass Variablennamen zunächst deklariert werden müssen, bevor man sie verwenden kann. Das ist zwar nicht unbedingt nötig, aber sehr sinnvoll, um später nicht ewig nach Fehlern zu suchen, die darauf beruhen, dass man eine Variable mit $myWonderfulLongVariableName anspricht, die in Wirklichkeit $myWonderfulLongVarName heißt (und dann natürlich keinen sinnvollen Inhalt hat). my my my my my my ($dsn) = "DBI:mysql:musikschule"; ($user_name); ($password); ($dbh, $sth); ($query); (@ary); # # # # # # Verbindungstyp und Datenbankname Benutzername (hier leer) Kennwort (hier leer) Verbindungshandle, Query-Handle SELECT-Befehl Datensatz Mit my(...) werden Variablen deklariert. Normale Variablen haben ein $ am Anfang ihres Namens, Arrays ein @. Hier kommen jetzt als Variablennamen verschiedene Bezeichnungen ins Spiel, die häufig im Zusammenhang mit DBI verwendet werden: • $dsn: enthält meist die Verbindungsdaten (DSN, Data Source Name), hier zum Beispiel den Datenbanktyp und den Datenbanknamen. • $user_name, $password: Diese Variablennamen sprechen wohl für sich. • $dbh: Ein sogenannter Handle, der als Variable die Verbindung an sich repräsentiert. Ihn brauchen wir im Folgenden immer wieder, da er alle Daten enthält, die für die Verbindung notwendig sind. • $sth: Ein weiterer Handle, der für die Verarbeitung einer Anfrage notwendig ist. Ihm wird der SELECT-Befehl übergeben und von ihm erhält man die Ergebnisse. • $query: Der String, der die eigentliche SQL-Anfrage enthält. Es macht Sinn, den SQL-Befehl in einer eigenen Variable zusammenzubauen, um sie leichter ausgeben zu können, wenn man Probleme mit der Anfrage hat. • @ary: Ein Array, in dem der Inhalt eines Datensatzes gespeichert wird. Die Variable $dsn wird hier gleich mit den notwendigen Verbindungsdaten gefüllt, die durch den Doppelpunkt getrennt sind. Zunächst kommt die Angabe DSI, dann der Datenbanktyp mysql, schließlich der Name der Datenbank musikschule. Handelt es sich nicht um die Datenbank auf localhost, kann man zum Schluss (wieder durch einen Doppelpunkt abgeteilt) auch noch den Rechnernamen angeben. 6FKQLWWVWHOOHQ $dbh = DBI->connect($dsn, $user_name, $password, {RaiseError => 1}); Mit diesem Befehl wird die Verbindung zur Datenbank aufgebaut und der Handle $dbh mit Leben gefüllt. {RaiseError => 1} sorgt dafür, dass bei einem Fehler im Verbindungsaufbau das Skript beendet wird und nicht mit einer Warnung weiterläuft. Normalerweise wird man sicherlich eine ausgefeiltere Fehlerbehandlung durchführen, aber wir haben es hier schließlich nur mit einem einfachen Skript zu tun. $query = "SELECT raum_id, raum_name, etage, personen " ."FROM raum ORDER BY raum_name"; $sth = $dbh->prepare($query); $sth->execute(); Nun wird die Abfrage definiert und der Query-Handle mit prepare(...) vorbereitet. Danach lässt er sich mit execute() ausführen. print "raum_id\traum_name\tetage\tpersonen\n\n"; Zunächst werden jetzt die Feldnamen ausgegeben. while(@ary = $sth->fetchrow_array()) { # Ausgabe des Datensatzes print join("\t", @ary), "\n"; } Nun wird in einer Schleife so lange die Methode fetchrow_array() aufgerufen, bis sie keine Ergebnisse mehr zurückliefert. Diese Methode liest den aktuellen Datensatz aus, gibt die Werte der Spalten in einem Array zurück und springt dann zu nächsten Datensatz. Handelt es sich dabei um den letzten Satz, wird beim nächsten Aufruf ein leeres Array zurückgegeben. Es gibt noch weitere Befehle zum Auslesen von Datensätzen, zum Beispiel fetchrow_arrayref(), fetch() und fetchrow_hashref(), die in anderen Situationen einsetzbar sind. print join("\t", @ary) gibt die einzelnen Elemente des Arrays durch Ta- bulatorzeichen getrennt aus. $sth->finish(); $dbh->disconnect(); exit(0); finish() gibt die Ressourcen wieder frei, die der Query-Handle benötigt hat. disconnect() trennt die Verbindung zur Datenbank und exit(0) schließlich beendet das Programm mit einem normalen Code. =XJULIIVP|JOLFKNHLWHQ Ruft man dieses Programm jetzt auf (zum Beispiel mit perl mysql01.pl), erhält man folgende Ausgabe: prompt>perl mysql01.pl raum_id raum_name etage 4 5 1 2 3 A5.21 A5.23 A5.33 B2.02 C4.16 5 5 5 2 4 personen 6 6 4 20 11 Möchte man Befehle ausführen, die im Allgemeinen keine Ergebnismenge zurückliefern, kann man statt execute() die Methode do(...)des Verbindungshandles $dbh nutzen. Mit ihr lassen sich zum Beispiel UPDATE, DELETE und INSERT ausführen. Hier wieder ein kleines Beispielskript: #! /usr/bin/perl # mysql02.pl - Einfaches Beispiel zum Ausführen von DML-Befehlen use DBI; use strict; :my ($dsn) = "DBI:mysql:musikschule"; # Verbindungstyp und Datenbankname my ($user_name); # Benutzername (hier leer) my ($password); # Kennwort (hier leer) my ($dbh); # Verbindungshandle my ($query); # SELECT-Befehl my ($rows); # Anzahl der betroffenen Zeilen # Verbindung aufbauen $dbh = DBI->connect($dsn, $user_name, $password, {RaiseError => 1}); # UPDATE ausführen $rows = $dbh->do("UPDATE raum SET personen = 9 WHERE raum_id = 2"); # Verbindung beenden $dbh->disconnect(); exit(0); Sie finden das Skript mit dem Dateinamen mysql02.pl auf der beiliegenden CD-ROM. do(...) liefert die Menge der betroffenen Zeilen zurück, wobei allerdings INSERT, UPDATE und DELETE immer 0E0 vermelden. Bei einem Fehler würde dagegen der Wert undef ausgegeben werden. 6FKQLWWVWHOOHQ Richtig nett wird es natürlich, wenn man die SQL-Befehle selber zusammenbaut. Dann kann man zum Beispiel folgendes Skript schreiben, welches einen Tabellennamen als Parameter enthält und den Inhalt dieser Tabelle ausgibt: #! /usr/bin/perl # mysql03.pl table_name - Einfaches Beispiel zum Anzeigen von Tabellen use DBI; use strict; my my my my my my ($dsn) = "DBI:mysql:musikschule"; ($user_name); ($password); ($dbh, $sth); ($query); (@ary); # # # # # # Verbindungstyp und Datenbankname Benutzername (hier leer) Kennwort (hier leer) Verbindungshandle, Query-Handle SELECT-Befehl Datensatz # Verbindung aufbauen $dbh = DBI->connect($dsn, $user_name, $password, {RaiseError => 1}); #SELECT-Befehl definieren $query = "SELECT * FROM ".$ARGV[0]; # Anfrage vorbereiten und ausführen $sth = $dbh->prepare($query); $sth->execute(); # Spaltenüberschriften ausgeben print join("\t", @{$sth->{NAME}}), "\n"; # Schleife über alle Datensätze while(@ary = $sth->fetchrow_array()) { # Ausgabe des Datensatzes print join("\t", @ary), "\n"; } # Freigeben des Query-Handles $sth->finish(); # Verbindung beenden $dbh->disconnect(); exit(0); =XJULIIVP|JOLFKNHLWHQ Sie finden das Skript mit dem Dateinamen mysql03.pl auf der beiliegenden CD-ROM. Hier haben wir die $query zusammengesetzt, um mit $ARGV[0] den Namen der Tabelle einbauen zu können. Natürlich muss man eigentlich noch Fehlerbehandlungsroutinen einbauen… Interessant ist noch die folgende Zeile: print join("\t", @{$sth->{NAME}}), "\n"; $sth->{NAME} liefert eine Referenz auf ein Array zurück (die dann mit @{...} aufgelöst wird), in der die Namen der zurückgegebenen Spalten stehen. Somit kann man hier unabhängig von der Tabelle die Spaltennamen ausgeben lassen: prompt>perl mysql03.pl instrument instrument_id instr_name instr_gruppe 1 Querflöte Holzbläser 2 Klarinette Holzbläser 3 Violine Streicher 4 Viola Streicher 5 Posaune Blechbläser 6 Trompete Blechbläser 7 Klavier Tasten 8 Keyboard Tasten Um eine SQL-Abfrage universell verwendbar zu machen, gibt es (hauptsächlich) zwei verschiedene Varianten: der jeweilige Aufbau eines SQLBefehls oder die Verwendung von Platzhaltern: • Die erste Variante haben wir im Prinzip schon kennengelernt: innerhalb des Abfrage-Strings wird eine Variable genutzt: $query = "SELECT * FROM schueler WHERE nachname LIKE '$name'"; $sth = $dbh->prepare($query); $sth->execute(); $name wird von Perl innerhalb von doppelten Anführungszeichen durch den Inhalt der Variablen ersetzt. Möchte man doppelte Anführungszeichen innerhalb des SQL-Befehls nutzen, muss man sie durch ein Fluchtzeichen (\) maskieren: $query = "SELECT * FROM lehrer WHERE plz = \"$plz\""; Eleganter und weniger fehleranfällig ist die Verwendung von qq{}. Alles zwischen den geschweiften Klammern (für die man im Übrigen auch andere Zeichen wie // oder () nutzen kann, die allerdings häufiger selbst in Strings vorkommen) wird dann als Zeichenkette interpre- 6FKQLWWVWHOOHQ tiert und so ausgewertet, als ob es von doppelten Anführungszeichen umschlossen wäre. Man muss sich dabei aber keine Gedanken um das Maskieren der Anführungszeichen machen: $query = qq{SELECT * FROM lehrer WHERE plz = "$plz"}; Die zweite Variante ist etwas aufwändiger. Dafür ermöglicht sie die mehrfache Verwendung von SQL-Befehlen mit verschiedenen Werten, ohne dass der Befehl vom Server neu analysiert werden müsste. Das spart Zeit, wenn man häufig gleiche Anfragen, nur mit unterschiedlichen Werten ausgestattet, schickt. Allerdings ist dieser Vorteil bei MySQL gerade nicht gegeben, da MySQL die SQL-Befehle nicht für eine spätere Verwendung zwischenspeichert. Es kann sich aber trotzdem anbieten, den Zugriff auf diese Weise zu realisieren, falls man später einmal auch auf andere Datenbanksysteme zugreifen möchte. Will man Platzhalter nutzen, verwendet man an Stelle der Werte das Fragezeichen im SQL-Befehl: $query = "SELECT * FROM schueler WHERE nachname = ? AND vorname = ?"; $sth = $dbh->prepare($query); Bei der Ausführung des Befehls werden execute() nun die entsprechenden Parameter in der angegebenen Reihenfolge mitgegeben: $sth->execute("Schmidt", "Thomas"); Platzhalter lassen sich auch für die Ausgabe verwenden. So kann man die Ergebnisspalten direkt mit Variablen verknüpfen, die dann bei jedem fetch automatisch mit den aktuellen Werten gefüllt werden. Das folgende Skript gibt die Adressen aller Schüler aus, deren Nachname mit den als Parameter übergebenen Buchstaben beginnt: #! /usr/bin/perl # mysql04.pl lastname - Einfaches Beispiel zum Verknüpfen von # Platzhaltern use DBI; use strict; my my my my my my my ($dsn) = "DBI:mysql:musikschule"; # Verbindungstyp und Datenbankname ($user_name); # Benutzername (hier leer) ($password); # Kennwort (hier leer) ($dbh, $sth); # Verbindungshandle, Query-Handle ($query); # SELECT-Befehl ($queryname) = $ARGV[0]; # Filterkriterium ($lastname, $firstname, $street, $plz, $city); # Ausgabevariablen =XJULIIVP|JOLFKNHLWHQ # Anfügen eines Prozentzeichens, um immer auch nach Namensstücken suchen # zu können $queryname = $queryname."%"; # Verbindung aufbauen $dbh = DBI->connect($dsn, $user_name, $password, {RaiseError => 1}); #SELECT-Befehl definieren $query = "SELECT nachname, vorname, strasse, plz, ort " ."FROM schueler WHERE nachname LIKE ?"; # Anfrage vorbereiten und ausführen $sth = $dbh->prepare($query); $sth->execute($queryname); # Ausgabespalten mit Variablen verbinden $sth->bind_col(1, \$lastname); $sth->bind_col(2, \$firstname); $sth->bind_col(3, \$street); $sth->bind_col(4, \$plz); $sth->bind_col(5, \$city); # Schleife über alle Datensätze print "$firstname $lastname\n$street\n$plz $city\n\n" while $sth->fetch(); # Freigeben des Query-Handles $sth->finish(); # Verbindung beenden $dbh->disconnect(); exit(0); Sie finden das Skript mit dem Dateinamen mysql04.pl auf der beiliegenden CD-ROM. Entscheidend für die Ausgabebindung ist hier der Befehl bind_col(...). Er sorgt dafür, dass die angegebenen Variablen mit der entsprechenden Ausgabespalte der Abfrage verbunden werden. Alternativ kann man auch alle Variablen auf einmal verbinden, indem man den Befehl bind_columns(...) nutzt: $sth->bind_columns(\$lastname, \$firstname, \$street, \$plz, \$city); Wichtig ist noch, dass bind_col(...) bzw. bind_columns(...) erst nach execute(...) ausgeführt wird. 6FKQLWWVWHOOHQ 5.5.2 C++ Um mittels der Programmiersprache C++ auf MySQL zugreifen zu können, benötigt man MySQL++, die entsprechende API von MySQL. Sie bietet eine umfassende Klassenstruktur, die man ähnlich nutzen kann wie andere Klassen der STL (Standard Template Library) von C++. Man kann mit MySQL++ sehr einfache und gut lesbare Programme schreiben, aber sie bietet eigentlich auch alles an, was man in irgendeiner Form für den Zugriff und die Kommunikation mit MySQL benötigt. MySQL++ findet man auf den Web-Seiten von MySQL im ContribBereich (http://www.mysql.com/Downloads/Contrib/). Die benötigten Dateien für Red Hat Linux und Windows (Borland und Visual C++) finden Sie auch auf der beiliegenden CD-ROM im Verzeichnis MySQL++. Ein einfaches Beispiel für den Zugriff auf MySQL ist das folgende Programm, welches den Beispielen von MySQL++ entnommen und für die Musikschule leicht modifiziert wurde: // mysql01.cpp // Ausgabe von Daten #include #include #include #include <windows.h> <iostream> <iomanip> <sqlplus.hh> int main() { try { Connection con("musikschule"); // Erstellen eines Query-Objektes, welches mit con verbunden ist Query query = con.query(); // Definieren der Abfrage query << "select * from raum"; // Ausführen der Query und Rückgabe des Ergebnisses Result res = query.store(); // Anzahl der Datensätze cout << "Records Found: " << res.size() << endl << endl; Row row; =XJULIIVP|JOLFKNHLWHQ // Überschrift cout.setf(ios::left); cout << setw(10) << "raum_id" << setw(20) << "raum_name" << setw(7) << "etage" << "personen" << endl << endl; // Iterator über die Ergebnismenge Result::iterator i; for (i = res.begin(); i != res.end(); i++) { row = *i; // Ausgabe der Daten cout << setw(10) << row[0] << setw(20) << row[1] << setw(7) << row["etage"] << row[3] << endl; } } catch (BadQuery er) { // Abfangen aller Fehler (außer s.u.) cerr << "Error: " << er.error << endl; return -1; } catch (BadConversion er) { // Konvertierungs-Fehler cerr << "Error: Tried to convert \"" << er.data << "\" to a \"" << er.type_name << "\"." << endl; return -1; } return 0; } Sie finden den Quelltext mit dem Dateinamen mysql01.cpp auf der beiliegenden CD-ROM. Kurz die einzelnen Schritte erläutert: Connection con("musikschule"); Hiermit wird ein Objekt con erzeugt, welches eine Verbindung zu einer Datenbank aufbaut. Es lassen sich neben dem Namen der Datenbank die üblichen Verbindungsparameter mit angeben. Query query = con.query(); query << "select * from raum"; Result res = query.store(); 6FKQLWWVWHOOHQ Mittels con.query() wird ein Query-Objekt erzeugt, welches seine Anfragen über die Verbindung con stellt. Dieses Objekt wird dann über << mit einem SQL-Befehl gefüllt und über store() ausgeführt. Letztere Funktion liefert eine Ergebnismenge vom Typ Result zurück. cout << "Records Found: " << res.size() << endl << endl; res.size() liefert die Anzahl der Datensätze zurück, die die Abfrage erge- ben hat. Row row; Result::iterator i; for (i = res.begin(); i != res.end(); i++) { row = *i; Eine Row kann die Daten eines Datensatzes enthalten. Um alle Datensätze der Ergebnismenge ausgeben zu können, nutzt man einen Iterator vom Typ Result::iterator. cout << << << << setw(10) << row[0] setw(20) << row[1] setw(7) << row["etage"] row[3] << endl; Auf die einzelnen Elemente einer Zeile kann man entweder über die Position der Spalte im Datensatz oder über den Namen der Spalte zugreifen. catch (BadQuery er) { cerr << "Error: " << er.error << endl; return -1; } catch (BadConversion er) { cerr << "Error: Tried to convert \"" << er.data << "\" to a \"" << er.type_name << "\"." << endl; } BadQuery und BadConversion sind Exceptions, die bei entsprechenden Fehlern geworfen werden. Als Ergebnis erhält man eine übersichtliche Tabelle mit allen Räumen: prompt>mysql01 Records Found: 5 raum_id raum_name etage personen 1 2 3 4 5 A5.33 B2.02 C4.16 A5.21 A5.23 5 2 4 5 5 =XJULIIVP|JOLFKNHLWHQ 4 9 11 6 6 Ein anderes Beispiel zeigt den Zugriff auf die Metadaten einer Abfrage: // mysql02.cpp // Ausgabe von Meta-Daten #include #include #include #include <windows.h> <iostream> <iomanip> <sqlplus.hh> int main() { try { Connection con(use_exceptions); con.connect("musikschule"); Query query = con.query(); query << "SELECT * FROM schueler"; Result res = query.store(); cout << "Records Found: " << res.size() << endl << endl; cout.setf(ios::left); for (unsigned int i cout << setw(3) << setw(15) << setw(25) << endl; } = 0; i < res.names().size(); i++) { << i << res.names(i).c_str() << res.types(i).sql_name() cout << endl; return 0; } catch (BadQuery er) { cerr << "Error: " << er.error << endl; return -1; } catch (BadConversion er) { cerr << "Error: Tried to convert \"" << er.data << "\" to a \"" << er.type_name << "\"." << endl; return -1; } } Sie finden den Quelltext mit dem Dateinamen mysql02.cpp auf der beiliegenden CD-ROM. 6FKQLWWVWHOOHQ Hier sei besonders auf die Nutzung der Elemente von Result hingewiesen: for (unsigned int i cout << setw(3) << setw(15) << setw(25) << endl; = 0; i < res.names().size(); i++) { << i << res.names(i).c_str() << res.types(i).sql_name() res.names(...).c_str() gibt Zugriff auf die Spaltennamen der Ergebnismenge, während res.types(...).sql_name() die Spaltentypen von MySQL ausgibt. Das Ergebnis lautet dann: prompt>mysql02 Records Found: 5 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 schueler_id nachname vorname geburtsdatum strasse plz ort telefon mobil email einzug bankname blz kontonr kontoname geschlecht INT UNSIGNED NOT NULL VARCHAR NOT NULL VARCHAR NULL DATE NULL VARCHAR NULL VARCHAR NULL VARCHAR NULL VARCHAR NULL VARCHAR NULL VARCHAR NULL TINYINT NULL VARCHAR NULL VARCHAR NULL VARCHAR NULL VARCHAR NULL TINYINT NULL Auch bei MySQL++ gibt es die Möglichkeit, mit Platzhaltern zu arbeiten. Darauf will ich hier aber nicht weiter eingehen, sondern verweise auf die Dokumentation, die zu MySQL++ auf den Web-Seiten von MySQL zu finden ist. Sie enthält noch einige weitere Beispiele, die zeigen, wie man die C++-API sinnvoll nutzen kann. 5.5.3 MyODBC Entwickelt man ein Programm, welches mit einer Datenbank zusammenarbeitet, wird man im Allgemeinen die Schnittstelle verwenden, die zum Datenbanksystem gehört. Das ermöglicht eine umfassende Kontrolle der Kommunikation und ist meistens auch recht performant. Möchte man aber ein Programm entwickeln, welches mit möglichst vielen verschiede- =XJULIIVP|JOLFKNHLWHQ nen Datenbanksystemen zusammenarbeitet, benötigt man eine Zwischenschicht, die die Verbindungen zur Datenbank verwaltet und die einzelnen SQL-Anweisungen an die Datenbank übermittelt. Solch eine Zwischenschicht ist ODBC (Open Database Connectivity). Diese Schnittstelle wurde von Microsoft entworfen und dient hauptsächlich dazu, Windows-Programmen die Kommunikation mit Datenbanken (egal ob unter Windows oder Unix) zu ermöglichen. Mittlerweile gibt es auch unter verschiedenen Unix-Systemen Applikationen, die mit ODBC laufen, allerdings ist dies ein recht seltener Fall. Um mit ODBC auf eine Datenbank zugreifen zu können, benötigt man einen entsprechenden ODBC-Treiber für das Datenbank-System, der die ODBC-Aufrufe in die entsprechenden Anweisungen für die Datenbank umwandelt. Für MySQL gibt es MyODBC, ein Treiber für Windows und Unix, der einen großen Teil der möglichen ODBC-Befehle umsetzt. Da ODBC für einen Unix-Client sehr selten genutzt wird, werde ich im Folgenden nur auf die Windows-Variante eingehen. Unterstützt ein Programm ODBC, kann es theoretisch jede Datenbank ansprechen, die entsprechende Treiber anbietet. Theoretisch deshalb, weil viele Applikationen dann doch recht spezielle SQL-Befehle einzelner Datenbank-Systeme nutzen oder auf Systemtabellen zugreifen, die nur in einem einzelnen RDBMS vorkommen. Macht man sich aber die Mühe, wirklich plattformübergreifend zu entwickeln, kann man zum Beispiel zunächst mit einer kleinen Datenbank arbeiten, um dann später auf ein deutlich größeres und besser skalierbares System umzusteigen. MyODBC erhält man auf den Web-Seiten von MySQL unter http:// www.mysql.com/downloads/api-myodbc.html. Dort kann man sich eine komprimierte Datei mit dem Namen myodbc-VERSION-OS.zip herunterladen, wobei VERSION die aktuelle Version ist und OS für das Betriebssystem steht: „win95“ Windows 95, Windows 98 und Windows ME; „nt“ für Windows NT, Windows 2000 und Windows XP. Diese Datei packt man aus (zum Beispiel mit WinZIP) und startet das Installationsprogramm SETUP.EXE (siehe Abbildung 5.13). Die entsprechenden Dateien myodbc-2.50.39-win95.zip und myodbc2.50.39-nt.zip finden Sie auch auf der beiliegenden CD-ROM im Verzeichnis MyODBC. 6FKQLWWVWHOOHQ Abbildung 5.13: Startbildschirm des Setups von MyODBC Wenn man die Schaltfläche Continue anklickt, gelangt man in das nächste Fenster (Abbildung 5.14), in dem man das entsprechende Produkt auswählt – hier ist allerdings nur eines verfügbar… Abbildung 5.14: Auswahl des Treibers bei der Installation von MyODBC =XJULIIVP|JOLFKNHLWHQ Nach einem kurzen Kopiervorgang erscheint ein Dialog zum Verwalten der ODBC-Datenquellen (Abbildung 5.15). Mit ihm kann man die automatisch mit eingerichtete MyODBC-Verbindung sample-MySQL zu einem MySQL-Server konfigurieren. Den entsprechenden Dialog (Abbildung 5.16) erreicht man, wenn man auf die Schaltfläche Setup... klickt. Die einzelnen Optionen will ich im Folgenden beschreiben: • Windows DSN-name: Dies ist der Name der ODBC-Verbindung. Er wird auch in der Liste der Verbindungen angezeigt und über ihn kann man die Verbindung in anderen Programmen ansprechen. • MySQL host (name or IP): Der Server, auf dem sich die MySQL-Datenbank befindet. Handelt es sich um den lokalen Rechner, sollte man hier localhost eintragen, ansonsten den entsprechenden Rechnernamen oder dessen IP-Adresse. • MySQL database name: Der Name der Datenbank, die angesprochen werden soll. • User: Name des Benutzers, der angemeldet werden soll. • Password: Kennwort des anzumeldenden Benutzers. • Port (if not 3306): Port, über den der MySQL-Server angesprochen wird. • SQL command on connect: SQL-Befehl, der gleich nach dem Verbinden ausgeführt werden soll. • Options that affects the behaviour of MyODBC: Optionen, mit denen man das Verhalten des MyODBC-Treibers steuern kann. In Abhängigkeit von der verwendeten Applikation kann es notwendig sein, eine oder mehrere der angegebenen Optionen zu aktivieren. Um zum Beispiel Daten mit Microsoft Excel weiterzuverarbeiten, empfiehlt es sich, die Option Return matching rows zu aktivieren. Weitere Optionen sind unter anderem im Manual von MySQL beschrieben. Um auch später die ODBC-Verbindungen konfigurieren zu können, kann man den Windows-eigenen Dialog aufrufen. Unter Windows 2000 zum Beispiel erreicht man ihn über Start/Einstellungen/Systemsteuerung, dort dann unter Verwaltung/Datenquellen (ODBC) (siehe auch Abbildung 5.17). Über die Schaltfläche Hinzufügen... (bzw. Add... bei der Konfigurationsoberfläche des MyODBC-Installers) gelangt man in das in Abbildung 5.18 dargestellte Fenster, in dem man einen Treiber auswählen kann, um eine neue Datenquelle (zum Beispiel für eine andere Datenbank oder einen anderen Server) zu erstellen. Um zu testen, ob die Verbindung auch richtig eingerichtet ist, gibt es unter den Installationsdateien von MyODBC das Programm admndemo.exe. Mit diesem Tool lassen sich Verbindungen zu einer ODBCDatenquelle herstellen und SQL-Befehle absetzen. 6FKQLWWVWHOOHQ Startet man das Tool, öffnet sich gleich ein Dialog, in dem man Dateidatenquellen und Computerdatenquellen auswählen kann. Die Dateidatenquellen interessieren hier weniger, daher sollte man gleich auf die Registerkarte Computerdatenquelle wechseln (siehe Abbildung 5.19). Dort kann man dann zum Beispiel sample-MySQL auswählen. Nach dem Verbindungsaufbau steht einem ein Eingabefenster zur Verfügung, in dem man SQL-Befehle ausführen kann (siehe Abbildung 5.20). Dazu gibt man zum Beispiel einen SELECT-Befehl ein und kann mit (Strg)(E) oder über den Menüpunkt Command/Execute den Befehl ausführen (siehe Abbildung 5.21). Wenn man hier Ergebnisse sieht, hat man das Ziel erreicht und kann die ODBC-Verbindung meist auch mit anderen Programmen erfolgreich nutzen. Es gibt noch einige andere Funktionen des Programms admndemo.exe, die hier aber nicht weiter aufgeführt werden sollen, so zum Beispiel die Möglichkeit, sich Datenbank-, Tabellen- und Indexstrukturen ausgeben zu lassen. Abbildung 5.15: ODBC-Datenquellen im Installationsprogramm von MyODBC =XJULIIVP|JOLFKNHLWHQ Abbildung 5.16: Einstellungsdialog von MyODBC Abbildung 5.17: ODBC-Datenquellen unter Windows 2000 6FKQLWWVWHOOHQ Abbildung 5.18: Hinzufügen einer neuen Datenquelle Abbildung 5.19: Auswahl einer Datenquelle in admndemo.exe =XJULIIVP|JOLFKNHLWHQ Abbildung 5.20: Eingabefenster bei admndemo.exe Abbildung 5.21: Erfolgreiche ODBC-Verbindung mit admndemo.exe 6FKQLWWVWHOOHQ 5.6 Fragen 1. Wie kann man sich in regelmäßigen Abständen Statusänderungen anzeigen lassen? 2. Auf welchem Weg lässt sich eine Datenbank komplett auf einen an- deren Server transportieren? 3. Über welches Modul sollte man in Perl eine MySQL-Datenbank an- sprechen? 4. Wie kann man in mysql die Befehle und Ausgaben aufzeichnen? =XJULIIVP|JOLFKNHLWHQ