Bietet Rezepte, Lösungen und ausführliche Beispiele rund um gesundes SQL und zufriedene Datenbanken.
Wie schon im MySQL-Manual so schön gefragt wird: Ist MySQL pingelig hinsichtlich reservierter Wörter? Gelegendlich (er-)findet man als Entwickler oder Datenbankdesigner Spaltennamen für Tabellen, die identisch zu einem MySQL Befehl oder Datentyp sind. So ist es zum Beispiel nicht sinnvoll einem Zahlenfeld in der Tabelle den Namen INT zu geben, da INT ebenfalls ein Datentyp ist. Wer unbedingt meint es trotzdem tun zu müssen, nutzt im Notfall eben die Backticks. So weit so klar. Manche Worte sind zwar reserviert, erzeugen aber nicht gleich einen Syntaxfehler beim CREATE TABLE bzw. sind in neueren MySQL Versionen zumeist auch neue Worte reserviert. Wie läßt sich das einfach prüfen?
Beginnen wir mit einer Mitgliedertabelle für den Verein. Diese enthält beispielweise Name und Vorname, das Alter, ein Geburtsdatum sowie ein Infofeld.
CREATE TABLE mitglied (
mitglied_id INT NOT NULL AUTO_INCREMENT,
name VARCHAR(50) NOT NULL,
vorname VARCHAR(30) NOT NULL,
alter INT NOT NULL,
gebdatum DATE NOT NULL,
info VARCHAR(500),
PRIMARY KEY(mitglied_id)
);
=> ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that
corresponds to your MySQL server version for the right syntax to use near 'alter
INT NOT NULL,
gebdatum DATE NOT NULL,
info VARCHAR(500),
PRIMARY KEY(mi' at line 5
Ein Fehler..? Richtig, die Spalte Alter geht nicht, da dies für MySQL zum Befehl ALTER TABLE .. gehört und der hat da nichts zu suchen. Ob Alter überhaupt eine sinnvolle Spalte ist, ist zweifelhaft, da sich diese Information ständig ändert und sich aus dem Geburtsdatum und dem aktuellen Datum errechnet. Aber egal, verwenden wir als Zaubermittel eben die Backticks, um MySQL zu überlisten.
CREATE TABLE mitglied (
mitglied_id INT NOT NULL AUTO_INCREMENT,
name VARCHAR(50) NOT NULL,
vorname VARCHAR(30) NOT NULL,
`alter` INT NOT NULL,
gebdatum DATE NOT NULL,
info VARCHAR(500),
PRIMARY KEY(mitglied_id)
);
=> Query OK, 0 rows affected (0.00 sec)
Perfekt!? Die Tabelle ist erzeugt. Alles wird gut.
So entstehen viele Projekte und wie läßt sich nachträglich erkennen, ob da eventuell ein Problem schlummert. Beispielweise bei einem Versionswechsel oder Migration zu einer anderen Datenbank.
Speziell hervorzuheben ist da noch folgende Sonderregelung aus historischen Gründen:
9.5. Ist MySQL pingelig hinsichtlich reservierter Wörter?
...MySQL gestattet auch die Verwendung bestimmter Schlüsselwörter als Bezeichner ohne Anführungszeichen, da viele Benutzer sie in der Vergangenheit bereits eingesetzt haben. Beispiele entnehmen Sie der folgenden Liste: ACTION, BIT, DATE, ENUM, NO, TEXT, TIME, TIMESTAMP
* mysql-essential-5.1.55-winx64
* mysql-5.5.9-winx64
* bei mysql-5.6.2-m5-winx64 ist die Tabelle mysql.help_keyword leer
MySQL liefert in der "mysql" Datenbank eine schöne Hilfe dafür. Die mysql.help_keyword Tabelle. Darin sind reservierte Worte und wichtige MySQL Kommandos hinterlegt. Nicht ganz perfekt, aber eine gute Grundlage um eventuelle Probleme aufzuspüren. Und was eignet sich dafür besser als eine MySQL PROCEDURE.
In der folgenden Stored Procedure wird mit Hilfe der Metadaten (information_schema.columns) und der MySQL-Hilfefunktion mysql.help_keyword eine Tabelle überprüft und gleich auch noch geprüft, ob ein PRIMARY KEY existiert. Während der Überprüfung wird eine temporäre Tabelle erzeugt, gefüllt und der Inhalt zum Schluß via SELECT ausgegeben. Die Procedure ist etwas lang geworden, deshalb hier nur die wichtigsten Teile. Der gesamte Quellcode ist hier (PDF 2kB) :
DELIMITER $$
CREATE PROCEDURE tw_check_table (IN p_sDatabase VARCHAR(64),
IN p_sTable VARCHAR(64) )
SQL SECURITY INVOKER
NOT DETERMINISTIC
MODIFIES SQL DATA
CONTAINS SQL
COMMENT 'SQL-Backstube 02.06.2011 (twiedmann.de)'
BEGIN
...
/* CURSOR - check MySQL columns und reserved words */
DECLARE curCheckTable CURSOR FOR
SELECT UPPER(c.column_name) AS column_name,
UPPER(kw.name) AS reserved_word,
UPPER(c.column_key) AS column_key
FROM information_schema.columns c
LEFT JOIN mysql.help_keyword kw
ON kw.name = c.column_name
WHERE c.table_schema = p_sDatabase
AND c.table_name = p_sTable;
...
END$$
DELIMITER ;
Schreiten wir zur Tat und probieren es anhand der Tabelle MITGLIED aus.
mysql> call tw_check_table(DATABASE(),'mitglied');
+----+-------------------------------------------------------+
| id | msg |
+----+-------------------------------------------------------+
| 1 | Check-Table: sample.mitglied Reserved-/Keyword(s): |
| 2 | Reserved Word: NAME |
| 3 | Reserved Word: ALTER |
| 4 | Reserved Word: INFO |
| 5 | Primary Key: exists |
+----+-------------------------------------------------------+
5 rows in set (0.00 sec)
Wie erwartet erscheint die Spalte ALTER hier auf der Warnliste, aber auch die Spalten NAME und INFO werden angemeckert. Sind dies auch reservierte Worte? Jedenfalls sind es Befehloptionen für einige Befehle. Schauen wir nach..
mysql> help name;
Name: 'ALTER DATABASE'
Description:
Syntax:
ALTER {DATABASE | SCHEMA} [db_name]
alter_specification ...
ALTER {DATABASE | SCHEMA} db_name
UPGRADE DATA DIRECTORY NAME
Tatsächlich, NAME wird beim ALTER DATABASE benötigt.
mysql> help info;
Name: 'SELECT INTO'
Description:
Syntax:
SELECT col_name [, col_name] ...
INTO var_name [, var_name] ...
table_expr
Hm, INFO = INTO ? Passt nicht wirklich, aber ich vermute, hier soll auf die MySQL API Referenz:
15.17.16. info(): gibt Informationen an den Optimierer zurück. Zurzeit implementiert dieser Tabellen-Handler die meisten erforderlichen Felder noch nicht
verwiesen werden.
Mit der oben gezeigten Procedure läßt sich auf einfache Art prüfen, ob die verwendeten Spaltenamen einer Tabelle identisch zu reservierten Worten oder besonderen MySQL Befehlen sind. Wer es genau wissen will, welche Worte reserviert sind, der schaut im Manual der jeweiligen MySQL-Version [1][2] nach.
[1] 8.3. Reserved Words http://dev.mysql.com/doc/refman/5.5/en/reserved-words.html
[2] 8.2.4. Function Name Parsing and Resolution http://dev.mysql.com/doc/refman/5.5/en/function-resolution.html