Kapitel 13. SQL-Anweisungssyntax
Zurück |  | Weiter

## Kapitel 13. SQL-Anweisungssyntax

Dieses Kapitel beschreibt die Syntax für die meisten von MySQL unterstützten SQL-Anweisungen. Weitere Beschreibungen zu Anweisungen finden Sie in den folgenden Kapiteln:

- Kapitel 7, Optimierung, beschreibt die `EXPLAIN`-Anweisung.

- Kapitel 19, Gespeicherte Prozeduren und Funktionen, behandelt Anweisungen zum Schreiben gespeicherter Routinen.

- Kapitel 20, Trigger, behandelt Anweisungen zum Schreiben von Triggern.

- Kapitel 21, Views, behandelt View-spezifische Anweisungen.

## 13.1. Datendefinition: `CREATE`, `DROP`, `ALTER`

### 13.1.1. `ALTER DATABASE`

    ALTER {DATABASE | SCHEMA} [db_name]
        alter_specification [, alter_specification] ...

    alter_specification:
        [DEFAULT] CHARACTER SET charset_name
      | [DEFAULT] COLLATE collation_name

Mit `ALTER DATABASE` können Sie die grundlegenden Eigenschaften einer Datenbank ändern. Diese Eigenschaften sind in der Datei `db.opt` im Datenbankverzeichnis gespeichert. Um `ALTER DATABASE` verwenden zu können, benötigen Sie die Berechtigung `ALTER` für die Datenbank. `ALTER SCHEMA` ist ein Synonym für `ALTER DATABASE`.

Die Klausel `CHARACTER SET` ändert den Standardzeichensatz der Datenbank. Die Klausel `COLLATE` ändert die Standardsortierfolge der Datenbank. Kapitel 10, Zeichensatz-Unterstützung, behandelt Namen von Zeichensätzen und Sortierfolgen.

Der Datenbankname kann weggelassen werden. In diesem Fall bezieht sich die Anweisung auf die Standarddatenbank.

### 13.1.2. `ALTER TABLE`

    ALTER [IGNORE] TABLE tbl_name
        alter_specification [, alter_specification] ...

    alter_specification:
        ADD [COLUMN] column_definition [FIRST | AFTER col_name ]
      | ADD [COLUMN] (column_definition,...)
      | ADD INDEX [index_name] [index_type] (index_col_name,...)
      | ADD [CONSTRAINT [symbol]]
            PRIMARY KEY [index_type] (index_col_name,...)
      | ADD [CONSTRAINT [symbol]]
            UNIQUE [INDEX] [index_name] [index_type] (index_col_name,...)
      | ADD FULLTEXT [INDEX] [index_name] (index_col_name,...)
          [WITH PARSER parser_name]
      | ADD SPATIAL [INDEX] [index_name] (index_col_name,...)
      | ADD [CONSTRAINT [symbol]]
            FOREIGN KEY [index_name] (index_col_name,...)
            [reference_definition]
      | ALTER [COLUMN] col_name {SET DEFAULT literal | DROP DEFAULT}
      | CHANGE [COLUMN] old_col_name column_definition
            [FIRST|AFTER col_name]
      | MODIFY [COLUMN] column_definition [FIRST | AFTER col_name]
      | DROP [COLUMN] col_name
      | DROP PRIMARY KEY
      | DROP INDEX index_name
      | DROP FOREIGN KEY fk_symbol
      | DISABLE KEYS
      | ENABLE KEYS
      | RENAME [TO] new_tbl_name
      | ORDER BY col_name
      | CONVERT TO CHARACTER SET charset_name [COLLATE collation_name]
      | [DEFAULT] CHARACTER SET charset_name [COLLATE collation_name]
      | DISCARD TABLESPACE
      | IMPORT TABLESPACE
      | table_options
      | partition_options
      | ADD PARTITION partition_definition
      | DROP PARTITION partition_names
      | COALESCE PARTITION number
      | REORGANIZE PARTITION partition_names INTO (partition_definitions)
      | ANALYZE PARTITION partition_names
      | CHECK PARTITION partition_names
      | OPTIMIZE PARTITION partition_names
      | REBUILD PARTITION partition_names
      | REPAIR PARTITION partition_names

`ALTER TABLE` ermöglicht Ihnen das Ändern der Struktur einer vorhandenen Tabelle. Sie können beispielsweise Spalten hinzufügen oder entfernen, Indizes erstellen oder löschen, den Typ einer vorhandenen Spalte ändern oder Spalten oder die Tabelle umbenennen. Ferner können Sie den Kommentar für die Tabelle und auch den Tabellentyp modifizieren.

Die Syntax für viele der zulässigen Änderungen ähnelt Klauseln der `CREATE TABLE`-Anweisung. Hierzu gehören `table_options`-Modifikationen für Optionen wie `ENGINE`, `AUTO_INCREMENT` und `AVG_ROW_LENGTH`. (Allerdings ignoriert `ALTER TABLE` die Tabellenoptionen `DATA DIRECTORY` und `INDEX DIRECTORY`.) Abschnitt 13.1.5, „`CREATE TABLE`“, listet alle Tabellenoptionen auf.

Bei manchen Operationen kann eine Warnung erzeugt werden, wenn diese auf eine Tabelle angewendet werden sollen, deren Speicher-Engine die Operation nicht unterstützt. Diese Warnungen lassen sich mit `SHOW WARNINGS` anzeigen. Siehe auch Abschnitt 13.5.4.25, „`SHOW WARNINGS`“.

`ALTER TABLE` erstellt zunächst eine temporäre Kopie der Ursprungstabelle. Die Änderung wird dann an der Kopie vorgenommen, und schließlich wird die Originaltabelle gelöscht und die Kopie entsprechend umbenannt. Während der Ausführung von `ALTER TABLE` kann die Originaltabelle von anderen Clients gelesen werden. Änderungs- und Schreiboperationen in der Tabelle werden blockiert, bis die neue Tabelle bereit ist, und dann automatisch in die neue Tabelle umgeleitet. Aktualisierungen schlagen nicht fehl.

Beachten Sie, dass, wenn Sie eine andere `ALTER TABLE`-Option als `RENAME` verwenden, MySQL immer eine Temporärtabelle erstellt – und zwar auch dann, wenn die Daten strenggenommen nicht kopiert werden müssten (z. B. wenn Sie nur den Namen einer Spalte ändern). Bei `MyISAM`-Tabellen ist die Neuerstellung des Indexes der zeitaufwändigste Teil des Änderungsvorgangs. Sie können diesen beschleunigen, indem Sie die Systemvariable `myisam_sort_buffer_size` auf einen hohen Wert setzen.

- Um `ALTER TABLE` zu verwenden, benötigen Sie die Berechtigungen `ALTER`, `INSERT` und `CREATE` für die Tabelle.

- `IGNORE` ist eine MySQL-Erweiterung zum SQL-Standard. Sie steuert, wie `ALTER TABLE` funktioniert, wenn Dubletten eindeutiger Schlüssel in der neuen Tabelle vorhanden sind oder (bei aktiviertem striktem Modus) Warnungen auftreten. Wenn `IGNORE` nicht angegeben ist, wird der Vorgang bei Auftreten von Schlüsseldubletten abgebrochen, und ein Rollback wird durchgeführt. Ist `IGNORE` angegeben, dann wird nur der erste von mehreren Datensätzen mit Dubletten eindeutiger Schlüssel verwendet. Die übrigen betroffenen Datensätze werden gelöscht. Falsche Werte werden auf den nächstliegenden zulässigen Wert gesetzt.

- Sie können mehrere `ADD`-, `ALTER`-, `DROP`- und `CHANGE`-Klauseln in einer `ALTER TABLE`-Anweisung angeben. Diese werden durch Kommata getrennt. Dies ist eine MySQL-Erweiterung zum SQL-Standard, der nur jeweils eine dieser Klauseln je `ALTER TABLE`-Anweisung zulässt. Um beispielsweise mehrere Spalten mit einer einzelnen Anweisung zu löschen, tun Sie Folgendes:

      ALTER TABLE t2 DROP COLUMN c, DROP COLUMN d;

- `CHANGE `col_name``, `DROP `col_name`` und `DROP INDEX` sind MySQL-Erweiterungen zum SQL-Standard.

- `MODIFY` ist eine Oracle-Erweiterung zu `ALTER TABLE`.

- Das Wort `COLUMN` ist optional und darf weggelassen werden.

- Wenn Sie `ALTER TABLE `tbl_name` RENAME TO `new_tbl_name`` ohne zusätzliche Optionen sehen, benennt MySQL alle Dateien, die der Tabelle `tbl_name` entsprechen, einfach um. Es ist nicht notwendig, eine Temporärtabelle zu erstellen. (Sie können zum Umbenennen von Tabellen auch die Anweisung `RENAME TABLE` verwenden. Siehe auch Abschnitt 13.1.9, „`RENAME TABLE`“.)

- `column_definition`-Klauseln verwenden dieselbe Syntax für `ADD` und `CHANGE` wie bei `CREATE TABLE`. Beachten Sie, dass diese Syntax den Spaltennamen (und nicht nur den Datentyp) enthält. Siehe auch Abschnitt 13.1.5, „`CREATE TABLE`“.

- Sie können eine Spalte mithilfe einer `CHANGE `old_col_name` `column_definition``-Klausel umbenennen. Zu diesem Zweck geben Sie den alten und den neuen Spaltennamen sowie den Typ an, den die Spalte zurzeit hat. Um beispielsweise eine `INTEGER`-Spalte von `a` zu `b` umzubenennen, geben Sie Folgendes ein:

      ALTER TABLE t1 CHANGE a b INTEGER;

  Wenn Sie den Typ einer Spalte, nicht aber ihren Namen ändern wollen, erfordert die `CHANGE`-Syntax trotzdem einen alten und neuen Spaltennamen, auch wenn diese dann identisch sind. Zum Beispiel:

      ALTER TABLE t1 CHANGE b b BIGINT NOT NULL;

  Sie können den Spaltentyp auch mit `MODIFY` ändern, ohne die Spalte umzubenennen:

      ALTER TABLE t1 MODIFY b BIGINT NOT NULL;

- Wenn Sie `CHANGE` oder `MODIFY` zum Kürzen einer Spalte verwenden, für die ein Index vorhanden ist, und die Länge der Spalte nach der Operation geringer ist als die Indexlänge, dann kürzt MySQL den Index automatisch.

- Ändern Sie einen Datentyp mit `CHANGE` oder `MODIFY`, dann versucht MySQL, vorhandene Spaltenwerte bestmöglich in den neuen Typ zu konvertieren.

- Um eine Spalte an eine bestimmte Position in einer Tabellenzeile hinzuzufügen, verwenden Sie `FIRST` oder `AFTER `col_name``. Standardmäßig werden neue Spalten am Ende eingefügt. Sie können `FIRST` und `AFTER` auch bei `CHANGE`- oder `MODIFY`-Operationen verwenden.

- `ALTER ... SET DEFAULT` oder `ALTER ... DROP DEFAULT` geben einen neuen Vorgabewert für eine Spalte an bzw. entfernen den vorhandenen Vorgabewert. Wenn die alte Vorgabe entfernt wird und die Spalte `NULL` werden kann, dann wird `NULL` zum neuen Vorgabewert. Kann die Spalte nicht `NULL` werden, dann weist MySQL einen Standardwert zu (siehe auch Abschnitt 11.1.4, „Vorgabewerte von Datentypen“).

- `DROP INDEX` entfernt einen Index. Dies ist eine MySQL-Erweiterung zum SQL-Standard. Siehe auch Abschnitt 13.1.7, „`DROP INDEX`“.

- Wenn Spalten aus einer Tabelle entfernt werden, werden die Spalten auch aus allen Indizes gelöscht, deren Bestandteil sie sind. Wenn alle Spalten, die einen Index bilden, gelöscht wurden, dann wird auch der Index gelöscht.

- Enthält eine Tabelle nur eine Spalte, dann kann diese nicht gelöscht werden. Zur Entfernung der Tabelle verwenden Sie stattdessen `DROP TABLE`.

- `DROP PRIMARY KEY` löscht den Primärschlüssel. Hinweis: Bei älteren MySQL-Versionen löscht `DROP PRIMARY KEY`, wenn kein Primärindex vorhanden ist, den ersten eindeutigen Index in der Tabelle. Dies trifft bei MySQL 5.1 nicht mehr zu: Wenn Sie hier `DROP PRIMARY KEY` auf eine Tabelle ohne Primärschlüssel anzuwenden versuchen, erhalten Sie einen Fehler.

  Wenn Sie einer Tabelle mit `UNIQUE INDEX` oder `PRIMARY KEY` einen eindeutigen Index bzw. einen Primärschlüssel hinzufügen, wird dieser vor jedem nichteindeutigen Index gespeichert, sodass MySQL Schlüsseldubletten schnellstmöglich erkennt.

- `ORDER BY` erlaubt Ihnen die Erstellung einer neuen Tabelle mit allen Datensätzen in einer bestimmten Reihenfolge. Beachten Sie, dass diese Reihenfolge nach Einfüge- und Löschoperationen nicht aufrechterhalten wird. Diese Option ist in erster Linie nützlich, wenn Sie wissen, dass die Datensätze meistens in einer bestimmten Reihenfolge abgefragt werden. Wenn Sie diese Option nach umfangreicheren Änderungen in der Tabelle verwenden, können Sie die Leistung unter Umständen steigern. In bestimmten Fällen kann es MySQL das Sortieren erleichtern, wenn die Tabelle in der Reihenfolge der Spalte angeordnet ist, nach der Sie sie später auch sortieren wollen.

- Wenn Sie `ALTER TABLE` auf eine `MyISAM`-Tabelle anwenden, werden alle nichteindeutigen Indizes in einer separaten Stapeloperation erstellt (wie bei `REPAIR TABLE`). Dies sollte `ALTER TABLE` erheblich beschleunigen, wenn Sie viele Indizes haben.

  Die Funktion lässt sich explizit aktivieren. `ALTER TABLE ... DISABLE KEYS` weist MySQL an, die Aktualisierung nichteindeutiger Indizes für eine `MyISAM`-Tabelle zu beenden. Danach sollte `ALTER TABLE ... ENABLE KEYS` verwendet werden, um die fehlenden Indizes neu zu erstellen. MySQL tut dies mit einem speziellen Algorithmus, der wesentlich schneller ist als das aufeinander folgende Einfügen von Schlüsseln. Insofern sollte die Deaktivierung von Schlüsseln vor umfangreichen Einfügeoperationen diese erheblich beschleunigen. Die Verwendung von `ALTER TABLE ... DISABLE KEYS` erfordert neben den bereits genannten Berechtigungen auch die Berechtigung `INDEX`.

- Die Klauseln `FOREIGN KEY` und `REFERENCES` werden von der `InnoDB`-Speicher-Engine unterstützt, die `ADD [CONSTRAINT [`symbol`]] FOREIGN KEY (...) REFERENCES ... (...)` implementiert. Siehe auch Abschnitt 14.2.6.4, „Fremdschlüssel-Beschränkungen“. Von anderen Speicher-Engines werden die Klauseln zwar erkannt, aber ignoriert. Zudem wird die Klausel `CHECK` von allen Speicher-Engines erkannt, aber ignoriert. Siehe auch Abschnitt 13.1.5, „`CREATE TABLE`“. Diese Verhaltensweise – das Erkennen und nachfolgende Ignorieren von Syntaxklauseln – ist aus Kompatibilitätsgründen vorhanden. Sie erleichtert die Portierung von Codes anderer SQL-Server und die Ausführung von Anwendungen, die Tabellen mit Referenzen erstellen. Siehe auch Abschnitt 1.9.5, „MySQL: Unterschiede im Vergleich zu ANSI SQL92“.

  In separaten Klauseln derselben `ALTER TABLE`-Anweisung können Sie keinen Fremdschlüssel hinzufügen und einen Fremdschlüssel löschen. Sie müssen hierzu separate Anweisungen verwenden.

- `InnoDB` unterstützt die Verwendung von `ALTER TABLE` zum Löschen von Fremdschlüsseln:

      ALTER TABLE tbl_name DROP FOREIGN KEY fk_symbol;

  In separaten Klauseln derselben `ALTER TABLE`-Anweisung können Sie keinen Fremdschlüssel hinzufügen und einen Fremdschlüssel löschen. Sie müssen hierzu separate Anweisungen verwenden.

  Weitere Informationen finden Sie unter Abschnitt 14.2.6.4, „Fremdschlüssel-Beschränkungen“.

- Wenn Sie den Standardzeichensatz einer Tabelle und den Zeichensatz aller Zeichenspalten (`CHAR`, `VARCHAR`, `TEXT`) auf einen neuen Zeichensatz umstellen wollen, verwenden Sie eine Anweisung wie die folgende:

      ALTER TABLE tbl_name CONVERT TO CHARACTER SET charset_name;

  Warnung: Die obige Operation wandelt Spaltenwerte zwischen Zeichensätzen um. Sie sollten dies keinesfalls tun, wenn Sie eine Spalte in einem Zeichensatz (z. B. `latin1`) haben, die gespeicherten Werte aber eigentlich einen anderen inkompatiblen Zeichensatz (wie `utf8`) verwenden. In diesem Fall müssen Sie bei solchen Spalten Folgendes tun:

      ALTER TABLE t1 CHANGE c1 c1 BLOB;
      ALTER TABLE t1 CHANGE c1 c1 TEXT CHARACTER SET utf8;

  Der Grund, warum dies funktioniert, ist, dass, wenn Sie von oder in `BLOB`-Spalten konvertieren, keine Konvertierung stattfindet.

  Wenn Sie `CONVERT TO CHARACTER SET binary` angeben, werden die `CHAR`-, `VARCHAR`- und `TEXT`-Spalten in ihre entsprechenden binären String-Typen umgewandelt (`BINARY`, `VARBINARY`, `BLOB`). Das bedeutet, dass die Spalten keinen Zeichensatz mehr haben; eine nachfolgende `CONVERT TO`-Operation hat also keine Auswirkungen mehr.

  Um nur den Standardzeichensatz einer Tabelle zu ändern, verwenden Sie folgende Anweisung:

      ALTER TABLE tbl_name DEFAULT CHARACTER SET charset_name;

  Das Wort `DEFAULT` ist optional. Der Standardzeichensatz ist der Zeichensatz, der verwendet wird, wenn Sie den Zeichensatz für eine neue Spalte, die Sie (etwa mit `ALTER TABLE ... ADD column`) zu einer Tabelle hinzufügen, nicht explizit angegeben haben.

- Bei einer `InnoDB`-Tabelle, die mit einem eigenen Tablespace in einer `.ibd`-Datei erstellt wurde, kann diese Datei verworfen und importiert werden. Mit folgender Anweisung können Sie die `.ibd`-Datei verwerfen:

      ALTER TABLE tbl_name DISCARD TABLESPACE;

  Hierbei wird die aktuelle `.ibd`-Datei gelöscht, d. h., Sie sollten zuerst ein Backup erstellt haben. Der Versuch des Zugriffs auf die Tabelle, während die Tablespace-Datei verworfen wird, führt zu einem Fehler.

  Um die `.ibd`-Sicherungsdatei in die Tabelle zurückzuimportieren, kopieren Sie sie ins Datenbankverzeichnis und setzen dann folgende Anweisung ab:

      ALTER TABLE tbl_name IMPORT TABLESPACE;

  Siehe auch Abschnitt 14.2.3.1, „Verwendung von Tabellen-Tablespaces (ein Tablespace pro Tabelle)“.

- `ALTER TABLE` kann auch bei partitionierten Tabellen verwendet werden, um Partitionen hinzuzufügen, zu löschen, zu verbinden oder aufzutrennen. Auch die Partitionierungswartung ist hiermit möglich.

  Die einfache Angabe einer `partition_options`-Klausel zu `ALTER TABLE` für eine partitionierte Tabelle partitioniert diese entsprechend dem Partitionierungsschema neu, welches über die `partition_options` angegeben wurde. Diese Klausel beginnt immer mit `PARTITION BY` und verwendet ansonsten dieselbe Syntax und die Regeln, die auch auf die `partition_options`-Klausel für `CREATE TABLE` zutreffen. (Weitere Informationen finden Sie in Abschnitt 13.1.5, „`CREATE TABLE`“). Hinweis: Diese Syntax wird derzeit vom MySQL 5.1 Server akzeptiert, tut aber eigentlich noch gar nichts. Wir erwarten die Implementierung im Zuge der Fortentwicklung von MySQL 5.1.

  Die `partition_definition`-Klausel für `ALTER TABLE ADD PARTITION` unterstützt dieselben Optionen wie die gleichnamige Klausel für die `CREATE TABLE`-Anweisung. (Informationen zu Syntax und eine Beschreibung finden Sie in Abschnitt 13.1.5, „`CREATE TABLE`“.) Angenommen, Sie haben wie folgt eine partitionierte Tabelle erstellt:

      CREATE TABLE t1 (
          id INT,
          year_col INT
      )
      PARTITION BY RANGE (year_col) (
          PARTITION p0 VALUES LESS THAN (1991),
          PARTITION p1 VALUES LESS THAN (1995),
          PARTITION p2 VALUES LESS THAN (1999)
      );

  Sie können dieser Tabelle nun wie folgt eine neue Partition `p3` hinzufügen, die Werte aufnehmen kann, die kleiner als `2002` sind.

      ALTER TABLE t1 ADD PARTITION p3 VALUES LESS THAN (2002);

  Hinweis: Sie können `ALTER TABLE` nicht zum Hinzufügen von Partitionen zu einer Tabelle verwenden, die (noch) nicht partitioniert ist.

  Mit `DROP PARTITION` können Sie eine oder mehrere `RANGE`- oder `LIST`-Partitionen löschen. Diese Anweisung kann nicht für `HASH`- oder `KEY`-Partitionen verwendet werden; dort benutzen Sie stattdessen `COALESCE PARTITION` (siehe unten). In gelöschten Partitionen vorhandene Daten, die in der Liste `partition_names` aufgeführt sind, werden verworfen. So können Sie beispielsweise in der zuvor definierten Tabelle `t1` die Partitionen `p0` und `p1` wie folgt löschen:

      ALTER TABLE DROP PARTITION p0, p1;

  Beachten Sie, dass `DROP PARTITION` nicht bei Tabellen funktioniert, die die `NDB Cluster`-Speicher-Engine verwenden. Siehe auch Abschnitt 17.3.1, „Verwaltung von `RANGE`- und `LIST`-Partitionen“, und Abschnitt 16.8, „Bekannte Beschränkungen von MySQL Cluster“.

  `ADD PARTITION` und `DROP PARTITION` unterstützen `IF [NOT] EXISTS` derzeit nicht. Ferner ist es nicht möglich, eine Partition oder eine partitionierte Tabelle umzubenennen. Stattdessen müssen Sie, wenn Sie eine Partition umbenennen wollen, diese löschen und neu erstellen. Wollen Sie eine partitionierte Tabelle umbenennen, dann müssen Sie zunächst alle Partitionen löschen, die Tabelle dann umbenennen und schließlich alle gelöschten Partitionen neu erstellen.

  `COALESCE PARTITION` kann bei Tabellen benutzt werden, die mit `HASH` oder `KEY` partitioniert wurden, um die Anzahl der Partitionen um den Wert `number` zu verringern. Angenommen, Sie haben die Tabelle `t2` mit der folgenden Definition erstellt:

      CREATE TABLE t2 (
          name VARCHAR (30),
          started DATE
      )
      PARTITION BY HASH(YEAR(started))
      PARTITIONS (6);

  Sie können die Anzahl der von `t2` verwendeten Partitionen nun mit der folgenden Anweisung von 6 auf 4 verringern:

      ALTER TABLE t2 COALESCE PARTITION 2;

  Die in den letzten `number` Partitionen enthaltenen Daten werden in die verbleibenden Partitionen eingefügt. In diesem Fall werden die Partitionen 4 und 5 in die ersten vier Partitionen (0 bis 3) eingefügt.

  Um einige, aber nicht alle Partitionen zu ändern, die von einer partitionierten Tabelle verwendet werden, können Sie `REORGANIZE PARTITION` verwenden. Diese Anweisung kann auf mehrere Arten verwendet werden:

  - Um mehrere Partitionen zu einer zusammenzufassen. Hierzu zählen Sie mehrere Partitionen in der `partition_names`-Liste auf und geben genau eine Definition für `partition_definition` an.

  - Um eine vorhandene Partition in mehrere Partitionen aufzuspalten. Hierzu benennen Sie genau eine Partition für `partition_names` und geben in `partition_definitions` mehrere Definitionen an.

  - Um die Bereiche für eine Teilmenge der Partitionen, die mit `VALUES LESS THAN` definiert wird, oder die Wertelisten für eine Teilmenge der Partitionen zu ändern, die mit `VALUES IN` definiert wird.

  Hinweis: Bei Partitionen, die nicht explizit aufgeführt wurden, verwendet MySQL automatisch die Standardnamen `p0`, `p1`, `p2` usw.

  Weitere Informationen zu `ALTER TABLE ... REORGANIZE PARTITION`-Anweisungen und zugehörige Beispiele finden Sie in Abschnitt 17.3, „Partitionsverwaltung“.

- Mehrere zusätzliche Klauseln ermöglichen die Wartung und Reparatur von Partitionen analog zu der Art und Weise, wie diese Funktionalitäten bei nicht partitionierten Tabellen durch Anweisungen wie `CHECK TABLE` und `REPAIR TABLE` (welche von partitionierten Tabellen nicht unterstützt werden) implementiert sind. Hierzu gehören `ANALYZE PARTITION`, `CHECK PARTITION`, `OPTIMIZE PARTITION`, `REBUILD PARTITION` und `REPAIR PARTITION`. Jede dieser Optionen nimmt eine `partition_names`-Klausel entgegen, die einen oder mehrere durch Kommata getrennte Partitionsnamen umfasst. Die Partitionen müssen in der zu ändernden Tabelle bereits vorhanden sein. Weitere Informationen hierzu und zugehörige Beispiele finden Sie in Abschnitt 17.3.3, „Wartung von Partitionen“.

Mit der C-API-Funktion `mysql_info()` können Sie ermitteln, wie viele Datensätze kopiert und (sofern `IGNORE` verwendet wird) aufgrund doppelt vorhandener eindeutiger Schlüsselwerte gelöscht wurden. Siehe auch Abschnitt 24.2.3.34, „`mysql_info()`“.

Es folgen ein paar Beispiele, die Anwendungsmöglichkeiten für `ALTER TABLE` zeigen. Beginnen wir mit einer Tabelle `t1`, die wie folgt erstellt wird:

    CREATE TABLE t1 (a INTEGER,b CHAR(10));

So benennen Sie die Tabelle von `t1` in `t2` um:

    ALTER TABLE t1 RENAME t2;

So ändern Sie den Typ der Spalte `a` von `INTEGER` auf `TINYINT NOT NULL` (wobei der Name erhalten bleibt) und den Typ der Spalte `b` von `CHAR(10)` zu `CHAR(20)` sowie deren Namen von `b` zu `c`:

    ALTER TABLE t2 MODIFY a TINYINT NOT NULL, CHANGE b c CHAR(20);

So fügen Sie eine neue `TIMESTAMP`-Spalte namens `d` hinzu:

    ALTER TABLE t2 ADD d TIMESTAMP;

So fügen Sie Indizes zu den Spalten `d` und `a` hinzu:

    ALTER TABLE t2 ADD INDEX (d), ADD INDEX (a);

So entfernen Sie die Spalte `c`:

    ALTER TABLE t2 DROP COLUMN c;

So fügen Sie eine neue `AUTO_INCREMENT`-Spalte namens `c` hinzu:

    ALTER TABLE t2 ADD c INT UNSIGNED NOT NULL AUTO_INCREMENT,
      ADD PRIMARY KEY (c);

Beachten Sie, dass wir `c` (als `PRIMARY KEY`) indiziert haben, weil `AUTO_INCREMENT`-Spalten indiziert werden müssen, und dass wir außerdem `c` als `NOT NULL` deklariert haben, weil Primärschlüsselspalten nicht `NULL` sein dürfen.

Wenn Sie eine `AUTO_INCREMENT`-Spalte hinzufügen, werden als Spaltenwerte automatisch Sequenznummern eingetragen. Bei `MyISAM`-Tabellen können Sie die erste Sequenznummer durch Ausführung von `SET INSERT_ID=`value`` vor `ALTER TABLE` oder durch Verwendung der Tabellenoption `AUTO_INCREMENT=`value`` einstellen. Siehe auch Abschnitt 13.5.3, „`SET`“.

Sie können die Tabellenoption `ALTER TABLE ... AUTO_INCREMENT=`value`` bei `InnoDB`-Tabellen zur Einstellung der Sequenznummer für neue Datensätze benutzen, wenn der Wert größer ist als der höchste Wert in der `AUTO_INCREMENT`-Spalte. Ist der Wert kleiner als der aktuelle Maximalwert der Spalte, dann wird keine Fehlermeldung ausgegeben, und der aktuelle Sequenzwert wird nicht geändert.

Wenn Sie bei `MyISAM`-Tabellen die `AUTO_INCREMENT`-Spalte nicht ändern, ist die Sequenznummer nicht betroffen. Wenn Sie eine `AUTO_INCREMENT`-Spalte löschen und dann eine neue `AUTO_INCREMENT`-Spalte hinzufügen, beginnen die Sequenznummern wieder bei 1.

Siehe auch Abschnitt A.7.1, „Probleme mit `ALTER TABLE`“.

### 13.1.3. `CREATE DATABASE`

    CREATE {DATABASE | SCHEMA} [IF NOT EXISTS] db_name
        [create_specification [, create_specification] ...]

    create_specification:
        [DEFAULT] CHARACTER SET charset_name
      | [DEFAULT] COLLATE collation_name

`CREATE DATABASE` erstellt eine Datenbank des angegebenen Namens. Um `CREATE DATABASE` verwenden zu können, benötigen Sie die Berechtigung `CREATE` für die Datenbank. `CREATE SCHEMA` ist ein Synonym für `CREATE DATABASE`.

Die Regeln für zulässige Datenbanknamen sind in Abschnitt 9.2, „Datenbank-, Tabellen-, Index-, Spalten- und Aliasnamen“, beschrieben. Wenn die Datenbank vorhanden ist und Sie `IF NOT EXISTS` nicht angegeben haben, tritt ein Fehler auf.

`create_specification`-Optionen geben die Datenbankeigenschaften an. Diese Datenbankeigenschaften sind in der Datei `db.opt` im Datenbankverzeichnis gespeichert. Die Klausel `CHARACTER SET` gibt den Standardzeichensatz der Datenbank an. Die Klausel `COLLATE` gibt die Standardsortierfolge der Datenbank an. Kapitel 10, Zeichensatz-Unterstützung, behandelt Namen von Zeichensätzen und Sortierfolgen.

Datenbanken werden in MySQL als Verzeichnisse implementiert, die Dateien enthalten, welche den Tabellen der Datenbank entsprechen. Weil bei der Erstellung einer Datenbank noch keine Tabellen vorhanden sind, erzeugt die Anweisung `CREATE DATABASE` lediglich ein Verzeichnis im MySQL-Datenverzeichnis sowie die Datei `db.opt`.

Wenn Sie manuell (z. B. mit mkdir) ein Verzeichnis im Datenverzeichnis erstellen, betrachtet der Server dieses als Datenbankverzeichnis und zeigt es in der Ausgabe von `SHOW DATABASES` an.

Sie können zur Erstellung von Datenbanken auch das Programm mysqladmin verwenden. Siehe auch Abschnitt 8.7, „mysqladmin — Client für die Verwaltung eines MySQL Servers“.

### 13.1.4. `CREATE INDEX`

    CREATE [UNIQUE|FULLTEXT|SPATIAL] INDEX index_name
        [USING index_type]
        ON tbl_name (index_col_name,...)
        [WITH PARSER parser_name]

    index_col_name:
        col_name [(length)] [ASC | DESC]

`CREATE INDEX` wird mit einer `ALTER TABLE`-Anweisung verknüpft, um Indizes zu erstellen. Siehe auch Abschnitt 13.1.2, „`ALTER TABLE`“. Weitere Informationen dazu, wie MySQL Indizes verwendet, finden Sie in Abschnitt 7.4.5, „Wie MySQL Indizes benutzt“.

Normalerweise erstellen Sie alle Indizes für eine Tabelle zu dem Zeitpunkt, an dem Sie auch die Tabelle selbst mit `CREATE TABLE` anlegen. Siehe auch Abschnitt 13.1.5, „`CREATE TABLE`“. `CREATE INDEX` erlaubt Ihnen das Hinzufügen von Indizes zu vorhandenen Tabellen.

Eine Spaltenliste in der Form `(col1,col2,...)` erstellt einen mehrspaltigen Index. Indexwerte werden gebildet, indem die Werte der betreffenden Spalten verkettet werden.

Bei `CHAR`-, `VARCHAR`-, `BINARY`- und `VARBINARY`-Spalten können Indizes erstellt werden, die nur einen Teil einer Spalte verwenden. Hier verwenden Sie die Syntax ``col_name`(`length`)`, um die Länge des Indexpräfixes anzugeben. Indexeinträge umfassen dann die ersten `length` Zeichen jedes Spaltenwerts bei `CHAR`- und `VARCHAR`-Spalten sowie die ersten `length` Bytes jedes Spaltenwerts bei `BINARY`- und `VARBINARY`-Spalten. `BLOB`- und `TEXT`-Spalten lassen sich auch indizieren, aber eine Präfixlänge muss angegeben werden.

Die folgende Anweisung erstellt einen Index unter Verwendung der ersten zehn Zeichen der Spalte `name`:

    CREATE INDEX part_of_name ON customer (name(10));

Wenn die ersten zehn Zeichen aller Namen in der Spalte sich durchgehend unterscheiden, dann sollte dieser Index nicht viel langsamer sein als ein Index, der aus der gesamten Spalte `name` erstellt wurde. Auch die Verwendung von Teilspalten für Indizes kann die Indexdatei wesentlich kleiner machen, wodurch sich viel Festplattenspeicher sparen lässt und `INSERT`-Operationen unter Umständen auch beschleunigt werden können.

Präfixe können bis 1.000 Byte lang sein (767 Byte bei `InnoDB`-Tabellen). Beachten Sie, dass Präfixbeschränkungen in Byte angegeben werden, wohingegen die Präfixlänge in `CREATE INDEX`-Anweisungen bei nichtbinären Datentypen (`CHAR`, `VARCHAR`, `TEXT`) als Anzahl der Zeichen interpretiert wird. Dies muss bei der Angabe einer Präfixlänge für eine Spalte berücksichtigt werden, die einen Multibytezeichensatz verwendet.

In MySQL 5.1 können Sie

- einen Index für eine Spalte, die `NULL`-Werte enthalten kann, nur dann hinzufügen, wenn Sie die Speicher-Engines `MyISAM`, `InnoDB`, `BDB` oder `MEMORY` verwenden,

- einen Index für eine `BLOB`- oder `TEXT`-Spalte nur dann hinzufügen, wenn Sie die Speicher-Engines `MyISAM`, `BDB` oder `InnoDB` verwenden.

Eine `index_col_name`-Definition kann auf `ASC` oder `DESC` enden. Diese Schlüsselwörter sind für zukünftige Erweiterungen zulässig, um eine Speicherung der Indexwerte in auf- oder absteigender Reihenfolge festzulegen. Zurzeit werden sie zwar erkannt, aber ignoriert – Indexwerte werden immer in aufsteigender Reihenfolge gespeichert.

Einige Speicher-Engines gestatten bei der Erstellung eines Indexes die Angabe eines Indextyps. Die Syntax für die Konfigurationsangabe `index_type` lautet `USING `type_name``. Zulässige Werte für `type_name`, die von den verschiedenen Speicher-Engines unterstützt werden, sind in der folgenden Tabelle aufgelistet. Sind mehrere Indextypen aufgeführt, so wird der erste standardmäßig verwendet, wenn keine Angabe für `index_type` vorhanden ist.

Speicher-Engine | Zulässige Indextypen
`MyISAM` | `BTREE`
`InnoDB` | `BTREE`
`MEMORY`/`HEAP` | `HASH`, `BTREE`

Ein paar Beispiele:

    CREATE TABLE lookup (id INT) ENGINE = MEMORY;
    CREATE INDEX id_index USING BTREE ON lookup (id);

`TYPE `type_name`` kann als Synonym für `USING `type_name`` benutzt werden, um einen Indextyp anzugeben. Allerdings ist `USING` die bevorzugte Form. Ferner ist der Indexname, der in der Syntax zur Indexspezifikation vor dem Indextyp steht, bei `TYPE` nicht optional: Anders als `USING` ist `TYPE` kein reserviertes Wort und wird infolgedessen nicht als Indexname interpretiert.

Wenn Sie einen Indextyp angeben, der für eine gegebene Speicher-Engine nicht zulässig ist, aber ein anderer Indextyp vorhanden ist, den die Engine verwenden kann, ohne dass hiervon Abfrageergebnisse betroffen wären, dann verwendet die Engine diesen verfügbaren Typ.

`FULLTEXT`-Indizes werden nur für `MyISAM`-Tabellen unterstützt und dürfen nur `CHAR`-, `VARCHAR`- und `TEXT`-Spalten enthalten. Siehe auch Abschnitt 12.7, „MySQL-Volltextsuche“. Eine `WITH PARSER`-Klausel kann angegeben werden, um ein Parser-Plug-In mit dem Index zu verknüpfen, wenn Volltextindizierungs- und Suchoperationen besondere Maßnahmen erfordern. Diese Klausel ist nur für `FULLTEXT`-Indizes zulässig. Informationen zur Erstellung von Plug-Ins finden Sie in Abschnitt 26.2, „Die MySQL-Plug-In-Schnittstelle“.

`SPATIAL`-Indizes werden nur für `MyISAM`-Tabellen unterstützt und dürfen nur raumbezogene Spalten enthalten, die als `NOT NULL` definiert sind. Kapitel 18, Raumbezogene Erweiterungen in MySQL, beschreibt raumbezogene Datentypen.

### 13.1.5. `CREATE TABLE`

    CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name
        [(create_definition,...)]
        [table_options] [select_statement]

Oder:

    CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name
        [(] LIKE old_tbl_name [)];

    create_definition:
        column_definition
      | [CONSTRAINT [symbol]] PRIMARY KEY [index_type] (index_col_name,...)
      | KEY [index_name] [index_type] (index_col_name,...)
      | INDEX [index_name] [index_type] (index_col_name,...)
      | [CONSTRAINT [symbol]] UNIQUE [INDEX]
            [index_name] [index_type] (index_col_name,...)
      | FULLTEXT [INDEX] [index_name] (index_col_name,...)
          [WITH PARSER parser_name]
      | SPATIAL [INDEX] [index_name] (index_col_name,...)
      | [CONSTRAINT [symbol]] FOREIGN KEY
            [index_name] (index_col_name,...) [reference_definition]
      | CHECK (expr)

    column_definition:
        col_name type [NOT NULL | NULL] [DEFAULT default_value]
            [AUTO_INCREMENT] [UNIQUE [KEY] | [PRIMARY] KEY]
            [COMMENT 'string'] [reference_definition]

    type:
        TINYINT[(length)] [UNSIGNED] [ZEROFILL]
      | SMALLINT[(length)] [UNSIGNED] [ZEROFILL]
      | MEDIUMINT[(length)] [UNSIGNED] [ZEROFILL]
      | INT[(length)] [UNSIGNED] [ZEROFILL]
      | INTEGER[(length)] [UNSIGNED] [ZEROFILL]
      | BIGINT[(length)] [UNSIGNED] [ZEROFILL]
      | REAL[(length,decimals)] [UNSIGNED] [ZEROFILL]
      | DOUBLE[(length,decimals)] [UNSIGNED] [ZEROFILL]
      | FLOAT[(length,decimals)] [UNSIGNED] [ZEROFILL]
      | DECIMAL(length,decimals) [UNSIGNED] [ZEROFILL]
      | NUMERIC(length,decimals) [UNSIGNED] [ZEROFILL]
      | DATE
      | TIME
      | TIMESTAMP
      | DATETIME
      | YEAR
      | CHAR(length) [BINARY | ASCII | UNICODE]
      | VARCHAR(length) [BINARY]
      | BINARY(length)
      | VARBINARY(length)
      | TINYBLOB
      | BLOB
      | MEDIUMBLOB
      | LONGBLOB
      | TINYTEXT [BINARY]
      | TEXT [BINARY]
      | MEDIUMTEXT [BINARY]
      | LONGTEXT [BINARY]
      | ENUM(value1,value2,value3,...)
      | SET(value1,value2,value3,...)
      | spatial_type

    index_col_name:
        col_name [(length)] [ASC | DESC]

    reference_definition:
        REFERENCES tbl_name [(index_col_name,...)]
                   [MATCH FULL | MATCH PARTIAL | MATCH SIMPLE]
                   [ON DELETE reference_option]
                   [ON UPDATE reference_option]

    reference_option:
        RESTRICT | CASCADE | SET NULL | NO ACTION

    table_options: table_option [table_option] ...

    table_option:
        {ENGINE|TYPE} [=] engine_name
      | AUTO_INCREMENT [=] value
      | AVG_ROW_LENGTH [=] value
      | [DEFAULT] CHARACTER SET charset_name [COLLATE collation_name]
      | CHECKSUM [=] {0 | 1}
      | COMMENT [=] 'string'
      | CONNECTION [=] 'connect_string'
      | MAX_ROWS [=] value
      | MIN_ROWS [=] value
      | PACK_KEYS [=] {0 | 1 | DEFAULT}
      | PASSWORD [=] 'string'
      | DELAY_KEY_WRITE [=] {0 | 1}
      | ROW_FORMAT [=] {DEFAULT|DYNAMIC|FIXED|COMPRESSED|REDUNDANT|COMPACT}
      | UNION [=] (tbl_name[,tbl_name]...)
      | INSERT_METHOD [=] { NO | FIRST | LAST }
      | DATA DIRECTORY [=] 'absolute path to directory'
      | INDEX DIRECTORY [=] 'absolute path to directory'

    partition_options:
        PARTITION BY
               [LINEAR] HASH(expr)
            |  [LINEAR] KEY(column_list)
            |  RANGE(expr)
            |  LIST(expr)
        [PARTITIONS num]
        [  SUBPARTITION BY
               [LINEAR] HASH(expr)
             | [LINEAR] KEY(column_list)
          [SUBPARTITIONS num]
        ]
        [(partition_definition) [, (partition_definition)] ...]

    partition_definition:
        PARTITION partition_name
            [VALUES {LESS THAN (expr) | MAXVALUE | IN (value_list)}]
            [[STORAGE] ENGINE [=] engine-name]
            [COMMENT [=] 'comment_text' ]
            [DATA DIRECTORY [=] 'data_dir']
            [INDEX DIRECTORY [=] 'index_dir']
            [MAX_ROWS [=] max_number_of_rows]
            [MIN_ROWS [=] min_number_of_rows]
            [TABLESPACE [=] (tablespace_name)]
            [NODEGROUP [=] node_group_id]
            [(subpartition_definition) [, (subpartition_definition)] ...]

    subpartition_definition:
        SUBPARTITION logical_name
            [[STORAGE] ENGINE [=] engine-name]
            [COMMENT [=] 'comment_text' ]
            [DATA DIRECTORY [=] 'data_dir']
            [INDEX DIRECTORY [=] 'index_dir']
            [MAX_ROWS [=] max_number_of_rows]
            [MIN_ROWS [=] min_number_of_rows]
            [TABLESPACE [=] (tablespace_name)]
            [NODEGROUP [=] node_group_id]

    select_statement:
        [IGNORE | REPLACE] [AS] SELECT ...   (Some legal select statement)

`CREATE TABLE` erstellt eine Tabelle des angegebenen Namens. Für die Tabelle benötigen Sie die Berechtigung `CREATE`.

Die Regeln für zulässige Tabellennamen sind in Abschnitt 9.2, „Datenbank-, Tabellen-, Index-, Spalten- und Aliasnamen“, beschrieben. Standardmäßig wird die Tabelle in der Standarddatenbank erstellt. Wenn die Tabelle bereits vorhanden ist oder weder die Standarddatenbank noch die angegebene Datenbank vorhanden sind, wird ein Fehler erstellt.

Der Tabellenname kann als `db_name.tbl_name` angegeben werden, um die Tabelle in einer bestimmten Datenbank zu erstellen. Das funktioniert unabhängig vom Vorhandensein einer Standarddatenbank, sofern die angegebene Datenbank vorhanden ist. Wenn Sie Bezeichner in Anführungszeichen verwenden, setzen Sie Datenbank- und Tabellennamen separat in Anführungszeichen. So ist etwa ``mydb`.`mytbl`` zulässig – anders als ``mydb.mytbl``.

Sie können das Schlüsselwort `TEMPORARY` bei der Erstellung einer Tabelle verwenden. Eine `TEMPORARY`-Tabelle ist nur für die aktuelle Verbindung sichtbar und wird beim Beenden dieser Verbindung automatisch gelöscht. Das bedeutet, dass zwei verschiedene Verbindungen Temporärtabellen desselben Namens verwenden können, ohne dass es zu Konflikten mit der jeweils anderen Tabelle oder einer nichttemporären Tabelle gleichen Namens kommt. (Die vorhandene Tabelle wird verborgen, bis die Temporärtabelle gelöscht wird.) Zur Erstellung von Temporärtabellen benötigen Sie die Berechtigung `CREATE TEMPORARY TABLES`.

Die Schlüsselwörter `IF NOT EXISTS` verhindern, dass ein Fehler auftritt, wenn die Tabelle vorhanden ist. Allerdings wird nicht überprüft, ob die vorhandene Tabelle die gleiche Struktur wie die in der `CREATE TABLE`-Anweisung angegebene Tabelle hat. Hinweis: Wenn Sie `IF NOT EXISTS` in einer `CREATE TABLE ... SELECT`-Anweisung verwenden, werden alle durch den `SELECT`-Teil gewählten Datensätze ohne Berücksichtigung der Frage eingefügt, ob die Tabelle bereits vorhanden ist.

MySQL stellt jede Tabelle durch eine `.frm`-Tabellenformatdatei (Definitionsdatei) im Datenbankverzeichnis dar. Die Speicher-Engine der Tabelle erstellt unter Umständen auch andere Dateien. Im Falle von `MyISAM`-Tabellen erstellt die Speicher-Engine Daten- und Indexdateien. Es gibt also für jede `MyISAM`-Tabelle `tbl_name` drei Dateien auf der Festplatte:

Datei | Zweck
``tbl_name`.frm` | Tabellenformatdatei (Definitionsdatei)
``tbl_name`.MYD` | Datendatei
``tbl_name`.MYI` | Indexdatei

Kapitel 14, Speicher-Engines und Tabellentypen, beschreibt, welche Dateien die einzelnen Speicher-Engines zur Darstellung von Tabellen erstellen.

`type` stellt den Datentyp einer Spaltendefinition dar. `spatial_type` ist ein raumbezogener Datentyp. Allgemeine Informationen zu den Eigenschaften von Datentypen (außer raumbezogenen Datentypen) finden Sie in Kapitel 11, Datentypen. Informationen zu raumbezogenen Datentypen finden Sie in Kapitel 18, Raumbezogene Erweiterungen in MySQL.

- Wenn weder `NULL` noch `NOT NULL` angegeben sind, wird die Spalte so behandelt, als ob `NULL` angegeben worden wäre.

- Eine Integer-Spalte kann das Zusatzattribut `AUTO_INCREMENT` erhalten. Wenn Sie den Wert `NULL` (empfohlen) oder `0` in eine indizierte `AUTO_INCREMENT`-Spalte einfügen, wird die Spalte auf den nächsten Sequenzwert gesetzt. Normalerweise ist dies ``value`+1`, wobei `value` der derzeit größte Wert der Spalte in der Tabelle ist. `AUTO_INCREMENT`-Sequenzen beginnen bei `1`.

  Um einen `AUTO_INCREMENT`-Wert nach Einfügen eines Datensatzes abzurufen, verwenden Sie die SQL-Funktion `LAST_INSERT_ID()` oder die C-API-Funktion `mysql_insert_id()`. Siehe auch Abschnitt 12.10.3, „Informationsfunktionen“, und Abschnitt 24.2.3.36, „`mysql_insert_id()`“.

  Wenn der SQL-Modus `NO_AUTO_VALUE_ON_ZERO` aktiviert ist, können Sie `0` in `AUTO_INCREMENT`-Spalten als `0` speichern, ohne einen neuen Sequenzwert zu erzeugen. Siehe auch Abschnitt 5.2.5, „Der SQL-Modus des Servers“.

  Hinweis: Es kann nur eine `AUTO_INCREMENT`-Spalte pro Tabelle geben. Diese muss indiziert sein und darf keinen Standardwert haben. Eine `AUTO_INCREMENT`-Spalte funktioniert nur dann einwandfrei, wenn sie ausschließlich positive Werte enthält. Das Einfügen eines negativen Werts wird als Einfügen einer sehr großen positiven Zahl aufgefasst. Dies wird gemacht, um genauigkeitsspezifische Probleme zu vermeiden, die beim „Umklappen“ von positiven auf negative Zahlen auftreten können, und um zu gewährleisten, dass Sie nicht versehentlich eine `AUTO_INCREMENT`-Spalte erhalten, die `0` enthält.

  Bei `MyISAM`- und `BDB`-Tabellen können Sie `AUTO_INCREMENT` in einer Sekundärspalte eines mehrspaltigen Schlüssels angeben. Siehe auch Abschnitt 3.6.9, „Verwendung von `AUTO_INCREMENT`“.

  Um MySQL mit einigen ODBC-Anwendungen kompatibel zu machen, können Sie den `AUTO_INCREMENT`-Wert für den letzten eingefügten Datensatz mit der folgenden Abfrage ermitteln:

      SELECT * FROM tbl_name WHERE auto_col IS NULL

- Das Attribut `SERIAL` kann als Alias für `BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE` verwendet werden.

- Zeichendatentypen (`CHAR`, `VARCHAR`, `TEXT`) können `CHARACTER SET`- und `COLLATE`-Attribute zur Angabe von Zeichensatz und Sortierfolge der Spalte enthalten. Weitere Informationen finden Sie in Kapitel 10, Zeichensatz-Unterstützung. `CHARSET` ist ein Synonym für `CHARACTER SET`. Beispiel:

      CREATE TABLE t (c CHAR(20) CHARACTER SET utf8 COLLATE utf8_bin);

  MySQL 5.1 interpretiert Längenangaben in Zeichenspaltendefinitionen als Anzahl von Zeichen. (Versionen vor MySQL 4.1 interpretierten sie als Anzahl von Bytes.)

- Die `DEFAULT`-Klausel gibt einen Vorgabewert für eine Spalte an. Mit einer Ausnahme muss der Vorgabewert immer eine Konstante sein. Funktionen oder Ausdrücke sind als Vorgabe nicht zulässig. Das bedeutet, dass Sie beispielsweise als Vorgabewert einer Datumsspalte nicht den Wert einer Funktion wie `NOW()` oder `CURRENT_DATE` angeben dürfen. Die genannte Ausnahme besteht darin, dass Sie `CURRENT_TIMESTAMP` als Vorgabe für eine `TIMESTAMP`-Spalte festlegen können. Siehe auch Abschnitt 11.3.1.1, „`TIMESTAMP`-Eigenschaften ab MySQL 4.1“.

  Wenn eine Spaltendefinition keinen expliziten `DEFAULT`-Wert enthält, bestimmt MySQL diesen wie in Abschnitt 11.1.4, „Vorgabewerte von Datentypen“, beschrieben.

  Für `BLOB`- und `TEXT`-Spalten können keine Vorgaben festgelegt werden.

- Ein Kommentar für eine Spalte kann mit der Option `COMMENT` angegeben werden. Der Kommentar wird über die Anweisungen `SHOW CREATE TABLE` und `SHOW FULL COLUMNS` angezeigt.

- `KEY` ist normalerweise ein Synonym für `INDEX`. Das Schlüsselattribut `PRIMARY KEY` kann auch einfach als `KEY` angegeben werden, sofern die Angabe in einer Spaltendefinition erfolgt. Dieses Verhalten wurde aus Gründen der Kompatibilität mit anderen Datenbanksystemen implementiert.

- Ein eindeutiger Index ist dahingehend eingeschränkt, dass alle Werte im Index eindeutig sein müssen. Wenn Sie einen neuen Datensatz mit einem Schlüssel hinzufügen, der dem eines vorhandenen Datensatzes entspricht, tritt ein Fehler auf. Eine Ausnahme hierzu besteht darin, dass, wenn eine Spalte im Index `NULL`-Werte enthalten darf, diese mehrere `NULL`-Werte enthalten kann. Diese Ausnahme gilt jedoch nicht für `BDB`-Tabellen, bei denen eine Spalte mit einem eindeutigen Index `NULL` nur einmalig gestattet.

- Ein Primärschlüssel ist ein eindeutiger Index, bei dem alle Schlüsselspalten als `NOT NULL` definiert sein müssen. Wenn sie nicht explizit als `NOT NULL` deklariert sind, holt MySQL dies implizit (und stillschweigend) nach. Eine Tabelle darf nur einen Primärschlüssel enthalten. Wenn Sie keinen Primärschlüssel haben und eine Anwendung nach dem Primärschlüssel in Ihren Tabellen fragt, gibt MySQL als Primärschlüssel den ersten eindeutigen Index zurück, der keine `NULL`-Spalten verwendet.

- In der erstellten Tabelle wird der Primärschlüssel an die erste Position gesetzt, gefolgt von allen eindeutigen Indizes und nachfolgend den nichteindeutigen Indizes. Dies erleichtert dem MySQL-Optimierer die Priorisierung der zu verwendenden Indizes und die schnelle Erkennung von Dubletten bei den `UNIQUE`-Schlüsseln.

- Ein Primärschlüssel kann ein mehrspaltiger Index sein. Sie können allerdings keinen mehrspaltigen Index mithilfe des Schlüsselattributs `PRIMARY KEY` in einer Spaltendefinition erstellen. Wenn Sie dies tun, wird nur diese eine Spalte als Primärschlüssel gekennzeichnet. Sie müssen hierzu eine separate `PRIMARY KEY(index_col_name, ...)`-Klausel verwenden.

- Wenn ein Primärschlüssel oder ein eindeutiger Index aus nur einer Spalte eines Integer-Typs bestehen, können Sie die Spalte auch in `SELECT`-Anweisungen als `_rowid` referenzieren.

- In MySQL lautet der Name eines Primärschlüssels `PRIMARY`. Bei anderen Indizes erhält, sofern Sie keinen Namen angeben, der Index jeweils denselben Namen wie die erste indizierte Spalte. Es kann optional ein Suffix (`_2`, `_3`, `...`) angegeben werden, um den Index eindeutig zu machen. Sie können die Indexnamen für eine Tabelle mit `SHOW INDEX FROM `tbl_name`` anzeigen. Siehe auch Abschnitt 13.5.4.12, „`SHOW INDEX`“.

- Einige Speicher-Engines gestatten bei der Erstellung eines Indexes die Angabe eines Indextyps. Die Syntax für die Konfigurationsangabe `index_type` lautet `USING `type_name``.

  Beispiel:

      CREATE TABLE lookup
        (id INT, INDEX USING BTREE (id))
        ENGINE = MEMORY;

  Detaillierte Informationen zu `USING` finden Sie in Abschnitt 13.1.4, „`CREATE INDEX`“.

  Weitere Informationen dazu, wie MySQL Indizes verwendet, finden Sie in Abschnitt 7.4.5, „Wie MySQL Indizes benutzt“.

- In MySQL 5.1 unterstützen nur die Speicher-Engines `MyISAM`, `InnoDB`, `BDB` und `MEMORY` Indizes bei Spalten, die `NULL`-Werte enthalten. In anderen Fällen müssen Sie indizierte Spalten als `NOT NULL` deklarieren, andernfalls wird ein Fehler zurückgegeben.

- Mit der Syntax ``col_name`(`length`)` in einer Indexdefinition können Sie einen Index erstellen, der die Spalte nur teilweise verwendet. Indexeinträge umfassen die ersten `length` Zeichen jedes Spaltenwerts bei `CHAR`- und `VARCHAR`-Spalten sowie die ersten `length` Bytes jedes Spaltenwerts bei `BINARY`- und `VARBINARY`-Spalten. Wenn Sie auf diese Weise nur ein Präfix der Spaltenwerte indizieren, kann dies die Indexdatei erheblich kleiner machen. Siehe auch Abschnitt 7.4.3, „Spaltenindizes“.

  Die Speicher-Engines `MyISAM`, `BDB` und `InnoDB` unterstützen die Indizierung von `BLOB`- und `TEXT`-Spalten. Bei der Indizierung einer `BLOB`- oder `TEXT`-Spalte müssen Sie eine Präfixlänge für den Index angeben. Zum Beispiel:

      CREATE TABLE test (blob_col BLOB, INDEX(blob_col(10)));

  Präfixe können bis 1.000 Byte lang sein (767 Byte bei `InnoDB`-Tabellen). Beachten Sie, dass Präfixbeschränkungen in Byte angegeben werden, wohingegen die Präfixlänge in `CREATE TABLE`-Anweisungen bei nichtbinären Datentypen (`CHAR`, `VARCHAR`, `TEXT`) als Anzahl der Zeichen interpretiert wird. Dies muss bei der Angabe einer Präfixlänge für eine Spalte berücksichtigt werden, die einen Multibytezeichensatz verwendet.

- Eine `index_col_name`-Definition kann auf `ASC` oder `DESC` enden. Diese Schlüsselwörter sind für zukünftige Erweiterungen zulässig, um eine Speicherung der Indexwerte in auf- oder absteigender Reihenfolge festzulegen. Zurzeit werden sie zwar erkannt, aber ignoriert – Indexwerte werden immer in aufsteigender Reihenfolge gespeichert.

- Wenn Sie `ORDER BY` oder `GROUP BY` für eine `TEXT`- oder `BLOB`-Spalte in einer `SELECT`-Anweisung verwenden, sortiert der Server Werte lediglich unter Verwendung der ersten Bytes. Wie viele Bytes dies sind, wird von der Systemvariablen `max_sort_length` angegeben. Siehe auch Abschnitt 11.4.3, „Die Spaltentypen `BLOB` und `TEXT`“.

- Sie können spezielle Volltextindizes erstellen, die für die Volltextsuche verwendet werden. Nur die `MyISAM`-Speicher-Engine unterstützt Volltextindizes. Diese können nur aus `CHAR`-, `VARCHAR`- und `TEXT`-Spalten erstellt werden. Die Indizierung erfolgt immer über die gesamte Spalte: Eine Teilindizierung wird nicht unterstützt, und ein eventuell angegebenes Präfix wird ignoriert. Weitere Informationen finden Sie in Abschnitt 12.7, „MySQL-Volltextsuche“. Eine `WITH PARSER`-Klausel kann angegeben werden, um ein Parser-Plug-In mit dem Index zu verknüpfen, wenn Volltextindizierungs- und Suchoperationen besondere Maßnahmen erfordern. Diese Klausel ist nur für `FULLTEXT`-Indizes zulässig. Informationen zur Erstellung von Plug-Ins finden Sie in Abschnitt 26.2, „Die MySQL-Plug-In-Schnittstelle“.

- `SPATIAL`-Indizes können Sie für raumbezogene Typen erstellen. Solche Typen werden nur für `MyISAM`-Tabellen unterstützt, und indizierte Spalten müssen als `NOT NULL` deklariert sein. Siehe auch Kapitel 18, Raumbezogene Erweiterungen in MySQL.

- `InnoDB`-Tabellen unterstützen die Überprüfung von Fremdschlüssel-Constraints. Siehe auch Abschnitt 14.2, „`InnoDB`-Tabellen“. Beachten Sie, dass die Fremdschlüsselsyntax in `InnoDB` restriktiver ist als die zu Beginn dieses Abschnitts für die `CREATE TABLE`-Anweisung präsentierte Syntax: Die Spalten der referenzierten Tabellen müssen immer explizit genannt werden. `InnoDB` unterstützt sowohl `ON DELETE`- als auch `ON UPDATE`-Aktionen für Fremdschlüssel. Informationen zur exakten Syntax finden Sie in Abschnitt 14.2.6.4, „Fremdschlüssel-Beschränkungen“.

  Bei anderen Speicher-Engines erkennt MySQL Server die `FOREIGN KEY`- und `REFERENCES`-Syntax in `CREATE TABLE`-Anweisungen, ignoriert sie aber. Zudem wird die Klausel `CHECK` von allen Speicher-Engines erkannt, aber ignoriert. Siehe auch Abschnitt 1.9.5.5, „Fremdschlüssel“.

- Bei `MyISAM`-Tabellen benötigt jede `NULL`-Spalte ein zusätzliches Bit, aufgerundet auf das nächste Byte. Die maximale Datensatzlänge in Byte kann wie folgt berechnet werden:

      row length = 1
                   + (sum of column lengths)
                   + (number of NULL columns + delete_flag + 7)/8
                   + (number of variable-length columns)

  `delete_flag` ist 1 bei Tabellen mit statischem Datensatzformat. Statische Tabellen verwenden ein Bit im Datensatz für ein Flag, das angibt, ob der Datensatz gelöscht wurde. `delete_flag` ist 0 bei dynamischen Tabellen, weil das Flag im dynamischen Datensatz-Header gespeichert wird.

  Diese Berechnungen gelten nicht für `InnoDB`-Tabellen, bei denen der Speicherbedarf von `NULL`-Spalten sich nicht von dem von `NOT NULL`-Spalten unterscheidet.

Die Tabellenoption `ENGINE` gibt die Speicher-Engine für die Tabelle an. `TYPE` ist ein Synonym hierzu, wobei `ENGINE` der bevorzugte Name ist.

Die Tabellenoption `ENGINE` akzeptiert die in der folgenden Tabelle aufgeführten Namen für Speicher-Engines.

Speicher-Engine | Beschreibung
`ARCHIVE` | Speicher-Engine zur Archivierung. Siehe auch Abschnitt 14.8, „Die `ARCHIVE`-Speicher-Engine“.
`BDB` | Transaktionssichere Tabellen mit Seitensperrung. Heißt auch `BerkeleyDB`. Siehe auch Abschnitt 14.5, „Die `BDB`-Speicher-Engine“.
`CSV` | Tabellen, die Datensätze als kommagetrennte Werte speichern. Siehe auch Abschnitt 14.9, „Die `CSV`-Speicher-Engine“.
`EXAMPLE` | Eine Beispiel-Engine. Siehe auch Abschnitt 14.6, „Die `EXAMPLE`-Speicher-Engine“.
`FEDERATED` | Speicher-Engine, die auf entfernte Tabellen zugreift. Siehe auch Abschnitt 14.7, „Die `FEDERATED`-Speicher-Engine“.
`HEAP` | Ein Synonym für `MEMORY`.
`ISAM` (VERALTET) | In MySQL 5.1 nicht verfügbar. Wenn Sie von einer älteren Version auf MySQL 5.1 aktualisieren, sollten Sie alle vorhandenen `ISAM`-Tabellen in `MyISAM`-Tabellen konvertieren, bevor Sie das Upgrade durchführen.
`InnoDB` | Transaktionssichere Tabellen mit Datensatzsperrung und Fremdschlüsseln. Siehe auch Abschnitt 14.2, „`InnoDB`-Tabellen“.
`MEMORY` | Die Daten für diese Speicher-Engine werden nur im Speicher abgelegt. Siehe auch Abschnitt 14.4, „Die `MEMORY`-Speicher-Engine“.
`MERGE` | Eine Sammlung von `MyISAM`-Tabellen, die als eine Tabelle verwendet wird. Heißt auch `MRG_MyISAM`. Siehe auch Abschnitt 14.3, „Die `MERGE`-Speicher-Engine“.
`MyISAM` | Binäre portable Speicher-Engine, die als Standard-Engine in MySQL verwendet wird. Siehe auch Abschnitt 14.1, „Die `MyISAM`-Speicher-Engine“.
`NDBCLUSTER` | Fehlertolerante, speicherbasierte Cluster-Tabellen. Heißt auch `NDB`. Siehe auch Kapitel 16, MySQL Cluster.

Wird eine Speicher-Engine angegeben, die nicht verfügbar ist, dann verwendet MySQL stattdessen die Standard-Engine. Im Normalfall ist dies `MyISAM`. Wenn beispielsweise eine Tabellendefinition die Option `ENGINE=BDB` enthält, aber der MySQL Server `BDB`-Tabellen nicht unterstützt, dann wird die Tabelle als `MyISAM`-Tabelle erstellt. Auf diese Weise ist eine Replikationskonfiguration realisierbar, bei der Sie transaktionssichere Tabellen auf dem Master haben, während die auf dem Slave erstellten Tabellen nicht transaktionssicher sind (was eine Erhöhung der Verarbeitungsgeschwindigkeit nach sich zieht). In MySQL 5.1 erscheint eine Warnung, wenn die Spezifikation der Speicher-Engine nicht berücksichtigt werden kann.

Die übrigen Tabellenoptionen werden zur Optimierung des Verhaltens der Tabelle verwendet. In den meisten Fällen müssen Sie sie überhaupt nicht angeben. Diese Optionen gelten für alle Speicher-Engines, soweit nichts anderes angegeben ist:

- `AUTO_INCREMENT`

  Der `AUTO_INCREMENT`-Startwert für die Tabelle. In MySQL 5.1 funktioniert dies bei `MyISAM`-, `MEMORY`- und `InnoDB`-Tabellen. Um den ersten `AUTO_INCREMENT`-Wert für Engines zu setzen, die die Tabellenoption `AUTO_INCREMENT` nicht unterstützen, fügen Sie einen „Pseudodatensatz“ mit einem Wert ein, der um 1 niedriger ist als der gewünschte Startwert. Nach der Erstellung der Tabelle löschen Sie den Pseudodatensatz dann.

  Bei Engines, die die Tabellenoption `AUTO_INCREMENT` in `CREATE TABLE`-Anweisungen unterstützen, können Sie auch `ALTER TABLE `tbl_name` AUTO_INCREMENT = `N`` verwenden, um den `AUTO_INCREMENT`-Wert zurückzusetzen.

- `AVG_ROW_LENGTH`

  Ein Näherungswert für die durchschnittliche Datensatzlänge in Ihrer Tabelle. Sie müssen die Einstellung nur bei großen Tabellen mit Datensätzen unterschiedlicher Größe vornehmen.

  Wenn Sie eine `MyISAM`-Tabelle erstellen, verwendet MySQL das Produkt der Optionen `MAX_ROWS` und `AVG_ROW_LENGTH`, um zu ermitteln, wie groß die resultierende Tabelle sein wird. Geben Sie keine der Optionen an, dann beträgt die maximale Tabellengröße 65.536 Tbyte Daten. (Wenn Ihr Betriebssystem derart große Dateien nicht unterstützt, wird die maximale Größe einer Tabelle durch die betriebssystemseitige Beschränkung der Dateigröße bestimmt.) Wenn Sie die Zeigergrößen gering halten wollen, damit der Index kleiner und schneller wird, und Sie eigentlich keine großen Dateien benötigen, können Sie die Standardzeigergröße durch Einstellen der Systemvariablen `myisam_data_pointer_size` verringern. (Siehe auch Abschnitt 5.2.2, „Server-Systemvariablen“.) Wenn Sie wollen, dass alle Ihre Tabellen über das standardmäßige Limit hinaus anwachsen können, und dafür in Kauf nehmen, dass die Tabellen etwas größer und langsamer sind als notwendig, dann können Sie die Standardzeigergröße durch Einstellen der Variablen auch erhöhen.

- `[DEFAULT] CHARACTER SET`

  Gibt einen Standardzeichensatz für die Tabelle an. `CHARSET` ist ein Synonym für `CHARACTER SET`.

- `COLLATE`

  Gibt eine Standardsortierfolge für die Tabelle an.

- `CHECKSUM`

  Setzen Sie diese Option auf 1, wenn Sie wollen, dass MySQL eine Prüfsumme für alle Datensätze erstellt, die zudem bei Änderungen in der Tabelle automatisch aktualisiert wird. Dies macht die Aktualisierung der Tabelle zwar ein wenig langsamer, erleichtert aber das Auffinden beschädigter Tabellen. Die Anweisung `CHECKSUM TABLE` meldet die Prüfsumme. (Nur für `MyISAM`.)

- `COMMENT`

  Ein Kommentar für die Tabelle, der bis zu 60 Zeichen lang sein kann.

- `CONNECTION`

  Der Verbindungs-String für eine `FEDERATED`-Tabelle. (Hinweis: Ältere Versionen von MySQL verwendeten eine Option `COMMENT` für den Verbindungs-String.)

- `MAX_ROWS`

  Maximale Anzahl der Datensätze, die Sie in der Tabelle zu speichern beabsichtigen. Dies ist keine feste Beschränkung, sondern ein Indikator für die Anzahl der Datensätze, die die Tabelle zumindest speichern können muss.

- `MIN_ROWS`

  Minimale Anzahl der Datensätze, die Sie in der Tabelle zu speichern beabsichtigen.

- `PACK_KEYS`

  Setzen Sie diese Option auf 1, wenn Sie kleinere Indizes wünschen. Hierdurch werden Updates in der Regel langsamer und Leseoperationen schneller. Wenn Sie die Option auf 0 setzen, wird das Packen für alle Schlüssel deaktiviert. Setzen Sie sie hingegen auf `DEFAULT`, dann wird die Speicher-Engine angewiesen, nur lange `CHAR`- und `VARCHAR`-Spalten zu packen. (Nur für `MyISAM`.)

  Wenn Sie `PACK_KEYS` nicht verwenden, werden standardmäßig Strings, aber nicht Zahlen gepackt. Bei `PACK_KEYS=1` werden auch Zahlen gepackt.

  Beim Packen von binären Zahlenschlüsseln verwendet MySQL die Präfixkompression:

  - Jeder Schlüssel benötigt ein zusätzliches Byte, um anzugeben, wie viele Bytes des vorherigen Schlüssels beim nachfolgenden Schlüssel identisch sind.

  - Der Zeiger auf den Datensatz wird direkt auf den Schlüssel folgend und in absteigender Reihenfolge der Bytewertigkeit gespeichert, um die Komprimierung zu optimieren.

  Das bedeutet, dass, wenn Sie viele gleiche Schlüssel in zwei aufeinander folgenden Datensätzen haben, alle nachfolgenden „identischen“ Schlüssel einschließlich des Zeigers auf den Datensatz nur 2 Byte benötigen. Vergleichen Sie dies einmal mit dem normalen Fall, in dem die nachfolgenden Schlüssel `storage_size_for_key + pointer_size` Bytes benötigen (wobei die Zeigergröße normalerweise 4 beträgt). Umgekehrt können Sie nur dann umfassend von der Präfixkomprimierung profitieren, wenn Sie viele identische Zahlen haben. Wenn alle Schlüssel vollständig unterschiedlich sind, verwenden Sie pro Schlüssel ein Byte mehr, wenn der jeweilige Schlüssel keine `NULL`-Werte haben kann. (In diesem Fall wird die Länge des gepackten Schlüssels im selben Byte gespeichert, das zur Kennzeichnung verwendet wird, wenn ein Schlüssel `NULL` ist.)

- `PASSWORD`

  Verschlüsselt die `.frm`-Datei mit einem Passwort. In der MySQL-Standardversion tut die Option nichts.

- `DELAY_KEY_WRITE`

  Setzen Sie diese Option auf 1, wenn Sie Schlüssel-Updates für die Tabelle auf einen Zeitpunkt verschieben wollen, an dem die Tabelle geschlossen ist. Details finden Sie in der Beschreibung zur Systemvariablen `delay_key_write` in Abschnitt 5.2.2, „Server-Systemvariablen“. (Nur für `MyISAM`.)

- `ROW_FORMAT`

  Definiert, wie die Datensätze gespeichert werden sollen. Bei `MyISAM`-Tabellen kann der Optionswert `FIXED` oder `DYNAMIC` für das statische wie auch das variabel lange Datensatzformat sein. myisampack setzt den Typ auf `COMPRESSED`. Siehe auch Abschnitt 14.1.3, „MyISAM-Tabellenformate“.

  Bei `InnoDB`-Tabellen werden die Datensätze standardmäßig im kompakten Format (`ROW_FORMAT=COMPACT`) gespeichert. Das nichtkompakte Format, welches in älteren MySQL-Versionen verwendet wurde, kann noch über die Angabe von `ROW_FORMAT=REDUNDANT` angefordert werden.

- `RAID_TYPE`

  Die `RAID`-Unterstützung wurde ab MySQL 5.0 entfernt. Informationen zu `RAID` finden Sie online im MySQL-4.1-Handbuch unter http://dev.mysql.com/doc/refman/4.1/en/create-table.html.

- `UNION`

  `UNION` wird verwendet, wenn Sie auf eine ganze Sammlung identischer `MyISAM`-Tabellen zugreifen wollen. Dies funktioniert nur bei `MERGE`-Tabellen. Siehe auch Abschnitt 14.3, „Die `MERGE`-Speicher-Engine“.

  Sie benötigen die Berechtigungen `SELECT`, `UPDATE` und `DELETE` für die Tabellen, um die Sammlung einer `MERGE` zuordnen zu können. (Hinweis: Ursprünglich mussten alle verwendeten Tabellen sich in der gleichen Datenbank wie die `MERGE`-Tabelle selbst befinden. Diese Einschränkung trifft nicht mehr zu.)

- `INSERT_METHOD`

  Wenn Sie Daten in eine `MERGE`-Tabelle einfügen wollen, müssen Sie mit `INSERT_METHOD` die Tabelle festlegen, in die der Datensatz einzufügen ist. Die Option `INSERT_METHOD` ist nur für `MERGE`-Tabellen sinnvoll. Verwenden Sie die Werte `FIRST` oder `LAST`, um die Einfügung in die erste bzw. letzte Tabelle vorzunehmen, oder `NO`, um Einfügeoperationen ganz auszuschließen. Siehe auch Abschnitt 14.3, „Die `MERGE`-Speicher-Engine“.

- `DATA DIRECTORY`, `INDEX DIRECTORY`

  Mithilfe von `DATA DIRECTORY='`directory`'` oder `INDEX DIRECTORY='`directory`'` können Sie angeben, wo die `MyISAM`-Speicher-Engine die Daten- und Indexdatei einer Tabelle ablegen soll. `directory` muss als vollständiger Pfadname zum Verzeichnis angegeben werden; relative Pfade sind nicht möglich.

  Diese Optionen funktionieren nur, wenn Sie die Option `--skip-symbolic-links` nicht verwenden. Außerdem muss Ihr Betriebssystem über einen funktionsfähigen und Thread-sicheren `realpath()`-Aufruf verfügen. Weitere Informationen finden Sie in Abschnitt 7.6.1.2, „Benutzung symbolischer Links für Tabellen“.

- Partitionierungsoptionen (`partition_options`) können zur Steuerung der Partitionierung einer Tabelle benutzt werden, die mit `CREATE TABLE` erstellt wurde. Sofern angegeben, muss mindestens eine `PARTITION BY`-Klausel enthalten sein. Diese Klausel enthält die Funktion, die zur Bestimmung der Partition verwendet wird. Die Funktion gibt einen ganzzahligen Wert zwischen 1 und `num` zurück, wobei `num` die Gesamtzahl der Partitionen ist. Die nachfolgende Liste zeigt die Auswahlmöglichkeiten für diese Funktion in MySQL 5.1.

  Wichtig: Nicht alle zu Beginn dieses Abschnitts in der Syntax für `partition_options` aufgeführten Optionen stehen für alle Partitionierungstypen zur Verfügung. Entnehmen Sie den Listings für die jeweiligen Typen die passenden Informationen. Weitere Informationen zu Wirkungsweise und Anwendungsmöglichkeiten der Partitionierung in MySQL sowie zusätzliche Beispiele zur Tabellenerstellung und zu anderen partitionierungsbezogenen Anweisungen in MySQL finden Sie in Kapitel 17, Partitionierung.

  - `HASH(`expr`)`: Führt ein Hashing einer oder mehrerer Spalten aus, um einen Schlüssel zum Platzieren und Wiederauffinden von Datensätzen zu erstellen. `expr` ist ein Ausdruck, der eine oder mehrere Tabellenspalten verwendet. Dabei kann es sich um einen zulässigen MySQL-Ausdruck (einschließlich MySQL-Funktionen) handeln, der genau einen Integer-Wert ausgibt. Die nachfolgenden `CREATE TABLE`-Anweisungen mit `PARTITION BY HASH`-Option etwa sind alle zulässig:

        CREATE TABLE t1 (col1 INT, col2 CHAR(5))
            PARTITION BY HASH(col1);

        CREATE TABLE t1 (col1 INT, col2 CHAR(5))
            PARTITION BY HASH( ORD(col2) );

        CREATE TABLE t1 (col1 INT, col2 CHAR(5), col3 DATETIME)
            PARTITION BY HASH ( YEAR(col3) );

    `VALUES LESS THAN`- und `VALUES IN`-Klauseln dürfen nicht mit `PARTITION BY HASH` gemeinsam eingesetzt werden.

    `PARTITION BY HASH` verwendet den Rest des Ausdrucks `expr` geteilt durch die Anzahl der Partitionen (d. h. den Modulo). Beispiele und Informationen finden Sie in Abschnitt 17.2.3, „`HASH`-Partitionierung“.

    Das Schlüsselwort `LINEAR` bringt einen etwas anderen Algorithmus mit sich. In diesem Fall wird die Nummer der Partition, auf der ein Datensatz gespeichert ist, als Ergebnis einer oder mehrerer logischer `AND`-Operationen ermittelt. Eine Beschreibung und Beispiele für das lineare Hashing finden Sie in Abschnitt 17.2.3.1, „`LINEAR HASH`-Partitionierung“.

  - `KEY(`column_list`)`: Dies ähnelt `HASH`, nur wird die Hashing-Funktion hier von MySQL selbst bereitgestellt, um eine gleichmäßige Datenverteilung zu gewährleisten. Das Argument `column_list` ist eine einfache Liste mit Tabellenspalten. Dieses Beispiel zeigt eine einfache, durch einen Schlüssel partitionierte Tabelle mit vier Partitionen:

        CREATE TABLE tk (col1 INT, col2 CHAR(5), col3 DATE)
            PARTITION BY KEY(col3)
            PARTITIONS 4;

    Bei Tabellen, die durch einen Schlüssel partitioniert sind, können Sie die lineare Partitionierung durch Angabe des Schlüsselworts `LINEAR` benutzen. Dies hat die gleichen Auswirkungen wie bei Tabellen, die mit `HASH` partitioniert wurden: Die Partitionsnummer wird mithilfe des Operators `&` statt über den Modulo ermittelt (siehe auch Abschnitt 17.2.3.1, „`LINEAR HASH`-Partitionierung“, und Abschnitt 17.2.4, „`KEY`-Partitionierung“). Dieses Beispiel verwendet die lineare Partitionierung über einen Schlüssel, um Daten auf fünf Partitionen zu verteilen:

        CREATE TABLE tk (col1 INT, col2 CHAR(5), col3 DATE)
            PARTITION BY LINEAR KEY(col3)
            PARTITIONS 5;

    `VALUES LESS THAN`- und `VALUES IN`-Klauseln dürfen nicht mit `PARTITION BY KEY` gemeinsam eingesetzt werden.

  - `RANGE`: In diesem Fall zeigt `expr` unter Verwendung einer Menge von `VALUES LESS THAN`-Operatoren einen Wertebereich an. Wenn Sie die Bereichspartitionierung verwenden, müssen Sie mindestens eine Partition mit `VALUES LESS THAN` angeben. `VALUES IN` können Sie bei der Bereichspartitionierung nicht einsetzen.

    `VALUES LESS THAN` kann entweder mit einem literalen Wert oder einem Ausdruck benutzt werden, der genau einen Wert zurückgibt.

    Angenommen, Sie haben eine Tabelle, die Sie nach einer Spalte partitionieren wollen, die Jahreswerte enthält. Hierbei wollen Sie das folgende Schema verwenden:

    Partitionsnummer: | Jahre
    0 | 1990 und früher
    1 | 1991–1994
    2 | 1995–1998
    3 | 1999–2002
    4 | 2003–2005
    5 | 2006 und später

    Eine Tabelle, die dieses Partitionierungsschema implementiert, kann mit der folgenden `CREATE TABLE`-Anweisung erstellt werden:

        CREATE TABLE t1 (
            year_col  INT,
            some_data INT
        )
        PARTITION BY RANGE (year_col) (
            PARTITION p0 VALUES LESS THAN (1991),
            PARTITION p1 VALUES LESS THAN (1995),
            PARTITION p2 VALUES LESS THAN (1999),
            PARTITION p3 VALUES LESS THAN (2002),
            PARTITION p4 VALUES LESS THAN (2006),
            PARTITION p5 VALUES LESS THAN MAXVALUE
        );

    `PARTITION ... VALUES LESS THAN ...`-Anweisungen arbeiten konsekutiv, d. h., `VALUES LESS THAN MAXVALUE` verarbeitet die „übrig gebliebenen“ Werte, die größer sind als der anderweitig angegebene Maximalwert.

    Beachten Sie, dass `VALUES LESS THAN`-Klauseln sequenziell auf eine Weise verarbeitet werden, die der von `case`-Abschnitten eines `switch ... case`-Blocks ähnelt, wie man sie aus vielen Programmiersprachen wie C, Java oder PHP her kennt: Die Klauseln müssen so angeordnet sein, dass der obere Grenzwert einer nachfolgenden `VALUES LESS THAN`-Klausel größer ist als der der vorherigen Klausel; dabei muss `MAXVALUE` als Letztes in der Liste erscheinen.

  - `LIST(`expr`)`: Dies ist praktisch, wenn man Partitionen basierend auf einer Tabellenspalte mit einer beschränkten Menge möglicher Werte (z. B. Land, PLZ usw.) konfiguriert. In einem solchen Fall lassen sich alle Datensätze, die einem bestimmten Land oder einer PLZ zuzuordnen sind, derselben Partition zuweisen, oder eine Partition kann für bestimmte Länder oder Postleitzahlen reserviert werden. Dies ähnelt `RANGE` mit der Einschränkung, dass nur `VALUES IN` zur Angabe zulässiger Werte für jede Partition verwendet werden kann.

    `VALUES IN` wird mit einer Liste passender Werte benutzt. Beispielsweise könnten Sie ein Partitionierungsschema wie das folgende erstellen:

        CREATE TABLE client_firms (
            id   INT,
            name VARCHAR(35)
        )
        PARTITION BY LIST (id) (
            PARTITION r0 VALUES IN (1, 5, 9, 13, 17, 21),
            PARTITION r1 VALUES IN (2, 6, 10, 14, 18, 22),
            PARTITION r2 VALUES IN (3, 7, 11, 15, 19, 23),
            PARTITION r3 VALUES IN (4, 8, 12, 16, 20, 24)
        );

    Wenn Sie die Listenpartitionierung verwenden, müssen Sie mindestens eine Partition mit `VALUES IN` angeben. `VALUES LESS THAN` können Sie bei der Listenpartitionierung nicht einsetzen.

    Hinweis: Derzeit darf die für `VALUES IN` verwendete Werteliste nur aus Integers bestehen.

  - Die Anzahl der Partitionen kann optional mit einer `PARTITIONS `num``-Klausel angegeben werden, wobei `num` die Anzahl der Partitionen ist. Werden diese Klausel und beliebige `PARTITION`-Klauseln verwendet, muss `num` gleich der Anzahl aller Partitionen sein, die mit `PARTITION`-Klauseln deklariert wurden.

    Hinweis: Unabhängig davon, ob Sie eine `PARTITIONS`-Klausel bei der Erstellung einer Tabelle verwenden, die mit `RANGE` oder `LIST` partitioniert wurde, müssen Sie in jedem Fall mindestens eine `PARTITION VALUES`-Klausel in der Tabellendefinition angeben (siehe unten).

  - Eine Partition kann optional in eine Anzahl Unterpartitionen aufgeteilt werden. Dies kann durch Verwendung der optionalen Klausel `SUBPARTITION BY` angegeben werden. Die Unterpartitionierung kann mit `HASH` oder `KEY` erfolgen. Beide können `LINEAR` sein. Sie funktionieren auf die gleiche Weise wie oben für die entsprechenden Partitionierungstypen beschrieben. (Es ist nicht möglich, Unterpartitionen nach `LIST` oder `RANGE` zu erstellen.)

    Die Anzahl der Unterpartitionen kann mit dem Schlüsselwort `SUBPARTITIONS`, gefolgt von einem Integer-Wert, angegeben werden.

  Jede Partition kann individuell mit einer `partition_definition`-Klausel definiert werden. Die einzelnen Teile, aus denen die Klausel besteht, sind die folgenden:

  - `PARTITION `partition_name``: Gibt einen logischen Namen für die Partition an.

  - `VALUES`-Klausel: Bei der Bereichspartitionierung muss jede Partition eine `VALUES LESS THAN`-Klausel enthalten, und bei der Listenpartitionierung müssen Sie eine `VALUES IN`-Klausel je Partition angeben. Hiermit wird bestimmt, welche Datensätze in dieser Partition gespeichert werden sollen. Weitere Informationen und Syntaxinformationen entnehmen Sie der Beschreibung der Partitionierungstypen in Kapitel 17, Partitionierung.

  - Eine optionale `COMMENT`-Klausel kann zur Beschreibung der Partition angegeben werden. Der Kommentar muss in einzelne Anführungszeichen gesetzt werden. Beispiel:

        COMMENT = 'Data for the years previous to 1999'

  - `DATA DIRECTORY` und `INDEX DIRECTORY` können zur Angabe des Verzeichnisses verwendet werden, in dem die Daten bzw. die Indizes dieser Partition gespeichert werden sollen. Sowohl ``data_dir`` als auch ``index_dir`` müssen absolute Pfadnamen sein. Beispiel:

        CREATE TABLE th (id INT, name VARCHAR(30), adate DATE)
        PARTITION BY LIST(YEAR(adate))
        (
          PARTITION p1999 VALUES IN (1995, 1999, 2003)
            DATA DIRECTORY = '/var/appdata/95/data'
            INDEX DIRECTORY = '/var/appdata/95/idx',
          PARTITION p2000 VALUES IN (1996, 2000, 2004)
            DATA DIRECTORY = '/var/appdata/96/data'
            INDEX DIRECTORY = '/var/appdata/96/idx',
          PARTITION p2001 VALUES IN (1997, 2001, 2005)
            DATA DIRECTORY = '/var/appdata/97/data'
            INDEX DIRECTORY = '/var/appdata/97/idx',
          PARTITION p2000 VALUES IN (1998, 2002, 2006)
            DATA DIRECTORY = '/var/appdata/98/data'
            INDEX DIRECTORY = '/var/appdata/98/idx'
        );

    `DATA DIRECTORY` und `INDEX DIRECTORY` verhalten sich genauso wie in der `table_option`-Klausel einer `CREATE TABLE`-Anweisung bei `MyISAM`-Tabellen.

    Je Partition können ein Daten- und ein Indexverzeichnis angegeben werden. Wenn keine Angaben gemacht werden, werden Daten und Indizes standardmäßig im MySQL-Datenverzeichnis abgelegt.

  - `MAX_ROWS` und `MIN_ROWS` können zur Angabe der größten bzw. kleinsten Zahl von Datensätzen verwendet werden, die in der Partition gespeichert werden. Die Werte für `max_number_of_rows` und `min_number_of_rows` müssen positive ganze Zahlen sein. Wie bei den gleichnamigen Optionen auf Tabellenebene sind auch dies keine festen Grenzwerte, sondern nur „Vorschläge“ für den Server.

  - Die optionale `TABLESPACE`-Klausel kann zur Angabe eines Tablespaces für die Partition verwendet werden. (Nur für MySQL Cluster.)

  - Die optionale `[STORAGE] ENGINE`-Klausel bewirkt, dass die Tabelle in dieser Partition die angegebene Speicher-Engine verwendet. Dies kann jede der vom betreffenden MySQL Server unterstützten Engines sein. Sowohl das Schlüsselwort `STORAGE` als auch das Gleichheitszeichen (`=`) sind optional. Wird keine partitionsspezifische Speicher-Engine mit dieser Option angegeben, dann wird die für die gesamte Tabelle gültige Engine auch für diese Partition verwendet.

    Hinweis: Der Partitionierungs-Handler akzeptiert eine Option `[STORAGE] ENGINE` sowohl für `PARTITION` als auch für `SUBPARTITION`. Die derzeit einzige Möglichkeit, diese Klausel zu nutzen, besteht darin, alle Partitionen oder alle Unterpartitionen auf dieselbe Speicher-Engine zu setzen. Der Versuch, verschiedene Engines für Partitionen oder Unterpartitionen einer Tabelle einzustellen, führt zum Fehler `ERROR 1469 (HY000): The mix of handlers in the partitions is not allowed in this version of MySQL`. Wir beabsichtigen, diese partitionierungsbezogene Einschränkung in einem zukünftigen Release von MySQL 5.1 zu beseitigen.

  - Die Option `NODEGROUP` kann verwendet werden, um diese Partition zu einem Teil der Knotengruppe zu machen, die als `node_group_id` angegeben ist. (Nur für MySQL Cluster.)

  - Die Partitionsdefinition kann optional eine oder mehrere `subpartition_definition`-Klauseln enthalten. Jede dieser Klauseln umfasst zumindest `SUBPARTITION `name``, wobei `name` ein Bezeichner für die Unterpartition ist. Die Syntax für eine Unterpartitionsdefinition ist mit der einer Partition bis auf die Tatsache identisch, dass das Schlüsselwort `PARTITION` durch `SUBPARTITION` zu ersetzen ist.

    Die Unterpartitionierung muss über `HASH` oder `KEY` erfolgen und kann nur bei `RANGE`- oder `LIST`-Partitionen durchgeführt werden. Siehe auch Abschnitt 17.2.5, „Unterpartitionen“.

  Partitionen können geändert, verbunden und zu Tabellen hinzugefügt sowie aus diesen gelöscht werden. Grundlegende Informationen zu den MySQL-Anweisungen, mit denen diese Aufgaben erledigt werden, finden Sie in Abschnitt 13.1.2, „`ALTER TABLE`“. Detaillierte Beschreibungen und Beispiele finden Sie in Abschnitt 17.3, „Partitionsverwaltung“.

Sie können eine Tabelle aus einer anderen Tabelle erstellen, indem Sie am Ende der `CREATE TABLE`-Anweisung eine `SELECT`-Anweisung hinzufügen:

    CREATE TABLE new_tbl SELECT * FROM orig_tbl;

MySQL erstellt neue Spalten für alle Elemente in der `SELECT`-Anweisung. Zum Beispiel:

    mysql> CREATE TABLE test (a INT NOT NULL AUTO_INCREMENT,
        ->        PRIMARY KEY (a), KEY(b))
        ->        ENGINE=MyISAM SELECT b,c FROM test2;

Hierbei wird eine `MyISAM`-Tabelle mit drei Spalten `a`, `b` und `c` erstellt. Beachten Sie, dass die Spalten aus der `SELECT`-Anweisung rechts an die Tabelle angehängt und nicht in diese eingesetzt werden. Betrachten Sie einmal das folgende Beispiel:

    mysql> SELECT * FROM foo;
    +---+
    | n |
    +---+
    | 1 |
    +---+

    mysql> CREATE TABLE bar (m INT) SELECT n FROM foo;
    Query OK, 1 row affected (0.02 sec)
    Records: 1  Duplicates: 0  Warnings: 0

    mysql> SELECT * FROM bar;
    +------+---+
    | m    | n |
    +------+---+
    | NULL | 1 |
    +------+---+
    1 row in set (0.00 sec)

Für jeden Datensatz in der Tabelle `foo` wird ein Datensatz in `bar` mit den Werten aus `foo` und den Standardwerten bei neuen Spalten eingefügt.

In einer Tabelle, die mit `CREATE TABLE ... SELECT` erstellt wurde, erscheinen die Spalten, die im `CREATE TABLE`-Teil genannt werden, zuerst. Die in beiden Teilen oder nur im `SELECT`-Teil genannten Spalten folgen nach. Der Datentyp der `SELECT`-Spalten kann außer Kraft gesetzt werden, indem die Spalte zusätzlich im `CREATE TABLE`-Teil genannt wird.

Wenn während des Kopierens der Daten in die Tabelle Fehler auftreten, wird diese automatisch gelöscht und nicht erstellt.

`CREATE TABLE ... SELECT` erstellt keine automatischen Indizes. Dies wurde bewusst so eingerichtet, um die Anweisung so flexibel wie möglich zu halten. Wenn Sie wollen, dass Indizes in der Tabelle erstellt werden, müssen Sie diese vor der `SELECT`-Anweisung spezifizieren:

    mysql> CREATE TABLE bar (UNIQUE (n)) SELECT n FROM foo;

Es kann dadurch zu Fällen von Datentypkonvertierung kommen. So wird z. B. das `AUTO_INCREMENT`-Attribut nicht beibehalten, und `VARCHAR`-Spalten können in `CHAR`-Spalten umgewandelt werden.

Wenn Sie eine Tabelle mit `CREATE ... SELECT` erstellen, müssen Sie in jedem Fall Aliase für Funktionsaufrufe oder Ausdrücke in der Abfrage verwenden. Andernfalls kann die `CREATE`-Anweisung fehlschlagen, oder es können unerwünschte Spaltennamen entstehen.

    CREATE TABLE artists_and_works
      SELECT artist.name, COUNT(work.artist_id) AS number_of_works
      FROM artist LEFT JOIN work ON artist.id = work.artist_id
      GROUP BY artist.id;

Sie können den Typ einer erzeugten Spalte auch explizit angeben:

    CREATE TABLE foo (a TINYINT NOT NULL) SELECT b+1 AS a FROM bar;

Mit `LIKE` können Sie eine leere Tabelle basierend auf der Definition einer anderen Tabelle einschließlich aller Spaltenattribute und Indizes erstellen, die auch in der Ursprungstabelle vorhanden sind:

    CREATE TABLE new_tbl LIKE orig_tbl;

`CREATE TABLE ... LIKE` behält weder für die Ursprungstabelle angegebene `DATA DIRECTORY`- und `INDEX DIRECTORY`-Optionen noch Fremdschlüsseldefinitionen bei.

Sie können dem `SELECT` ein `IGNORE` oder `REPLACE` voranstellen, um anzugeben, wie mit Datensätzen zu verfahren ist, in denen Dubletten für eindeutige Schlüssel auftreten. Bei `IGNORE` werden neue Datensätze, die eine Dublette eines eindeutigen Schlüssels für einen bereits vorhandenen Datensatz enthalten, einfach verworfen. Wenn Sie `REPLACE` angeben, ersetzen die neuen die vorhandenen Datensätze, die denselben eindeutigen Schlüsselwert aufweisen. Werden weder `IGNORE` noch `REPLACE` angegeben, dann führt das Auftreten von Dubletten eindeutiger Schlüssel zu einem Fehler.

Um sicherzustellen, dass das Binärlog zur Wiederherstellung der Originaltabellen verwendet werden kann, gestattet MySQL keine gleichzeitigen Einfügeoperationen während der Ausführung einer `CREATE TABLE ... SELECT`-Anweisung.

### 13.1.6. `DROP DATABASE`

    DROP {DATABASE | SCHEMA} [IF EXISTS] db_name

`DROP DATABASE` löscht alle Tabellen in der Datenbank und nachfolgend auch die Datenbank. Seien Sie im Umgang mit dieser Anweisung extrem sorgfältig! Um `DROP DATABASE` verwenden zu können, benötigen Sie die Berechtigung `DROP` für die Datenbank. `DROP SCHEMA` ist ein Synonym für `DROP DATABASE`.

`IF EXISTS` wird verwendet, um einen Fehler abzufangen, wenn die Datenbank nicht vorhanden ist.

Wenn Sie `DROP DATABASE` für eine symbolisch verknüpfte Datenbank verwenden, werden sowohl die Verknüpfung als auch die Originaldatenbank gelöscht.

`DROP DATABASE` gibt die Anzahl der entfernten Tabellen zurück. Diese entspricht der Anzahl der gelöschten `.frm`-Dateien.

Die `DROP DATABASE`-Anweisung entfernt jene Dateien und Verzeichnisse, die MySQL im normalen Betrieb selbst erstellt hat, aus dem angegebenen Datenbankverzeichnis:

- Alle Dateien mit den folgenden Erweiterungen:

  `.BAK` | `.DAT` | `.HSH`
  `.MRG` | `.MYD` | `.ISD`
  `.MYI` | `.db` | `.frm`

- Alle Unterverzeichnisse mit Namen, die aus zwei Hexadezimalstellen (`00`-`ff`) bestehen. Dies sind Unterverzeichnisse, die für `RAID`-Tabellen verwendet werden. (Diese Verzeichnisse werden ab MySQL 5.0 nicht entfernt, weil die Unterstützung für `RAID`-Tabellen aufgehoben wurde. Sie sollten alle vorhandenen `RAID`-Tabellen konvertieren und diese Verzeichnisse manuell entfernen, bevor Sie auf MySQL 5.0 oder höher aktualisieren. Weitere Informationen finden Sie im Abschnitt zur Aktualisierung von früheren Releases auf MySQL 5.0 im MySQL 5.0 Reference Manual, welches auf der MySQL-Website erhältlich ist.)

- Datei `db.opt` (sofern vorhanden).

Wenn andere Dateien oder Verzeichnisse im Datenbankverzeichnis zurückbleiben, nachdem MySQL die genannten Elemente entfernt hat, kann das Datenbankverzeichnis nicht gelöscht werden. In diesem Fall müssen Sie alle verbleibenden Dateien oder Verzeichnisse manuell entfernen und die `DROP DATABASE`-Anweisung nachfolgend erneut absetzen.

Sie können Datenbanken auch mit mysqladmin löschen. Siehe auch Abschnitt 8.7, „mysqladmin — Client für die Verwaltung eines MySQL Servers“.

### 13.1.7. `DROP INDEX`

    DROP INDEX index_name ON tbl_name

`DROP INDEX` löscht den Index namens `index_name` aus der Tabelle `tbl_name`. Diese Anweisung wird einer `ALTER TABLE`-Anweisung zugewiesen, die den Index löscht. Siehe auch Abschnitt 13.1.2, „`ALTER TABLE`“.

### 13.1.8. `DROP TABLE`

    DROP [TEMPORARY] TABLE [IF EXISTS]
        tbl_name [, tbl_name] ...
        [RESTRICT | CASCADE]

`DROP TABLE` löscht eine oder mehrere Tabellen. Für jede Tabelle benötigen Sie die Berechtigung `DROP`. Alle Tabellendaten und die Tabellendefinition werden entfernt! Seien Sie also auch im Umgang mit dieser Anweisung sehr vorsichtig!

Beachten Sie, dass `DROP TABLE` bei einer partitionierten Tabelle die Tabellendefinition, alle Partitionen und alle in diesen Partitionen gespeicherten Daten permanent entfernt. Ebenso gelöscht wird die Partitionierungsdefinitiondatei (`.par`) der gelöschten Tabelle.

Verwenden Sie `IF EXISTS`, um einen Fehler bei Tabellen abzufangen, die nicht vorhanden sind. Für jede nicht vorhandene Tabelle wird ein Hinweis erzeugt, wenn Sie `IF EXISTS` benutzen. Siehe auch Abschnitt 13.5.4.25, „`SHOW WARNINGS`“.

`RESTRICT` und `CASCADE` erlauben eine leichtere Portierung. Derzeit haben sie aber keine Funktion.

Hinweis: `DROP TABLE` übergibt die derzeit aktive Transaktion sofort, sofern Sie nicht das Schlüsselwort `TEMPORARY` benutzen.

Das Schlüsselwort `TEMPORARY` hat die folgenden Auswirkungen:

- Die Anweisung löscht nur Temporärtabellen.

- Die Anweisung beendet keine laufende Transaktion.

- Zugriffsrechte werden nicht geprüft. (Eine Temporärtabelle ist nur für den Client sichtbar, der sie erstellt hat; insofern ist eine Überprüfung unnötig.)

Die Verwendung von `TEMPORARY` ist eine gute Möglichkeit, sicherzustellen, dass Sie nicht versehentlich eine nichttemporäre Tabelle löschen.

### 13.1.9. `RENAME TABLE`

    RENAME TABLE tbl_name TO new_tbl_name
        [, tbl_name2 TO new_tbl_name2] ...

Mit dieser Anweisung werden eine oder mehrere Tabellen umbenannt.

Der Umbenennungsvorgang erfolgt automatisch, d. h., kein anderer Thread kann währenddessen auf die umzubenennende(n) Tabelle(n) zugreifen. Wenn Sie beispielsweise eine Tabelle `old_table` haben, können Sie eine andere Tabelle `new_table` erstellen, die dieselbe Struktur hat, aber leer ist, und die vorhandene Tabelle dann wie folgt durch die leere Tabelle ersetzen (sofern `backup_table` nicht bereits vorhanden ist):

    CREATE TABLE new_table (...);
    RENAME TABLE old_table TO backup_table, new_table TO old_table;

Wenn die Anweisung mehrere Tabellen umbenennt, erfolgen die Umbenennungen von links nach rechts. Wollen Sie zwei Tabellennamen gegeneinander austauschen, dann können Sie dies wie folgt tun (sofern `tmp_table` nicht bereits vorhanden ist):

    RENAME TABLE old_table TO tmp_table,
                 new_table TO old_table,
                 tmp_table TO new_table;

Solange zwei Datenbanken sich im selben Dateisystem befinden, können Sie mit `RENAME TABLE` auch eine Tabelle von einer Datenbank in eine andere verschieben:

    RENAME TABLE current_db.tbl_name TO other_db.tbl_name;

`RENAME TABLE` funktioniert auch bei Views, solange Sie nicht versuchen, einen View in einer anderen Datenbank umzubenennen.

Wenn Sie `RENAME` ausführen, dürfen keine Tabellen gesperrt und keine Transaktionen aktiv sein. Sie benötigen für die Ursprungstabelle ferner die Berechtigungen `ALTER` und `DROP` sowie die Berechtigungen `CREATE` und `INSERT` für die neue Tabelle.

Wenn MySQL in einer tabellenübergreifenden Umbenennungsaktion auf Fehler trifft, wird für alle umbenannten Tabellen eine umgekehrte Umbenennung durchgeführt, um den ursprünglichen Zustand wiederherzustellen.

## 13.2. Datenmanipulation: `SELECT`, `INSERT`, `UPDATE`, `DELETE`

### 13.2.1. `DELETE`

Syntax für eine Tabelle:

    DELETE [LOW_PRIORITY] [QUICK] [IGNORE] FROM tbl_name
        [WHERE where_condition]
        [ORDER BY ...]
        [LIMIT row_count]

Syntax für mehrere Tabellen:

    DELETE [LOW_PRIORITY] [QUICK] [IGNORE]
        tbl_name[.*] [, tbl_name[.*]] ...
        FROM table_references
        [WHERE where_condition]

Oder:

    DELETE [LOW_PRIORITY] [QUICK] [IGNORE]
        FROM tbl_name[.*] [, tbl_name[.*]] ...
        USING table_references
        [WHERE where_condition]

Bei der Ein-Tabellen-Syntax löscht die `DELETE`-Anweisung Datensätze aus `tbl_name` und gibt die Anzahl gelöschter Datensätze zurück. Sofern angegeben, bestimmt die `WHERE`-Klausel die Bedingungen dafür, welche Datensätze gelöscht werden. Ohne `WHERE`-Klausel werden alle Datensätze gelöscht. Wenn die `ORDER BY`-Klausel vorhanden ist, werden die Datensätze in der angegebenen Reihenfolge gelöscht. Die `LIMIT`-Klausel kann die Anzahl der zu löschenden Datensätze beschränken.

Bei der Mehrtabellensyntax löscht `DELETE` aus jeder Tabelle `tbl_name` die Datensätze, die die Bedingungen erfüllen. In diesem Fall können `ORDER BY` und `LIMIT` nicht verwendet werden.

`where_condition` ist ein Ausdruck, der für jeden zu löschenden Datensatz wahr ist. Er wird wie in Abschnitt 13.2.7, „`SELECT`“, beschrieben angegeben.

Wie bereits gesagt, löscht eine `DELETE`-Anweisung ohne `WHERE`-Klausel alle Datensätze. Wenn Sie die Anzahl der gelöschten Datensätze nicht kennen müssen, können Sie dies schneller mit `TRUNCATE TABLE` erledigen. Siehe auch Abschnitt 13.2.9, „`TRUNCATE`“.

Wenn Sie den Datensatz entfernen, der den höchsten Wert für eine `AUTO_INCREMENT`-Spalte hat, dann wird der Wert bei `BDB`-Tabellen später wiederverwendet, nicht jedoch bei `MyISAM`- oder `InnoDB`-Tabellen. Wenn Sie im `AUTOCOMMIT`-Modus alle Datensätze in der Tabelle mit `DELETE FROM `tbl_name`` (ohne `WHERE`-Klausel) löschen, beginnt die Sequenz für alle Speicher-Engines mit Ausnahme von `InnoDB` und `MyISAM` neu. Bei `InnoDB`-Tabellen gibt es bezüglich dieses Verhaltens ein paar Ausnahmen, die in Abschnitt 14.2.6.3, „Wie eine Auto-Increment-Spalte in InnoDB funktioniert“, beschrieben sind.

Bei `MyISAM`- und `BDB`-Tabellen können Sie `AUTO_INCREMENT` in einer Sekundärspalte eines mehrspaltigen Schlüssels angeben. In diesem Fall werden Werte, die am Anfang der Sequenz gelöscht wurden, auch bei `MyISAM`-Tabellen wiederverwendet. Siehe auch Abschnitt 3.6.9, „Verwendung von `AUTO_INCREMENT`“.

Die `DELETE`-Anweisung unterstützt die folgenden Modifizierer:

- Wenn Sie `LOW_PRIORITY` angeben, verzögert der Server die Ausführung von `DELETE`, bis kein Client mehr aus der Tabelle liest.

- Wenn Sie bei `MyISAM`-Tabellen das Schlüsselwort `QUICK` angeben, fasst die Speicher-Engine beim Löschen Indexzweige nicht zusammen. Dies kann bestimmte Arten von Löschvorgängen beschleunigen.

- Das Schlüsselwort `IGNORE` bewirkt, dass MySQL alle Fehler während des Vorgangs der Datensatzlöschung ignoriert. (Fehler, die bei der Analyse auftreten, werden allerdings wie gewöhnlich verarbeitet.) Fehler, die aufgrund der Verwendung von `OPTION` ignoriert werden, werden als Warnungen zurückgegeben.

Die Geschwindigkeit von Löschoperationen kann auch von den Faktoren beeinflusst werden, die in Abschnitt 7.2.18, „Geschwindigkeit von `DELETE`-Anfragen“, beschrieben werden.

Bei `MyISAM`-Tabellen werden gelöschte Datensätze zu einer verknüpften Liste hinzugefügt. Nachfolgende `INSERT`-Operationen verwenden die alten Datensatzpositionen neu. Um ungenutzten Speicher wieder freizugeben und die Dateigrößen zu verringern, verwenden Sie die `OPTIMIZE TABLE`-Anweisung oder das Hilfsprogramm myisamchk zur Reorganisierung der Tabellen. `OPTIMIZE TABLE` ist einfacher, myisamchk hingegen schneller. Siehe auch Abschnitt 13.5.2.5, „`OPTIMIZE TABLE`“, und Abschnitt 8.2, „myisamchk — Hilfsprogramm für die Tabellenwartung von MyISAM“.

Der Modifizierer `QUICK` bestimmt, ob Indexzweige bei Löschoperationen zusammengefasst werden. `DELETE QUICK` ist am nützlichsten bei Anwendungen, bei denen Indexwerte für gelöschte Datensätze durch ähnliche Indexwerte von später eingefügten Datensätzen ersetzt werden. In diesem Fall werden die von den gelöschten Werten zurückgelassenen Löcher wiederverwendet.

`DELETE QUICK` ist hingegen nicht nützlich, wenn gelöschte Werte nicht aufgefüllte Indexblöcke zur Folge haben, die einen Bereich von Indexwerten umfassen, bei denen neue Einfügeoperationen auftreten. In diesem Fall kann die Verwendung von `QUICK` zur Verschwendung von Speicher im Index führen, da dieser Speicher nicht mehr freigegeben wird. Hier ein Beispiel für ein solches Szenario:

1. Erstellen Sie eine Tabelle, die eine indizierte `AUTO_INCREMENT`-Spalte enthält.

2. Fügen Sie viele Datensätze in diese Tabelle ein. Jede Einfügeoperation führt dazu, dass ein Indexwert am Ende des Indexes eingefügt wird.

3. Löschen Sie mit `DELETE QUICK` einen Block mit Datensätzen vorne im Spaltenbereich.

In diesem Szenario werden die Indexblöcke, die mit den gelöschten Indexwerten verknüpft sind, nicht aufgefüllt, aber aufgrund der Verwendung von `QUICK` auch nicht mit anderen Indexblöcken zusammengefasst. Sie bleiben also unaufgefüllt, wenn weitere Einfügeoperationen auftreten, weil die neuen Datensätze keine Indexwerte im gelöschten Bereich haben. Außerdem bleiben sie auch dann unaufgefüllt, wenn Sie später `DELETE` ohne `QUICK` verwenden, sofern nicht zufällig einige der gelöschten Indexwerte in Indexblöcken innerhalb oder neben den nicht aufgefüllten Blöcken liegen. Um ungenutzten Indexspeicher unter diesen Umständen wieder freizugeben, verwenden Sie `OPTIMIZE TABLE`.

Wenn Sie viele Datensätze aus einer Tabelle zu löschen beabsichtigen, kann `DELETE QUICK` gefolgt von `OPTIMIZE TABLE` die schnellere Lösung sein. Hierbei wird der Index neu erstellt, statt zahlreiche Zusammenfassungsoperationen für Indexblöcke auszuführen.

Die MySQL-spezifische Option `LIMIT `row_count`` für `DELETE` nennt dem Server die maximale Anzahl Datensätze, die gelöscht werden, bevor die Kontrolle an den Client zurückgegeben wird. Hiermit können Sie gewährleisten, dass eine gegebene `DELETE`-Anweisung nicht zu viel Zeit in Anspruch nimmt. Sie können die `DELETE`-Anweisung dann einfach wiederholen, bis die Gesamtzahl betroffener Datensätze kleiner ist als der `LIMIT`-Wert.

Wenn die `DELETE`-Anweisung eine `ORDER BY`-Klausel enthält, werden die Datensätze in der in der Klausel angegebenen Reihenfolge gelöscht. Dies ist nur in Verbindung mit `LIMIT` wirklich nützlich. Die folgende Anweisung beispielsweise findet Datensätze, die der `WHERE`-Klausel entsprechen, sortiert sie nach `timestamp_column` und löscht den ersten (d. h. ältesten) Datensatz:

    DELETE FROM somelog WHERE user = 'jcole'
    ORDER BY timestamp_column LIMIT 1;

Sie können in einer `DELETE`-Anweisung mehrere Tabellen angeben, aus denen je nach Bedingung der `WHERE`-Klausel Datensätze gelöscht werden. Allerdings können Sie `ORDER BY` oder `LIMIT` nicht in einer `DELETE`-Anweisung für mehrere Tabellen verwenden. Die Klausel `table_references` listet die Tabellen auf, die im Join berücksichtigt werden. Die Syntax ist in Abschnitt 13.2.7.1, „`JOIN`“, beschrieben.

Bei der ersten Mehrtabellensyntax werden nur passende Datensätze aus den Tabellen gelöscht, die vor der `FROM`-Klausel aufgelistet sind. Bei der zweiten Mehrtabellensyntax werden nur passende Datensätze aus den Tabellen gelöscht, die in der `FROM`-Klausel (vor der `USING`-Klausel) aufgelistet sind. Die Folge ist, dass Sie Datensätze aus vielen Tabellen gleichzeitig löschen und gleichzeitig in weiteren Tabellen nur suchen lassen können:

    DELETE t1, t2 FROM t1, t2, t3 WHERE t1.id=t2.id AND t2.id=t3.id;

Oder:

    DELETE FROM t1, t2 USING t1, t2, t3 WHERE t1.id=t2.id AND t2.id=t3.id;

Diese Anweisungen verwenden auf der Suche nach zu löschenden Datensätzen alle drei Tabellen, aber gelöscht werden passende Datensätze tatsächlich nur aus den Tabellen `t1` und `t2`.

Die obigen Beispiele zeigen innere Joins, die den Kommaoperator verwenden. `DELETE`-Anweisungen für mehrere Tabellen können jedoch einen beliebigen Join-Typ verwenden, der für `SELECT`-Anweisungen zulässig ist, also etwa `LEFT JOIN`.

Die Syntax erlaubt `.*` nach den Tabellennamen, um die Kompatibilität mit Access zu gewährleisten.

Wenn Sie eine `DELETE`-Anweisung für mehrere Tabellen verwenden, die auch `InnoDB`-Tabellen einbezieht, für die Fremdschlüssel-Constraints vorhanden sind, dann verarbeitet der MySQL-Optimierer die Tabellen unter Umständen in einer Reihenfolge, die sich von der ihrer Parent/Child-Beziehung unterscheidet. In diesem Fall schlägt die Anweisung fehl, und es wird ein Rollback durchgeführt. Stattdessen sollten Sie die Löschoperation dann aus nur einer Tabelle durchführen und sich auf die `ON DELETE`-Funktionalität verlassen, die `InnoDB` bietet, um andere Tabellen entsprechend zu ändern.

Hinweis: Wenn Sie einen Alias für eine Tabelle angegeben haben, müssen Sie diesen bei der Referenzierung der Tabelle verwenden:

    DELETE t1 FROM test AS t1, test2 WHERE ...

Datenbankübergreifende Löschvorgänge werden von Löschvorgängen für mehrere Tabellen unterstützt. In diesem Fall müssen Sie die Tabellen aber ohne Verwendung von Aliasen referenzieren. Zum Beispiel:

    DELETE test1.tmp1, test2.tmp2 FROM test1.tmp1, test2.tmp2 WHERE ...

Zurzeit können Sie in einer Unterabfrage keine Löschoperation in einer Tabelle durchführen und gleichzeitig eine Auswahl in einer anderen Tabelle treffen.

### 13.2.2. `DO`

    DO expr [, expr] ...

`DO` führt Ausdrücke aus, gibt aber keine Ergebnisse zurück. In den meisten Fällen ist `DO` eine Kurzform von `SELECT `expr`, ...`, hat aber den Vorteil, dass es etwas schneller ist, sofern das Ergebnis für Sie keine Rolle spielt. Allerdings meldet `DO` keine Fehler. Stattdessen werden Fehler als Warnungen ausgegeben.

`DO` ist in erster Linie bei Funktionen praktisch, die Begleiterscheinungen haben (z. B. `RELEASE_LOCK()`).

### 13.2.3. `HANDLER`

    HANDLER tbl_name OPEN [ AS alias ]
    HANDLER tbl_name READ index_name { = | >= | <= | < } (value1,value2,...)
        [ WHERE where_condition ] [LIMIT ... ]
    HANDLER tbl_name READ index_name { FIRST | NEXT | PREV | LAST }
        [ WHERE where_condition ] [LIMIT ... ]
    HANDLER tbl_name READ { FIRST | NEXT }
        [ WHERE where_condition ] [LIMIT ... ]
    HANDLER tbl_name CLOSE

Die Anweisung `HANDLER` bietet direkten Zugriff auf die Schnittstellen der Speicher-Engine einer Tabelle. Sie steht für `MyISAM`- und `InnoDB`-Tabellen zur Verfügung.

Die Anweisung `HANDLER ... OPEN` öffnet eine Tabelle und gestattet den Zugriff über nachfolgende `HANDLER ... READ`-Anweisungen. Dieses Tabellenobjekt wird nicht mit anderen Threads gemeinsam genutzt und wird erst geschlossen, wenn der Thread `HANDLER ... CLOSE` aufruft oder beendet wird. Wenn Sie die Tabelle unter Verwendung eines Alias öffnen, müssen nachfolgende Referenzierungen durch andere `HANDLER`-Anweisungen den Alias statt des Tabellennamens verwenden.

Die erste `HANDLER ... READ`-Syntax holt einen Datensatz, bei dem der angegebene Index den übergebenen Werten entspricht und die `WHERE`-Bedingung erfüllt ist. Wenn Sie einen mehrspaltigen Index haben, geben Sie die Indexspaltenwerte als kommagetrennte Liste an. Entweder geben Sie Werte für alle Spalten im Index oder aber Werte für das links stehende Präfix der Indexspalten an. Angenommen, ein Index `my_idx` enthält drei Spalten namens `col_a`, `col_b` und `col_c` in genau dieser Reihenfolge. Die Anweisung `HANDLER` kann Werte für alle drei Spalten im Index oder für die Spalten in einem links stehenden Präfix angeben. Zum Beispiel:

    HANDLER ... READ my_idx = (col_a_val,col_b_val,col_c_val) ...
    HANDLER ... READ my_idx = (col_a_val,col_b_val) ...
    HANDLER ... READ my_idx = (col_a_val) ...

Um die `HANDLER`-Schnittstelle für die Referenzierung des Primärschlüssels einer Tabelle zu verwenden, setzen Sie den Bezeichner in Anführungszeichen (``PRIMARY``).

    HANDLER tbl_name READ `PRIMARY` ...

Die zweite `HANDLER ... READ`-Syntax holt aus der Tabelle einen Datensatz in der Indexreihenfolge, die der `WHERE`-Bedingung entspricht.

Die dritte `HANDLER ... READ`-Syntax holt aus der Tabelle einen Datensatz in der natürlichen Datensatzreihenfolge, die der `WHERE`-Bedingung entspricht. Sie ist schneller als `HANDLER `tbl_name` READ `index_name``, wenn ein vollständiger Tabellenscan gewünscht wird. Die natürliche Datensatzreihenfolge ist die Reihenfolge, in der die Datensätze in der Datendatei einer `MyISAM`-Tabelle gespeichert sind. Diese Anweisung funktioniert auch bei `InnoDB`-Tabellen, aber das Konzept greift hier in Ermangelung einer separaten Datendatei nicht.

Ohne eine `LIMIT`-Klausel holen alle Formen von `HANDLER ... READ` einen einzelnen Datensatz (sofern vorhanden). Um eine bestimmte Anzahl Datensätze zurückzugeben, fügen Sie eine `LIMIT`-Klausel ein. Sie hat dieselbe Syntax wie bei der `SELECT`-Anweisung. Siehe auch Abschnitt 13.2.7, „`SELECT`“.

`HANDLER ... CLOSE` schließt eine Tabelle, die mit `HANDLER ... OPEN` geöffnet worden war.

`HANDLER` ist eine etwas maschinennahe Anweisung. Sie bietet z. B. keine Konsistenz: `HANDLER ... OPEN` fertigt keine Momentaufnahme der Tabelle an und sperrt sie nicht. Das bedeutet, dass, nachdem eine `HANDLER ... OPEN`-Anweisung abgesetzt wurde, die Tabellendaten (vom aktuellen, aber auch von anderen Threads) modifiziert werden können und diese Änderungen dann für `HANDLER ... NEXT`- oder `HANDLER ... PREV`-Scans unter Umständen nur teilweise sichtbar sind.

Es gibt eine Reihe von Gründen zur Verwendung der `HANDLER`-Schnittstelle anstelle einer normalen `SELECT`-Anweisung:

- `HANDLER` ist schneller als `SELECT`:

  - Für `HANDLER ... OPEN` wird ein dediziertes Speicher-Engine-spezifisches Handler-Objekt reserviert. Das Objekt wird bei nachfolgenden `HANDLER`-Anweisungen für diese Tabelle wiederverwendet; es muss nicht jeweils neu initialisiert werden.

  - Der Analyseaufwand ist geringer.

  - Es ist kein zusätzlicher Aufwand für den Optimierer oder die Abfrageüberprüfung erforderlich.

  - Die Tabelle muss nicht zwischen zwei Handler-Anforderungen gesperrt werden.

  - Die Handler-Schnittstelle muss keine konsistente Sicht der Daten bieten (Dirty Reads beispielsweise sind zulässig) – die Speicher-Engine kann also Optimierungen verwenden, die `SELECT` normalerweise nicht zulassen würde.

- Bei Anwendungen, die eine maschinennahe `ISAM`-artige Schnittstelle verwenden, erleichtert `HANDLER` deren Portierung auf MySQL.

- `HANDLER` erlaubt Ihnen das Durchlaufen einer Datenbank auf eine Weise, die mit `SELECT` – wenn überhaupt – nur sehr schwierig zu realisieren ist. Die `HANDLER`-Schnittstelle ist eine natürlicher anmutende Art der Datensicht, wenn Sie mit Anwendungen arbeiten, die eine interaktive Benutzeroberfläche für die Datenbank bereitstellen.

### 13.2.4. `INSERT`

    INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE]
        [INTO] tbl_name [(col_name,...)]
        VALUES ({expr | DEFAULT},...),(...),...
        [ ON DUPLICATE KEY UPDATE col_name=expr, ... ]

Oder:

    INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE]
        [INTO] tbl_name
        SET col_name={expr | DEFAULT}, ...
        [ ON DUPLICATE KEY UPDATE col_name=expr, ... ]

Oder:

    INSERT [LOW_PRIORITY | HIGH_PRIORITY] [IGNORE]
        [INTO] tbl_name [(col_name,...)]
        SELECT ...
        [ ON DUPLICATE KEY UPDATE col_name=expr, ... ]

`INSERT` fügt neue Datensätze in eine vorhandene Tabelle ein. Die Formen `INSERT ... VALUES` und `INSERT ... SET` der Anweisung fügen Datensätze basierend auf explizit angegebenen Werten ein. Die Form `INSERT ... SELECT` fügt Datensätze ein, die in einer oder mehreren anderen Tabellen ausgewählt wurden. `INSERT ... SELECT` wird in Abschnitt 13.2.4.1, „`INSERT ... SELECT`“, näher erläutert.

Sie können `REPLACE` anstelle von `INSERT` verwenden, um alte Datensätze zu überschreiben. `REPLACE` ist das Gegenstück zu `INSERT IGNORE` bei der Behandlung neuer Datensätze, deren eindeutige Schlüsselwerte Dubletten bereits vorhandener Datensätze sind: Die neuen Datensätze ersetzen die alten, statt verworfen zu werden. Siehe auch Abschnitt 13.2.6, „`REPLACE`“.

`tbl_name` ist die Tabelle, in die die Datensätze eingefügt werden sollen. Die Spalten, für die die Anweisung Werte angibt, lassen sich wie folgt angeben:

- Sie können eine kommagetrennte Liste von Spaltennamen gefolgt vom Tabellennamen angeben. In diesem Fall muss für jede genannte Spalte in der `VALUES`-Liste oder der `SELECT`-Anweisung ein Wert vorhanden sein.

- Wenn Sie keine Liste mit Spaltennamen für `INSERT ... VALUES` oder `INSERT ... SELECT` angeben, dann müssen die Werte für alle Spalten in der Tabelle in der `VALUES`-Liste oder der `SELECT`-Anweisung vorhanden sein. Wenn Sie die Reihenfolge der Spalten in der Tabelle nicht kennen, ermitteln Sie sie mit `DESCRIBE `tbl_name``.

- Die `SET`-Klausel gibt die Spaltennamen ausdrücklich an.

Spaltenwerte lassen sich auf mehrerlei Weise übergeben:

- Wenn Sie MySQL nicht im strikten SQL-Modus ausführen, dann wird jede Spalte, für die kein Wert angegeben wird, auf den (expliziten oder impliziten) Standardwert gesetzt. Wenn Sie also etwa eine Spaltenliste angeben, die nicht alle Spalten in der Tabelle aufführt, werden nicht genannte Spalten auf ihre jeweiligen Standardwerte gesetzt. Die Zuweisung von Standardwerten ist in Abschnitt 11.1.4, „Vorgabewerte von Datentypen“, beschrieben. Siehe auch Abschnitt 1.9.6.2, „Constraints auf ungültigen Daten“.

  Wenn Sie wollen, dass eine `INSERT`-Anweisung einen Fehler erzeugt, wenn Sie nicht alle Werte für alle Spalten ausdrücklich angeben, für die kein Standardwert vorhanden ist, dann sollten Sie den strikten Modus verwenden. Siehe auch Abschnitt 5.2.5, „Der SQL-Modus des Servers“.

- Mit dem Schlüsselwort `DEFAULT` können Sie eine Spalte explizit auf ihren Standardwert setzen. Dies erleichtert das Formulieren von `INSERT`-Anweisungen, die allen Spalten (bis auf einigen wenigen) Werte zuweisen, denn so brauchen Sie keine unvollständige `VALUES`-Liste zu erstellen, die nicht für jede Spalte in der Tabelle einen Wert enthält. Andernfalls müssten Sie die Liste der Spaltennamen ausschreiben, die den einzelnen Werten in der `VALUES`-Liste entspricht.

  Sie können auch `DEFAULT(`col_name`)` als eine allgemeinere Form benutzen, mit der in Ausdrücken der Standardwert einer gegebenen Spalte erzeugt werden kann.

- Wenn sowohl die Spaltenliste als auch die `VALUES`-Liste leer sind, erstellt `INSERT` einen Datensatz, bei dem jede Spalte auf den jeweiligen Standardwert gesetzt ist:

      INSERT INTO tbl_name () VALUES();

  Im strikten Modus tritt ein Fehler auf, wenn nicht für jede Spalte ein Standardwert angegeben ist. Andernfalls verwendet MySQL den impliziten Standardwert für jede Spalte, der kein expliziter Wert zugewiesen ist.

- Sie können den Spaltenwert auch durch einen Ausdruck `expr` angeben. Dies kann eine Typenkonvertierung bedingen, wenn der Ausdruckstyp nicht dem Typ der Spalte entspricht. Die Konvertierung eines gegebenen Werts kann je nach Datentyp zu unterschiedlichen Einfügewerten führen. So hat z. B. das Einfügen des Strings `'1999.0e-2'` in eine `INT`-. `FLOAT`-, `DECIMAL(10,6)`- oder `YEAR`-Spalte die Einfügewerte `1999`, `19.9921`, `19.992100` bzw. `1999` zur Folge. Der Grund dafür, dass der in den `INT`- und `YEAR`-Spalten gespeicherte Wert `1999` ist, besteht darin, dass bei der Konvertierung des Strings in den Integer nur der Teil des Strings berücksichtigt wird, der als gültiger Integer bzw. als sinnvolle Jahresangabe betrachtet wird. Bei Fließkomma- und Festkommaspalten wird bei der Umwandlung des Strings in einen Fließkommawert der gesamte String als zulässiger Fließkommawert betrachtet.

  Ein Ausdruck `expr` kann jede Spalte referenzieren, die zuvor in einer Werteliste eingestellt wurde. Sie könnten dies beispielsweise tun, weil der Wert von `col2` die zuvor zugewiesene Spalte `col1` referenziert:

      INSERT INTO tbl_name (col1,col2) VALUES(15,col1*2);

  Die folgende Variante ist jedoch nicht zulässig, weil der Wert für `col1` die Spalte `col2` referenziert, die jedoch erst nach `col1` zugewiesen wurde:

      INSERT INTO tbl_name (col1,col2) VALUES(col2*2,15);

  Eine Ausnahme betrifft Spalten, die `AUTO_INCREMENT`-Werte enthalten. Weil der `AUTO_INCREMENT`-Wert nach anderen Wertezuweisungen erzeugt wird, gibt eine Referenzierung einer `AUTO_INCREMENT`-Spalte `0` zurück.

`INSERT`-Anweisungen, die die `VALUES`-Syntax verwenden, können mehrere Datensätze einfügen. Zu diesem Zweck fügen Sie mehrere Listen mit Spaltenwerten ein, die jeweils in Klammern gesetzt und durch Kommata getrennt sind. Beispiel:

    INSERT INTO tbl_name (a,b,c) VALUES(1,2,3),(4,5,6),(7,8,9);

Die Werteliste für jeden Datensatz muss in Klammern gesetzt werden. Die folgende Anweisung ist unzulässig, weil die Anzahl der Werte in der Liste nicht der Anzahl der Spaltennamen entspricht:

    INSERT INTO tbl_name (a,b,c) VALUES(1,2,3,4,5,6,7,8,9);

Der Wert der von einer `INSERT`-Anweisung betroffenen Datensätze kann mit der C-API-Funktion `mysql_affected_rows()` ermittelt werden. Siehe auch Abschnitt 24.2.3.1, „`mysql_affected_rows()`“.

Wenn Sie eine `INSERT ... VALUES`-Anweisung mit mehreren Wertelisten oder `INSERT ... SELECT` verwenden, gibt die Anweisung einen Informations-String im folgenden Format zurück:

    Records: 100 Duplicates: 0 Warnings: 0

`Records` gibt die Anzahl der von der Anweisung verarbeiteten Datensätze zurück. (Dies entspricht nicht unbedingt der Anzahl der tatsächlich eingefügten Datensätze, weil `Duplicates` auch ungleich null sein kann.) `Duplicates` gibt die Anzahl der Datensätze an, die nicht eingefügt wurden, weil eindeutige Schlüsselwerte andernfalls dupliziert worden wären. `Warnings` gibt die Anzahl der Spalteneinfügeversuche an, die aus irgendeinem Grund problematisch waren. Warnungen können unter den folgenden Umständen auftreten:

- Einfügen von `NULL` in eine Spalte, die als `NOT NULL` deklariert wurde. Bei `INSERT`-Anweisung für mehrere Datensätze oder `INSERT INTO ... SELECT`-Anweisungen wird die Spalte auf den impliziten Standardwert für den betreffenden Spaltendatentyp gesetzt. Bei numerischen Typen ist dies `0`, bei String-Typen der Leer-String (`''`) und der „Nullwert“ bei Datums- und Uhrzeittypen. `INSERT INTO ... SELECT`-Anweisungen werden auf die gleiche Weise behandelt wie Einfügeoperationen für mehrere Datensätze, weil der Server die Ergebnismenge von `SELECT` nicht darauf überprüft, ob genau ein Datensatz zurückgegeben wird. (Bei `INSERT`-Anweisungen für nur einen Datensatz erscheint keine Warnung, wenn `NULL` in eine `NOT NULL`-Spalte eingefügt wird. Stattdessen schlägt die Anweisung mit einem Fehler fehl.)

- Setzen einer numerischen Spalte auf einen Wert außerhalb des zulässigen Wertebereichs. Der Wert wird auf den nächstgelegenen Endpunkt des Bereichs gesetzt.

- Zuweisen eines Werts wie `'10.34 a'` zu einer numerischen Spalte. Der nichtnumerische Text am Ende wird entfernt, und der verbleibende numerische Teil wird eingefügt. Hat der String-Wert am Anfang keinen numerischen Teil, dann wird die Spalte auf `0` gesetzt.

- Einfügen eines Strings in eine String-Spalte (`CHAR`, `VARCHAR`, `TEXT` oder `BLOB`), die die maximale Länge der Spalte überschreitet. Der Wert wird auf die zulässige Maximallänge der Spalte gekürzt.

- Einfügen eines Werts in eine Spalte für Datum oder Uhrzeit, der für diesen Datentyp nicht zulässig ist. Die Spalte wird auf den passenden Nullwert des Typs gesetzt.

Wenn Sie die C-API verwenden, kann der Informations-String durch Aufruf der Funktion `mysql_info()` ermittelt werden. Siehe auch Abschnitt 24.2.3.34, „`mysql_info()`“.

Wenn `INSERT` einen Datensatz in eine Tabelle einfügt, die eine `AUTO_INCREMENT`-Spalte enthält, dann können Sie den Wert dieser Spalte mithilfe der SQL-Funktion `LAST_INSERT_ID()` abfragen. Aus der C-API heraus verwenden Sie die Funktion `mysql_insert_id()`. Sie sollten allerdings beachten, dass die beiden Funktionen sich nicht immer identisch verhalten. Das Verhalten von `INSERT`-Anweisungen in Bezug auf `AUTO_INCREMENT`-Spalten wird in Abschnitt 12.10.3, „Informationsfunktionen“, und Abschnitt 24.2.3.36, „`mysql_insert_id()`“, ausführlicher beschrieben.

Die `INSERT`-Anweisung unterstützt die folgenden Modifizierer:

- Wenn Sie das Schlüsselwort `DELAYED` verwenden, legt der Server den oder die einzufügenden Datensätze in einem Puffer ab, und der Client, der die `INSERT DELAYED`-Anweisung abgesetzt hat, kann sofort weiterarbeiten. Wird die Tabelle gerade verwendet, dann hält der Server die Datensätze zurück. Sobald die Tabelle frei ist, startet der Server mit dem Einfügen der Datensätze und prüft dabei periodisch, ob neue Leseanforderungen für die Tabelle anstehen. In diesem Fall wird die Warteschlange mit den verzögerten Datensätzen angehalten, bis die Tabelle wieder frei wird. Siehe auch Abschnitt 13.2.4.2, „`INSERT DELAYED`“.

  `DELAYED` wird bei `INSERT ... SELECT` oder `INSERT ... ON DUPLICATE KEY UPDATE` ignoriert.

- Wenn Sie das Schlüsselwort `LOW_PRIORITY` angeben, wird die Ausführung von `INSERT` verzögert, bis kein Client mehr aus der Tabelle liest. Dies schließt andere Clients mit ein, die Leseoperationen starten, während bereits vorhandene Clients aus der Tabelle lesen und die `INSERT LOW_PRIORITY`-Anweisung wartet. Aus diesem Grund ist es möglich, dass ein Client, der eine `INSERT LOW_PRIORITY`-Anweisung absetzt, sehr lange warten muss – in Umgebungen mit extrem hohen Aufkommen von Leseoperationen sogar für immer. (Dies steht im Gegensatz zu `INSERT DELAYED`, wo der Client direkt fortfahren kann.) Beachten Sie, dass `LOW_PRIORITY` normalerweise nicht bei `MyISAM`-Tabellen benutzt werden sollte, da auf diese Weise gleichzeitige Einfügeoperationen unmöglich gemacht werden. Siehe auch Abschnitt 7.3.3, „Gleichzeitige Einfügevorgänge“.

- Wenn Sie `HIGH_PRIORITY` angeben, setzt es die Auswirkungen der Option `--low-priority-updates` außer Kraft, sofern der Server mit dieser Option gestartet worden war. Außerdem sind auch hier gleichzeitige Einfügeoperationen nicht möglich.

- Wenn Sie das Schlüsselwort `IGNORE` angeben, werden Fehler, die während der Ausführung der `INSERT`-Anweisung auftreten, als Warnungen behandelt. So würde beispielsweise ohne `IGNORE` ein Datensatz, der einen vorhandenen eindeutigen Index oder einen Primärschlüsselwert in der Tabelle dupliziert, einen Dublettenfehler verursachen, woraufhin die Anweisung abgebrochen würde. Bei `IGNORE` wird der Datensatz zwar auch nicht eingefügt, aber es wird kein Fehler ausgegeben. Bei Fehler auslösenden Datenkonvertierungen wird die Anweisung abgebrochen, wenn `IGNORE` nicht angegeben ist. Bei `IGNORE` hingegen werden ungültige Werte auf den jeweils nächstgelegenen gültigen Wert gesetzt und dann einfügt; außerdem werden Warnungen erzeugt, aber die Anweisung wird nicht abgebrochen. Mit der C-API-Funktion `mysql_info()` können Sie ermitteln, wie viele Datensätze tatsächlich in die Tabelle eingefügt wurden.

- Wenn Sie `ON DUPLICATE KEY UPDATE` angeben und ein Datensatz eingefügt wird, der einen doppelten Wert in einem eindeutigen Index oder einem Primärschlüssel erzeugen würde, dann wird für den alten Datensatz `UPDATE` ausgeführt. Siehe auch Abschnitt 13.2.4.3, „`INSERT ... ON DUPLICATE KEY UPDATE`“.

#### 13.2.4.1. `INSERT ... SELECT`

    INSERT [LOW_PRIORITY | HIGH_PRIORITY] [IGNORE]
        [INTO] tbl_name [(col_name,...)]
        SELECT ...
        [ ON DUPLICATE KEY UPDATE col_name=expr, ... ]

Mit `INSERT ... SELECT` können Sie schnell mehrere Datensätze aus einer oder mehreren Tabellen in eine Tabelle einfügen. Zum Beispiel:

    INSERT INTO tbl_temp2 (fld_id)
      SELECT tbl_temp1.fld_order_id
      FROM tbl_temp1 WHERE tbl_temp1.fld_order_id > 100;

Die folgenden Bedingungen gelten für eine `INSERT ... SELECT`-Anweisung:

- Geben Sie `IGNORE` an, um Datensätze zu ignorieren, die unzulässige Schlüsseldubletten erzeugen würden.

- `DELAYED` wird bei `INSERT ... SELECT` ignoriert.

- Die Zieltabelle der `INSERT`-Anweisung kann in der `FROM`-Klausel des `SELECT`-Teils der Abfrage erscheinen. (Dies war bei einigen älteren MySQL-Versionen nicht möglich.)

- `AUTO_INCREMENT`-Spalten arbeiten wie gewöhnlich.

- Um sicherzustellen, dass das Binärlog zur Wiederherstellung der Originaltabellen verwendet werden kann, gestattet MySQL keine nebenläufigen Einfügeoperationen während der Ausführung einer `INSERT ... SELECT`-Anweisung.

- Zurzeit können Sie in einer Unterabfrage keine Einfügeoperation in eine Tabelle durchführen und gleichzeitig eine Auswahl in einer anderen Tabelle treffen.

Im Werteteil von `ON DUPLICATE KEY UPDATE` können Sie Spalten in anderen Tabellen referenzieren, solange Sie im `SELECT`-Teil nicht `GROUP BY` verwenden. Eine Begleiterscheinung besteht darin, dass Sie nichteindeutige Spaltennamen im Werteteil qualifizieren müssen.

#### 13.2.4.2. `INSERT DELAYED`

    INSERT DELAYED ...

Die Option `DELAYED` für die `INSERT`-Anweisung ist eine MySQL-Erweiterung zum SQL-Standard, die sehr praktisch ist, wenn Sie Clients haben, die nicht auf den Abschluss der `INSERT`-Anweisung warten können oder müssen. Eine solche Situation liegt häufig vor, wenn Sie MySQL zum Loggen verwenden und zudem regelmäßig `SELECT`- und `UPDATE`-Anweisungen ausführen, deren Fertigstellung sehr lange dauert.

Wenn ein Client `INSERT DELAYED` verwendet, wird diese Anweisung vom Server sofort angenommen und der Datensatz in einer Warteschlange abgelegt. Sobald die Tabelle von keinem anderen Thread mehr verwendet wird, wird der Datensatz dann aus der Warteschlange eingefügt.

Ein weiterer wesentlicher Vorteil von `INSERT DELAYED` besteht darin, dass Einfügeoperationen mehrerer Clients gebündelt und dann in einem Block geschrieben werden. Dies ist bedeutend schneller als die Durchführung vieler separater Einfügeoperationen.

Beachten Sie, dass `INSERT DELAYED`, sofern die Tabelle gerade nicht anderweitig verwendet wird, langsamer als eine normale `INSERT`-Anweisung ist. Auch liegt die Serverbelastung etwas höher, weil der Server für jede Tabelle, für die verzögerte Datensätze vorhanden sind, einen separaten Thread verwalten muss. Insofern sollten Sie `INSERT DELAYED` nur verwenden, wenn Sie wirklich sicher sind, dass Sie die Funktionalität benötigen.

Die Datensätze in der Warteschlange verbleiben nur solange im Speicher, bis sie in die Tabelle eingefügt wurden. Aufgrund dessen gehen, wenn Sie mysqld – etwa mit `kill -9` – terminieren oder mysqld unerwartet abstürzt, alle Datensätze in der Warteschlange, die noch nicht auf Festplatte geschrieben wurden, verloren!

Für die Verwendung von `DELAYED` gelten einige Einschränkungen:

- `INSERT DELAYED` funktioniert nur bei `MyISAM`-, `MEMORY`- und `ARCHIVE`-Tabellen. Siehe auch Abschnitt 14.1, „Die `MyISAM`-Speicher-Engine“, Abschnitt 14.4, „Die `MEMORY`-Speicher-Engine“ und Abschnitt 14.8, „Die `ARCHIVE`-Speicher-Engine“.

  Bei `MyISAM`-Tabellen werden, wenn keine freien Blöcke in der Mitte der Datendatei vorhanden sind, gleichzeitige `SELECT`- und `INSERT`-Anweisung unterstützt. Unter diesen Umständen müssen Sie `INSERT DELAYED` bei `MyISAM` nur in sehr seltenen Fällen verwenden.

- `INSERT DELAYED` sollte nur für `INSERT`-Anweisungen eingesetzt werden, die Wertelisten angeben. Bei `INSERT DELAYED ... SELECT`-Anweisungen ignoriert der Server das `DELAYED`.

- Ebenso ignoriert der Server das `DELAYED` bei `INSERT ... SELECT`- oder `INSERT ... ON DUPLICATE KEY UPDATE`-Anweisungen.

- Weil die `INSERT DELAYED`-Anweisung aus Clientsicht abgeschlossen wird, bevor die Datensätze tatsächlich eingefügt werden, können Sie den von der Anweisung erstellten `AUTO_INCREMENT`-Wert nicht mit `LAST_INSERT_ID()` abrufen.

- Verzögerte Datensätze werden für `SELECT`-Anweisungen erst sichtbar, wenn sie tatsächlich eingefügt wurden.

- `DELAYED` wird auf Slave-Replikationsservern ignoriert, weil andernfalls auf dem Slave andere Daten vorhanden sein könnten als auf dem Master.

Nachfolgend wird ausführlich beschrieben, was geschieht, wenn Sie die Option `DELAYED` für `INSERT` oder `REPLACE` einsetzen. In dieser Beschreibung ist „Thread“ der Thread, der eine `INSERT DELAYED`-Anweisung empfangen hat, und „Handler“ der Thread, der alle `INSERT DELAYED`-Anweisungen der betreffenden Tabelle verwaltet.

- Wenn ein Thread eine `DELAYED`-Anweisung für eine Tabelle ausführt, wird – sofern nicht bereits vorhanden – ein Handler-Thread erzeugt, um alle `DELAYED`-Anweisungen für die Tabelle zu verarbeiten.

- Der Thread überprüft, ob der Handler zuvor bereits eine `DELAYED`-Sperre erwirkt hat, und weist den Handler andernfalls dazu an. Die `DELAYED`-Sperre kann auch dann erwirkt werden, wenn andere Threads eine `READ`- oder `WRITE`-Sperre für die Tabelle halten. Allerdings wartet der Handler, bis alle `ALTER TABLE`-Sperren aufgehoben und `FLUSH TABLES`-Anweisungen abgeschlossen sind, um zu gewährleisten, dass die Tabellenstruktur aktuell ist.

- Der Thread führt die `INSERT`-Anweisung aus, schreibt den Datensatz aber nicht in die Tabelle, sondern setzt eine Kopie des endgültigen Datensatzes in eine Warteschlange, die vom Handler verwaltet wird. Syntaxfehler werden vom Thread bemerkt und an das Clientprogramm zurückgemeldet.

- Der Client kann die Anzahl doppelter Datensätze oder den `AUTO_INCREMENT`-Wert des resultierenden Datensatzes nicht beim Server erfragen, weil die `INSERT`-Anweisung vor Durchführung der eigentlichen Einfügeoperation bereits abgeschlossen wird. (Wenn Sie die C-API verwenden, dann gibt die Funktion `mysql_info()` aus demselben Grund nur irrelevante Angaben zurück.)

- Das Binärlog wird vom Handler-Thread aktualisiert, sobald der Datensatz in die Tabelle eingefügt wurde. Im Falle des Einfügens mehrerer Datensätze wird das Binärlog aktualisiert, wenn der erste Datensatz eingefügt wird.

- Jedes Mal, wenn `delayed_insert_limit` Datensätze geschrieben wurden, überprüft der Handler, ob noch weitere `SELECT`-Anweisungen anhängig sind. Ist dies der Fall, so gestattet er deren Ausführung, bevor er fortfährt.

- Wenn der Handler keine Datensätze mehr in der Warteschlange hat, wird die Tabelle entsperrt. Werden innerhalb des durch `delayed_insert_timeout` (in Sekunden) angegebenen Zeitraums keine neuen `INSERT DELAYED`-Anweisungen empfangen, dann wird der Handler beendet.

- Sind mehr als `delayed_queue_size` Datensätze in einer bestimmten Handler-Warteschlange anhängig, dann fordert der Thread `INSERT DELAYED` auf, zu warten, bis wieder Platz in der Warteschlange ist. Hierdurch soll gewährleistet werden, dass mysqld nicht den gesamten Speicher für die Warteschlange mit den verzögerten Datensätzen verwendet.

- Der Handler-Thread erscheint in der MySQL-Prozessliste als `delayed_insert` in der Spalte `Command`. Er wird terminiert, wenn Sie eine `FLUSH TABLES`-Anweisung absetzen oder `KILL `thread_id`` ausführen. Allerdings speichert er vor der Terminierung alle in der Warteschlange vorhandenen Datensätze in die Tabelle, bevor er beendet wird. In diesem Zeitraum werden keine neuen `INSERT`-Anweisungen anderer Threads angenommen. Wenn Sie nachfolgend eine `INSERT DELAYED`-Anweisung ausführen, wird ein neuer Handler-Thread erstellt.

  Beachten Sie, dass dies bedeutet, dass `INSERT DELAYED`-Anweisungen Vorrang vor normalen `INSERT`-Anweisungen haben, wenn ein `INSERT DELAYED`-Handler ausgeführt wird. Andere Änderungsanweisungen müssen warten, bis die `INSERT DELAYED`-Warteschlange leer ist oder jemand den Handler-Thread (mit `KILL `thread_id``) terminiert oder eine `FLUSH TABLES`-Anweisung ausführt.

- Die folgenden Statusvariablen machen Angaben zu `INSERT DELAYED`-Anweisungen:

  Statusvariable | Bedeutung
  `Delayed_insert_threads` | Anzahl der Handler-Threads
  `Delayed_writes` | Anzahl der mit `INSERT DELAYED` geschriebenen Datensätze
  `Not_flushed_delayed_rows` | Anzahl der Datensätze, die noch geschrieben werden müssen

  Sie können diese Variablen anzeigen, indem Sie eine `SHOW STATUS`-Anweisung absetzen oder den Befehl mysqladmin extended-status ausführen.

#### 13.2.4.3. `INSERT ... ON DUPLICATE KEY UPDATE`

Wenn Sie `ON DUPLICATE KEY UPDATE` angeben und ein Datensatz eingefügt wird, der einen doppelten Wert in einem eindeutigen Index oder einem Primärschlüssel erzeugen würde, dann wird für den alten Datensatz `UPDATE` ausgeführt. Angenommen, die Spalte `a` wird als `UNIQUE` deklariert und enthält den Wert `1`; in diesem Fall hätten die beiden folgenden Anweisungen dieselbe Wirkung:

    INSERT INTO table (a,b,c) VALUES (1,2,3)
      ON DUPLICATE KEY UPDATE c=c+1;

    UPDATE table SET c=c+1 WHERE a=1;

Der Wert der betroffenen Datensätze ist 1, wenn der Datensatz als neuer Datensatz eingefügt wird, und 2, wenn ein vorhandener Eintrag aktualisiert wird.

Wenn die Spalte `b` ebenfalls eindeutig ist, ist die `INSERT`-Anweisung stattdessen gleichbedeutend mit der folgenden `UPDATE`-Anweisung:

    UPDATE table SET c=c+1 WHERE a=1 OR b=2 LIMIT 1;

Wenn `a=1 OR b=2` mehreren Datensätzen entspricht, wird nur ein Datensatz aktualisiert. Generell sollten Sie von der Verwendung einer `ON DUPLICATE KEY`-Klausel bei Tabellen mit mehreren eindeutigen Indizes absehen.

Sie können die Funktion `VALUES(`col_name`)` in der `UPDATE`-Klausel verwenden, um Spaltenwerte aus dem `INSERT`-Teil der `INSERT ... UPDATE`-Anweisung zu referenzieren. Anders gesagt, verweist `VALUES(`col_name`)` in der `UPDATE`-Klausel auf den Wert von `col_name`, der eingefügt worden wäre, wäre nicht ein Konflikt aufgrund einer Schlüsseldublette aufgetreten. Diese Funktion ist insbesondere bei Einfügevorgängen für mehrere Datensätze praktisch. Die Funktion `VALUES()` ist nur in `INSERT ... UPDATE`-Anweisungen sinnvoll zu verwenden; andernfalls gibt sie `NULL` zurück. Beispiel:

    INSERT INTO table (a,b,c) VALUES (1,2,3),(4,5,6)
      ON DUPLICATE KEY UPDATE c=VALUES(a)+VALUES(b);

Diese Anweisung ist identisch mit den folgenden beiden Anweisungen:

    INSERT INTO table (a,b,c) VALUES (1,2,3)
      ON DUPLICATE KEY UPDATE c=3;
    INSERT INTO table (a,b,c) VALUES (4,5,6)
      ON DUPLICATE KEY UPDATE c=9;

Die Option `DELAYED` wird ignoriert, wenn Sie `ON DUPLICATE KEY UPDATE` verwenden.

### 13.2.5. `LOAD DATA INFILE`

    LOAD DATA [LOW_PRIORITY | CONCURRENT] [LOCAL] INFILE 'file_name'
        [REPLACE | IGNORE]
        INTO TABLE tbl_name
        [FIELDS
            [TERMINATED BY 'string']
            [[OPTIONALLY] ENCLOSED BY 'char']
            [ESCAPED BY 'char']
        ]
        [LINES
            [STARTING BY 'string']
            [TERMINATED BY 'string']
        ]
        [IGNORE number LINES]
        [(col_name_or_user_var,...)]
        [SET col_name = expr,...)]

Die Anweisung `LOAD DATA INFILE` liest Datensätze mit extrem hoher Geschwindigkeit aus einer Textdatei in eine Tabelle ein. Der Dateiname muss als literaler String übergeben werden.

Die Syntax für die `FIELDS`- und `LINES`-Klauseln gilt auch für die `SELECT ... INTO OUTFILE`-Anweisung, die im weiteren Verlauf dieses Abschnitts beschrieben wird. (Siehe auch Abschnitt 13.2.7, „`SELECT`“.)

Weitere Informationen zur Effektivität von `INSERT` im Vergleich zu `LOAD DATA INFILE` und zur Beschleunigung von `LOAD DATA INFILE` finden Sie in Abschnitt 7.2.16, „Geschwindigkeit von `INSERT`-Anweisungen“.

Der von der Systemvariablen `character_set_database` angegebene Zeichensatz wird zur Interpretation der Daten in der Datei verwendet. `SET NAMES` und die Einstellung von `character_set_client` wirken sich hingegen nicht auf die Interpretation der Eingabe aus.

Beachten Sie, dass es derzeit nicht möglich ist, Datendateien zu laden, die den Zeichensatz `ucs2` verwenden.

Sie können Datendateien auch mithilfe des Hilfsprogramms mysqlimport laden; dieses sendet dann eine `LOAD DATA INFILE`-Anweisung an den Server. Die Option `--local` bewirkt, dass mysqlimport Datendateien vom Clienthost liest. Sie können die Option `--compress` angeben, um bei langsamen Netzwerken eine bessere Leistung zu erzielen, sofern Client und Server das Komprimierungsprotokoll unterstützen. Siehe auch Abschnitt 8.12, „mysqlimport — Programm zum Datenimport“.

Wenn Sie das Schlüsselwort `LOW_PRIORITY` angeben, wird die Ausführung von `LOAD DATA` verzögert, bis kein Client mehr aus der Tabelle liest.

Geben Sie `CONCURRENT` bei einer `MyISAM`-Tabelle an, die die Bedingungen für gleichzeitige Einfügeoperationen erfüllt (d. h. keine freien Blöcke in der Mitte enthält), dann können andere Threads Daten aus der Tabelle abrufen, während `LOAD DATA` ausgeführt wird. Die Verwendung dieser Option beeinflusst die Leistungsfähigkeit von `LOAD DATA` auch dann geringfügig, wenn gleichzeitig kein anderer Thread die Tabelle verwendet.

Das Schlüsselwort `LOCAL` wird, sofern angegeben, in Bezug auf die Clientseite der Verbindung interpretiert:

- Wenn `LOCAL` angegeben ist, wird die Datei vom Clientprogramm auf dem Clienthost gelesen und an den Server geschickt. Die Datei kann als vollständiger Pfadname angegeben werden, um die exakte Position zu beschreiben. Erfolgt die Angabe als relativer Pfadname, dann wird der Name relativ zum Verzeichnis interpretiert, in dem das Clientprogramm gestartet wurde.

- Wird `LOCAL` nicht angegeben, dann muss die Datei sich auf dem Serverhost befinden und wird direkt vom Server gelesen. Der Server wendet zur Bestimmung der Dateiposition die folgenden Regeln an:

  - Wenn der Dateiname absolut angegeben wurde, verwendet ihn der Server wie angegeben.

  - Ist der Dateiname ein relativer Pfadname mit einer oder mehreren am Anfang stehenden Komponenten, dann sucht der Server nach der Datei relativ zum eigenen Datenverzeichnis.

  - Wird ein Dateiname ohne Komponenten am Anfang übergeben, dann sucht der Server im Datenbankverzeichnis der Standarddatenbank nach der Datei.

Beachten Sie, dass, sofern keine `LOCAL`-Option angegeben wurde, die Regeln zur Folge haben, dass eine Datei namens `./myfile.txt` im Datenverzeichnis des Servers gesucht wird, während die Datei `myfile.txt` aus dem Datenbankverzeichnis der Standarddatenbank gelesen wird. Ist also beispielsweise `db1` die Standarddatenbank, dann liest die folgende `LOAD DATA`-Anweisung die Datei `data.txt` aus dem Datenbankverzeichnis für `db1` aus, obwohl die Anweisung die Datei explizit in die Datenbank `db2` lädt:

    LOAD DATA INFILE 'data.txt' INTO TABLE db2.my_table;

Windows-Pfadnamen müssen unter Verwendung von Schrägstrichen (statt Backslashs) angegeben werden. Wenn Sie Backslashs (umgekehrte Schrägstriche) verwenden, müssen Sie sie doppelt angeben.

Aus Sicherheitsgründen müssen Textdateien, die auf dem Server ausgelesen werden, entweder im Datenbankverzeichnis liegen oder von allen gelesen werden können. Außerdem benötigen Sie zur Verwendung von `LOAD DATA INFILE` für Serverdateien die Berechtigung `FILE`. Siehe auch Abschnitt 5.8.3, „Von MySQL zur Verfügung gestellte Berechtigungen“.

Die Verwendung von `LOCAL` ist ein wenig langsamer als der Direktzugriff des Servers auf die Dateien, weil der Inhalt der Datei vom Client über die Verbindung an den Server gesendet werden muss. Die Berechtigung `FILE` benötigen Sie hingegen zum Laden lokaler Dateien nicht.

Die Option `LOCAL` funktioniert nur, wenn ihre Verwendung sowohl am Client als auch am Server aktiviert wurde. Wenn beispielsweise mysqld mit `--local-infile=0` gestartet wurde, funktioniert `LOCAL` nicht. Siehe auch Abschnitt 5.7.4, „Sicherheitsprobleme mit `LOAD DATA LOCAL`“.

Unter Unix können Sie, wenn `LOAD DATA` über eine Pipe lesen soll, die folgende Methode verwenden (hierbei laden wir das Listing des Verzeichnisses `/` in eine Tabelle):

    mkfifo /mysql/db/x/x
    chmod 666 /mysql/db/x/x
    find / -ls > /mysql/db/x/x
    mysql -e "LOAD DATA INFILE 'x' INTO TABLE x" x

Die Schlüsselwörter `REPLACE` und `IGNORE` steuern den Umgang mit eingegebenen Datensätzen, die Duplikate vorhandener Datensätze mit eindeutigen Schlüsselwerten darstellen.

Wenn Sie `REPLACE` angeben, ersetzt die Eingabe vorhandene Datensätze. Dies betrifft Datensätze, die denselben Wert bei einem Primärschlüssel oder einem eindeutigen Index wie die neuen Datensätze haben. Siehe auch Abschnitt 13.2.6, „`REPLACE`“.

Bei Angabe von `IGNORE` hingegen werden neue Datensätze, deren eindeutiger Schlüsselwert bereits einem vorhandenen Datensatz zugewiesen ist, ignoriert. Wenn Sie keine Option angeben, hängt das Verhalten davon ab, ob das Schlüsselwort `LOCAL` angegeben wird. Ohne `LOCAL` tritt ein Fehler auf, wenn ein doppelter Schlüsselwert gefunden wird; in diesem Fall wird der Rest der Textdatei ignoriert. Mit `LOCAL` ist das Standardverhalten so, als ob `IGNORE` angegeben worden wäre. Das liegt daran, dass der Server keine Möglichkeit hat, die Übertragung der Datei während des Vorgangs zu beenden.

Wenn Sie Fremdschlüssel-Constraints während des Ladevorgangs ignorieren wollen, können Sie eine `SET FOREIGN_KEY_CHECKS=0`-Anweisung vor der Ausführung von `LOAD DATA` absetzen.

Wenn Sie `LOAD DATA INFILE` auf eine leere `MyISAM`-Tabelle anwenden, werden alle nichteindeutigen Indizes in einer separaten Stapeloperation erstellt (wie bei `REPAIR TABLE`). Dies sollte `LOAD DATA INFILE` erheblich beschleunigen, wenn Sie viele Indizes haben. In einigen Extremfällen können Sie die Indizes noch schneller erstellen, indem Sie sie vor dem Einladen der Datei in die Tabelle mit `ALTER TABLE ... DISABLE KEYS` abschalten und sie nach Abschluss des Ladevorgangs mit `ALTER TABLE ... ENABLE KEYS` neu erstellen. Siehe auch Abschnitt 7.2.16, „Geschwindigkeit von `INSERT`-Anweisungen“.

`LOAD DATA INFILE` ist das Gegenstück zu `SELECT ... INTO OUTFILE`. (Siehe auch Abschnitt 13.2.7, „`SELECT`“.) Um Daten aus einer Tabelle in eine Datei zu schreiben, benutzen Sie `SELECT ... INTO OUTFILE`; wollen Sie die Datei wieder in eine Tabelle einlesen, dann verwenden Sie `LOAD DATA INFILE`. Die Syntax der Klauseln `FIELDS` und `LINES` ist bei beiden Anweisungen dieselbe. Beide sind optional, aber `FIELDS` muss `LINES` vorangehen, sofern beide angegeben sind.

Wenn Sie eine `FIELDS`-Klausel festlegen, ist auch jede einzelne Unterklausel (`TERMINATED BY`, `[OPTIONALLY] ENCLOSED BY` und `ESCAPED BY`) ebenfalls optional – Sie müssen lediglich mindestens eine dieser Unterklauseln angeben.

Wenn Sie keine `FIELDS`-Klausel angeben, entsprechen die Vorgabeeinstellungen dem Folgenden:

    FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\'

Wenn Sie keine `LINES`-Klausel angeben, entsprechen die Vorgabeeinstellungen dem Folgenden:

    LINES TERMINATED BY '\n' STARTING BY ''

Anders gesagt, die Standardwerte bewirken, dass `LOAD DATA INFILE` sich beim Einlesen wie folgt verhält:

- Es wird nach Zeilenbegrenzungen bei Zeilenumbrüchen gesucht.

- Zeilenpräfixe werden nicht übersprungen.

- Zeilen werden bei Tabulatoren in Felder unterteilt.

- Felder müssen nicht innerhalb von Anführungszeichen abgeschlossen werden.

- Fälle von Tabulatoren, Zeilenumbrüchen oder ‘`\`’, denen ‘`\`’ vorangeht, werden als literale Zeichen interpretiert, die Teile von Feldwerten sind.

Umgekehrt bewirken die Voreinstellungen, dass sich `SELECT ... INTO OUTFILE` beim Schreiben einer Ausgabe wie folgt verhält:

- Tabulatoren werden zwischen Felder gesetzt.

- Mehrere Felder werden nicht zwischen Anführungszeichen gesetzt.

- ‘`\`’ wird zur Kennzeichnung von Tabulatoren, Zeilenumbrüchen und ‘`\`’ verwendet, die innerhalb von Feldwerten auftreten.

- Am Ende von Zeilen werden Zeilenumbrüche geschrieben.

Der Backslash wird bei MySQL als Escape-Zeichen in Strings verwendet. Insofern müssen Sie, um `FIELDS ESCAPED BY '\\'` zu schreiben, zwei Backslashes angeben, damit der Wert als ein Backslash interpretiert wird.

Hinweis: Wenn Sie die Textdatei auf einem Windows-System erzeugt haben, müssen Sie unter Umständen `LINES TERMINATED BY '\r\n'` verwenden, um die Datei korrekt einzulesen, weil Windows-Programme normalerweise zwei Zeichen als Zeilenendzeichen verwenden. Einige Programme wie WordPad verwenden beim Schreiben von Dateien unter Umständen sogar `\r` als Zeilenendzeichen. Um solche Dateien zu lesen, verwenden Sie `LINES TERMINATED BY '\r'`.

Wenn alle Zeilen, die Sie einlesen wollen, ein gemeinsames Präfix aufweisen, das Sie ignorieren wollen, können Sie mit `LINES STARTING BY '`prefix_string`'` das Präfix und alles, was davor steht, überspringen. Enthält eine Zeile das Präfix gar nicht, dann wird die gesamte Zeile übersprungen. Nehmen wir an, dass Sie folgende Anweisung absetzen:

    LOAD DATA INFILE '/tmp/test.txt' INTO TABLE test
      FIELDS TERMINATED BY ','  LINES STARTING BY 'xxx';

Nehmen wir ferner an, dass die Datendatei wie folgt aussieht:

    xxx"abc",1
    something xxx"def",2
    "ghi",3

In diesem Fall werden als Ergebnis die Datensätze `("abc",1)` und `("def",2)` erzeugt. Der dritte Datensatz in der Datei wird übersprungen, weil er das Präfix nicht enthält.

Die Option `IGNORE `number` LINES` kann verwendet werden, um Zeilen am Anfang der Datei zu ignorieren. So können Sie etwa `IGNORE 1 LINES` angeben, um eine Kopfzeile zu überspringen, die etwa die Spaltennamen enthält:

    LOAD DATA INFILE '/tmp/test.txt' INTO TABLE test IGNORE 1 LINES;

Wenn Sie `SELECT ... INTO OUTFILE` gemeinsam mit `LOAD DATA INFILE` verwenden, um Daten aus einer Datenbank in eine Datei zu schreiben und die Datei später wieder in die Datenbank einzulesen, dann müssen die Optionen der beiden Anweisungen zur Behandlung von Feldern und Zeilen einander entsprechen. Andernfalls kann `LOAD DATA INFILE` den Inhalt der Datei nicht korrekt einlesen. Angenommen, Sie schreiben mit `SELECT ... INTO OUTFILE` eine Datei mit Feldern, die kommagetrennt sind:

    SELECT * INTO OUTFILE 'data.txt'
      FIELDS TERMINATED BY ','
      FROM table2;

Um diese kommagetrennte Datei wieder einzulesen, müssen Sie folgende Anweisung verwenden:

    LOAD DATA INFILE 'data.txt' INTO TABLE table2
      FIELDS TERMINATED BY ',';

Haben Sie stattdessen probiert, die Datei mit der folgenden Anweisung einzulesen, dann ist dies nicht gelungen, da `LOAD DATA INFILE` angewiesen wird, nach Tabulatoren zwischen den Feldern zu suchen:

    LOAD DATA INFILE 'data.txt' INTO TABLE table2
      FIELDS TERMINATED BY '\t';

Infolgedessen wird jede Eingabezeile wohl als separates Feld interpretiert werden.

Mit `LOAD DATA INFILE` können Sie Dateien lesen, die Sie aus externen Quellen erhalten haben. Beispielsweise exportieren viele Programme Daten als kommagetrennte Werte im so genannten CSV-Format (Comma-Separate Values). Hierbei werden die Felder durch Kommata voneinander getrennt und in doppelte Anführungszeichen gesetzt. Wenn Zeilen in einer solchen Datei durch Zeilenumbrüche abgeschlossen werden, veranschaulicht die folgende Anweisung die Optionen zur Feld- und Zeilenbehandlung, wie Sie sie zum Laden der Datei verwenden würden:

    LOAD DATA INFILE 'data.txt' INTO TABLE tbl_name
      FIELDS TERMINATED BY ',' ENCLOSED BY '"'
      LINES TERMINATED BY '\n';

Alle Optionen zur Feld- und Zeilenbehandlung können einen Leer-String (`''`) angeben. Wenn der String nicht leer ist, müssen die Werte `FIELDS [OPTIONALLY] ENCLOSED BY` und `FIELDS ESCAPED BY` genau ein Zeichen umfassen. Die Werte `FIELDS TERMINATED BY`, `LINES STARTING BY` und `LINES TERMINATED BY` können hingegen auch mehrere Zeichen enthalten. Um etwa Zeilen zu schreiben, die jeweils aus einem aus einer Absatzschaltung und einem Zeilenvorschub bestehenden Zeichenpaar bestehen, geben Sie die Klausel `LINES TERMINATED BY '\r\n'` an.

Um eine Datei mit Witzen zu lesen, die durch aus `%%` bestehenden Zeilen getrennt sind, können Sie Folgendes tun:

    CREATE TABLE jokes
      (a INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
      joke TEXT NOT NULL);
    LOAD DATA INFILE '/tmp/jokes.txt' INTO TABLE jokes
      FIELDS TERMINATED BY ''
      LINES TERMINATED BY '\n%%\n' (joke);

`FIELDS [OPTIONALLY] ENCLOSED BY` steuert die Anführungszeichen um die Felder. Bei der Ausgabe (`SELECT ... INTO OUTFILE`) werden, wenn Sie das Wort `OPTIONALLY` weglassen, alle Felder vom durch `ENCLOSED BY` angegebenen Zeichen umschlossen. Hier ein Beispiel für eine solche Ausgabe (mit dem Komma als Feldtrennzeichen):

    "1","a string","100.20"
    "2","a string containing a , comma","102.20"
    "3","a string containing a \" quote","102.20"
    "4","a string containing a \", quote and comma","102.20"

Wenn Sie `OPTIONALLY` angeben, wird das `ENCLOSED BY`-Zeichen nur zum Umschließen von Werten in Spalten verwendet, die einen String-Datentyp haben (z. B. `CHAR`, `BINARY`, `TEXT` oder `ENUM`):

    1,"a string",100.20
    2,"a string containing a , comma",102.20
    3,"a string containing a \" quote",102.20
    4,"a string containing a \", quote and comma",102.20

Beachten Sie, dass das Auftreten des `ENCLOSED BY`-Zeichens in einem Feldwert gekennzeichnet wird, indem man ihm das `ESCAPED BY`-Zeichen voranstellt. Ferner ist wichtig, dass es, wenn Sie einen leeren `ESCAPED BY`-Wert angeben, möglich ist, versehentlich eine Ausgabe zu erzeugen, die von `LOAD DATA INFILE` nicht korrekt eingelesen werden kann. Die obige Ausgabe beispielsweise würde wie folgt angezeigt werden, wenn das Escape-Zeichen leer wäre. Sie werden bemerken, dass das zweite Feld in der vierten Zeile ein auf das Anführungszeichen folgendes Komma enthält, welches das Feld abzuschließen scheint (was nicht zutrifft).

    1,"a string",100.20
    2,"a string containing a , comma",102.20
    3,"a string containing a " quote",102.20
    4,"a string containing a ", quote and comma",102.20

Bei der Eingabe wird das `ENCLOSED BY`-Zeichen – sofern vorhanden – am Ende der jeweiligen Feldwerte entfernt. (Dies erfolgt unabhängig davon, ob `OPTIONALLY` angegeben ist oder nicht – `OPTIONALLY` hat keine Auswirkung auf die Eingabeinterpretation.) Instanzen des `ENCLOSED BY`-Zeichens, denen das `ESCAPED BY`-Zeichen vorangestellt ist, werden als Teil des aktuellen Feldwerts interpretiert.

Beginnt das Feld mit dem `ENCLOSED BY`-Zeichen, dann werden Instanzen dieses Zeichens nur dann als Feldtrennzeichen ausgewertet, wenn ihnen jeweils die `TERMINATED BY`-Sequenz für Feld oder Zeile folgt. Um Mehrdeutigkeiten zu vermeiden, können Fälle des `ENCLOSED BY`-Zeichens innerhalb eines Feldwerts verdoppelt werden; sie werden dann als einzelne Instanz des Zeichens ausgewertet. Wird also etwa `ENCLOSED BY '"'` angegeben, dann wird mit Anführungszeichen wie hier gezeigt verfahren:

    "The ""BIG"" boss"  -> The "BIG" boss
    The "BIG" boss      -> The "BIG" boss
    The ""BIG"" boss    -> The ""BIG"" boss

`FIELDS ESCAPED BY` steuert, wie Sonderzeichen geschrieben oder gelesen werden. Wenn das `FIELDS ESCAPED BY`-Zeichen nicht leer ist, dann wird es bei der Ausgabe als Präfix für die folgenden Zeichen verwendet:

- `FIELDS ESCAPED BY`-Zeichen

- `FIELDS [OPTIONALLY] ENCLOSED BY`-Zeichen

- das erste Zeichen der Werte `FIELDS TERMINATED BY` und `LINES TERMINATED BY`

- ASCII `0` (eigentlich wird auf das Escape-Zeichen folgend ASCII ‘`0`’ und kein Nullwertbyte geschrieben)

Ist das `FIELDS ESCAPED BY`-Zeichen leer, dann werden keinerlei Zeichen gekennzeichnet und `NULL` wird als `NULL` (und nicht als `\N`) ausgegeben. Es ist wahrscheinlich nicht angeraten, ein leeres Escape-Zeichen anzugeben; dies gilt insbesondere dann, wenn Feldwerte in Ihren Daten eines der in der obigen Liste enthaltenen Zeichen enthalten.

Wenn das `FIELDS ESCAPED BY`-Zeichen nicht leer ist, werden Instanzen dieses Zeichens bei der Eingabe entfernt, und das nachfolgende Zeichen wird literal als Teil des Feldwerts verwendet. Ausnahmen sind die gekennzeichneten Zeichen ‘`0`’ oder ‘`N`’ (z. B. `\0` oder `\N`, wenn das Escape-Zeichen ‘`\`’ ist). Diese Sequenzen werden als ASCII-NUL (Nullwertbyte) bzw. als `NULL` interpretiert. Die Regeln für den Umgang mit `NULL` werden im weiteren Verlauf dieses Abschnitts beschrieben.

Weitere Informationen zur ‘`\`’-Escape-Syntax finden Sie in Abschnitt 9.1, „Literale: wie Strings und Zahlen geschrieben werden“.

In bestimmten Fällen interagieren die Optionen zur Feld- und Zeilenbehandlung:

- Wenn `LINES TERMINATED BY` ein Leer-String und `FIELDS TERMINATED BY` nicht leer ist, werden Zeilen auch mit `FIELDS TERMINATED BY` abgeschlossen.

- Sind die Werte von `FIELDS TERMINATED BY` und `FIELDS ENCLOSED BY` beide leer (`''`), dann wird ein festes Datensatzformat (ohne Trennzeichen) verwendet. Bei einem solchen Format fehlt zwar das Trennzeichen, ein Zeilenabschlusszeichen kann aber nichtsdestoweniger vorhanden sein. Stattdessen werden Spaltenwerte unter Berücksichtigung der Anzeigebreiten der Spalten geschrieben und gelesen. Wird z. B. eine Spalte als `INT(7)` deklariert, dann werden Werte für diese Spalte unter Verwendung von Feldern mit einer Länge von sieben Zeichen geschrieben. Bei der Eingabe werden die Spaltenwerte dann ermittelt, indem sieben Zeichen ausgelesen werden.

  `LINES TERMINATED BY` wird nach wie vor zur Trennung von Zeilen verwendet. Wenn eine Zeile nicht alle Felder enthält, werden die verbleibenden Spalten auf ihre Vorgabewerte gesetzt. Wenn kein Zeilenabschlusszeichen vorhanden ist, sollten Sie dieses auf `''` setzen. In diesem Fall muss die Textdatei alle Felder für jeden Datensatz enthalten.

  Das Festformat für Datensätze beeinflusst auch den Umgang mit `NULL`-Werten (siehe unten). Beachten Sie, dass dieses Format nicht funktioniert, wenn Sie einen Multibytezeichensatz verwenden.

Die Handhabung von `NULL`-Werten variiert entsprechend den verwendeten `FIELDS`- und `LINES`-Optionen:

- Bei den `FIELDS`- und `LINES`-Standardwerten wird `NULL` als Feldwert `\N` in die Ausgabe geschrieben. Analog wird der Feldwert `\N` bei der Eingabe als `NULL` gelesen (vorausgesetzt, das `ESCAPED BY`-Zeichen ist ‘`\`’).

- Wenn `FIELDS ENCLOSED BY` nicht leer ist, dann wird ein Feld, das das Wort `NULL` als Wert enthält, als `NULL`-Wert gelesen. Dies unterscheidet sich von dem Wort `NULL`, wenn es in `FIELDS ENCLOSED BY`-Zeichen gesetzt ist – dieses wird als `'NULL'` gelesen.

- Ist `FIELDS ESCAPED BY` leer, dann wird `NULL` als Wort `NULL` geschrieben.

- Beim Festformat (welches verwendet wird, wenn `FIELDS TERMINATED BY` und `FIELDS ENCLOSED BY` beide leer sind), wird `NULL` als Leer-String geschrieben. Beachten Sie, dass dies zur Folge hat, dass `NULL`-Werte und Leer-Strings in der Tabelle nicht mehr unterschieden werden können, sobald sie in die Datei geschrieben werden, weil beide als Leer-Strings geschrieben werden. Müssen die beiden Werte nach dem Wiedereinlesen der Datei weiterhin unterscheidbar sein, dann sollten Sie das Festformat nicht verwenden.

Manche Fälle werden von `LOAD DATA INFILE` nicht unterstützt:

- Datensätze fester Länge (`FIELDS TERMINATED BY` und `FIELDS ENCLOSED BY` sind leer) und `BLOB`- oder `TEXT`-Spalten.

- Wenn Sie ein Trennzeichen angeben, das mit einem anderen Trennzeichen (oder dessen Präfix) identisch ist, kann `LOAD DATA INFILE` die Eingabe nicht korrekt interpretieren. Die folgende `FIELDS`-Klausel beispielsweise würde Probleme verursachen:

      FIELDS TERMINATED BY '"' ENCLOSED BY '"'

- Wenn `FIELDS ESCAPED BY` leer ist, bewirkt ein Feldwert, der eine Instanz von `FIELDS ENCLOSED BY` oder `LINES TERMINATED BY` gefolgt vom `FIELDS TERMINATED BY`-Wert enthält, dass `LOAD DATA INFILE` das Einlesen eines Felds oder einer Zeile zu früh beendet. Dies geschieht, weil `LOAD DATA INFILE` nicht genau bestimmen kann, wo der Feld- oder Zeilenwert endet.

Das folgende Beispiel lädt alle Spalten der Tabelle `persondata`:

    LOAD DATA INFILE 'persondata.txt' INTO TABLE persondata;

Standardmäßig wird, wenn keine Spaltenliste am Ende der `LOAD DATA INFILE`-Anweisung vorhanden ist, erwartet, dass Eingabezeilen ein Feld für jede Tabellenspalte enthalten. Wenn Sie nur einen Teil der Spalten einer Tabelle laden wollen, müssen Sie eine Spaltenliste angeben:

    LOAD DATA INFILE 'persondata.txt' INTO TABLE persondata (col1,col2,...);

Ferner müssen Sie eine Spaltenliste festlegen, wenn die Reihenfolge der Felder in der Eingabedatei sich von der Reihenfolge der Spalten in der Tabelle unterscheidet. Andernfalls kann MySQL nicht ermitteln, wie die Eingabefelder den Tabellenspalten zuzuordnen sind.

Die Spaltenliste kann entweder Spaltennamen oder Benutzervariablen enthalten. Bei Benutzervariablen gestattet Ihnen die `SET`-Klausel die Durchführung einer Werteumwandlung vor der Zuweisung des Ergebnisses zu den Spalten.

Benutzervariablen in der `SET`-Klausel können auf unterschiedliche Weise verwendet werden. Die folgenden Werte benutzen die erste Eingabespalte direkt für den Wert von `t1.column1` und weisen die zweite Eingabespalte einer Benutzervariablen zu, an der eine Division durchgeführt wird, bevor sie als Wert für `t1.column2` verwendet wird:

    LOAD DATA INFILE 'file.txt'
      INTO TABLE t1
      (column1, @var1)
      SET column2 = @var1/100;

Die `SET`-Klausel kann zur Übermittlung von Werten benutzt werden, die nicht der Eingabedatei entnommen wurden. Die folgende Anweisung weist `column3` das aktuelle Datum und die Uhrzeit zu:

    LOAD DATA INFILE 'file.txt'
      INTO TABLE t1
      (column1, column2)
      SET column3 = CURRENT_TIMESTAMP;

Sie können einen Eingabewert auch verwerfen, indem Sie ihn einer Benutzervariablen zuweisen, der Variablen aber keine Tabellenspalte zuordnen:

    LOAD DATA INFILE 'file.txt'
      INTO TABLE t1
      (column1, @dummy, column2, @dummy, column3);

Die Verwendung der Spalten-/Variablenliste und der `SET`-Klausel ist den folgenden Einschränkungen unterworfen:

- Zuordnungen in der `SET`-Klausel sollten auf der linken Seite des Zuweisungsoperators nur Spaltennamen aufweisen.

- Auf der rechten Seite einer `SET`-Zuordnung dürfen auch Unterabfragen zum Einsatz kommen. Eine Unterabfrage, die einen Wert zurückgibt, der einer Spalte zugeordnet werden soll, darf nur eine skalare Unterabfrage sein. Außerdem können Sie eine Unterabfrage nicht für Auswahlabfragen an die Tabelle verwenden, die gerade geladen wird.

- Zeilen, die von einer `IGNORE`-Klausel ignoriert werden, werden für die Spalten-/Variablenliste oder die `SET`-Klausel nicht verarbeitet.

- Benutzervariablen können nicht verwendet werden, wenn Daten mit Festformat geladen werden, da Benutzervariablen keine Anzeigebreite haben.

Wenn eine Eingabezeile verarbeitet wird, unterteilt `LOAD DATA` sie in Felder und verwendet die Werte entsprechend der Spalten-/Variablenliste und der `SET`-Klausel, sofern diese vorhanden sind. Der Ergebnisdatensatz wird dann in die Tabelle eingefügt. Sind `BEFORE INSERT`- oder `AFTER INSERT`-Trigger für die Tabelle vorhanden, so werden diese vor bzw. nach dem Einfügen des Datensatzes aktiviert.

Hat eine Eingabezeile zu viele Felder, dann werden die überzähligen Felder ignoriert und die Anzahl der Warnungen wird erhöht.

Hat eine Eingabezeile zu wenig Felder, dann werden die Tabellenspalten, deren Eingabefelder fehlen, auf ihre Standardwerte gesetzt. Die Zuweisung von Standardwerten ist in Abschnitt 11.1.4, „Vorgabewerte von Datentypen“, beschrieben.

Ein leerer Feldwert wird anders interpretiert als ein fehlender Feldwert:

- Bei String-Typen wird die Spalte auf den Leer-String gesetzt.

- Bei numerischen Typen wird die Spalte auf `0` gesetzt.

- Bei zeitbezogenen Typen wird die Spalte auf den passenden „Nullwert“ des Typs gesetzt. Siehe auch Abschnitt 11.3, „Datums- und Zeittypen“.

Dies sind dieselben Werte, die als Ergebnis ausgegeben werden, wenn Sie einem String, einem numerischen oder einem zeitbezogenen Wert in einer `INSERT`- oder `UPDATE`-Anweisung explizit den Leer-String zuweisen.

`TIMESTAMP`-Spalten werden nur dann auf die aktuellen Werte für Datum und Uhrzeit gesetzt, wenn ein `NULL`-Wert (d. h. `\N`) für die Spalte vorhanden ist oder der Standardwert der `TIMESTAMP`-Spalte der aktuelle Zeitstempel ist und in der Feldliste (sofern vorhanden) weggelassen wurde.

`LOAD DATA INFILE` betrachtet alle Eingaben als Strings, d. h., Sie können für `ENUM`- oder `SET`-Spalten numerische Werte nicht so eingeben wie von `INSERT`-Anweisungen her gewohnt. Alle `ENUM`- und `SET`-Werte müssen als Strings angegeben werden.

Wenn die `LOAD DATA INFILE`-Anweisung abgeschlossen ist, gibt sie einen Informations-String im folgenden Format zurück:

    Records: 1  Deleted: 0  Skipped: 0  Warnings: 0

Wenn Sie die C-API verwenden, können Sie Informationen zur Anweisung durch einen Aufruf der Funktion `mysql_info()` ermitteln. Siehe auch Abschnitt 24.2.3.34, „`mysql_info()`“.

Warnungen treten unter denselben Umständen auf wie beim Einfügen von Werten mithilfe der `INSERT`-Anweisung (siehe Abschnitt 13.2.4, „`INSERT`“); der einzige Unterschied besteht darin, dass `LOAD DATA INFILE` auch dann Warnungen erzeugt, wenn zu wenig oder zu viel Felder im Eingabedatensatz vorhanden sind. Die Warnungen werden nirgends gespeichert; Sie können ihrer Anzahl lediglich entnehmen, ob alles geklappt hat oder nicht.

Mit `SHOW WARNINGS` erhalten Sie eine Liste der ersten `max_error_count` Warnungen mit Informationen dazu, was unter Umständen nicht geklappt hat. Siehe auch Abschnitt 13.5.4.25, „`SHOW WARNINGS`“.

### 13.2.6. `REPLACE`

    REPLACE [LOW_PRIORITY | DELAYED]
        [INTO] tbl_name [(col_name,...)]
        VALUES ({expr | DEFAULT},...),(...),...

Oder:

    REPLACE [LOW_PRIORITY | DELAYED]
        [INTO] tbl_name
        SET col_name={expr | DEFAULT}, ...

Oder:

    REPLACE [LOW_PRIORITY | DELAYED]
        [INTO] tbl_name [(col_name,...)]
        SELECT ...

`REPLACE` funktioniert auf exakt gleiche Weise wie `INSERT`. Der Unterschied besteht darin, dass, wenn ein alter Datensatz denselben Wert wie ein neuer Datensatz für einen Primärschlüssel oder einen eindeutigen Index hat, der alte Datensatz gelöscht wird, bevor der neue eingefügt wird. Siehe auch Abschnitt 13.2.4, „`INSERT`“.

`REPLACE` ist eine MySQL-Erweiterung zum SQL-Standard. Es kann Datensätze einfügen, oder es kann Datensätze löschen und einfügen. Wenn Sie eine Anweisung suchen, die dem SQL-Standard entspricht und die entweder einfügt oder aktualisiert, dann benutzen Sie die `INSERT ... ON DUPLICATE KEY UPDATE`-Anweisung (siehe auch Abschnitt 13.2.4.3, „`INSERT ... ON DUPLICATE KEY UPDATE`“).

Beachten Sie, dass, sofern die Tabelle nicht einen Primärschlüssel oder einen eindeutigen Index hat, die Verwendung von `REPLACE` unsinnig ist. Die Anweisung wäre dann mit `INSERT` identisch, weil kein Index vorhanden ist, anhand dessen bestimmt werden könnte, ob ein neuer Datensatz ein Duplikat eines bereits vorhandenen darstellt.

Werte für alle Spalten werden den Werten entnommen, die in der `REPLACE`-Anweisung angegeben sind. Fehlende Spalten werden – wie bei `INSERT` – auf ihre Standardwerte gesetzt. Es ist nicht möglich, Werte aus dem aktuellen Datensatz zu referenzieren und diese dann im neuen Datensatz zu verwenden. Wenn Sie eine Zuordnung wie `SET `col_name` = `col_name` + 1` verwenden, wird die Referenzierung des Spaltennamens auf der rechten Seite wie `DEFAULT(`col_name`)` behandelt, d. h., die Zuordnung ist äquivalent zu `SET `col_name` = DEFAULT(`col_name`) + 1`.

Um `REPLACE` zu verwenden, benötigen Sie die Berechtigungen `INSERT` und `DELETE` für die Tabelle.

Die `REPLACE`-Anweisung gibt einen Wert zurück, der die Anzahl der betroffenen Datensätze angibt. Konkret ist dies die Summe der gelöschten und eingefügten Datensätze. Wenn der Wert bei einer `REPLACE`-Anweisung für einen Datensatz 1 beträgt, dann wurde ein Datensatz eingefügt und keiner gelöscht. Ist der Wert größer als 1, dann wurden ein oder mehrere alte Datensätze gelöscht, bevor der neue Datensatz eingefügt wurde. Ein einzelner Datensatz kann durchaus mehr als nur einen alten Datensatz ersetzen, sofern die Tabelle mehrere eindeutige Indizes hat und der neue Datensatz Werte verschiedener alter Datensätze in verschiedenen eindeutigen Indizes dupliziert.

Die Anzahl der betroffenen Datensätze erlaubt also die einfache Bestimmung, ob `REPLACE` nur einen Datensatz hinzugefügt hat oder ob auch Datensätze ersetzt wurden: Überprüfen Sie, ob der Wert 1 (Hinzufügung) oder größer ist (Ersetzung).

Wenn Sie die C-API verwenden, kann die Anzahl der betroffenen Datensätze durch die Funktion `mysql_affected_rows()` ermittelt werden.

Zurzeit können Sie in einer Unterabfrage keine Ersetzungsoperation in einer Tabelle durchführen und gleichzeitig eine Auswahl in einer anderen Tabelle treffen.

MySQL verwendet für `REPLACE` (und `LOAD DATA ... REPLACE`) den folgenden Algorithmus:

1. Es wird versucht, den neuen Datensatz in die Tabelle einzufügen.

2. Wenn die Einfügeoperation aufgrund einer Schlüsseldublette in einem Primärschlüssel oder einem eindeutigen Index fehlschlägt,

   1. wird der konfliktauslösende Datensatz mit dem doppelten Schlüsselwert aus der Tabelle entfernt,

   2. wird erneut versucht, den neuen Datensatz in die Tabelle einzufügen.

### 13.2.7. `SELECT`

    SELECT
        [ALL | DISTINCT | DISTINCTROW ]
          [HIGH_PRIORITY]
          [STRAIGHT_JOIN]
          [SQL_SMALL_RESULT] [SQL_BIG_RESULT] [SQL_BUFFER_RESULT]
          [SQL_CACHE | SQL_NO_CACHE] [SQL_CALC_FOUND_ROWS]
        select_expr, ...
        [FROM table_references
        [WHERE where_condition]
        [GROUP BY {col_name | expr | position}
          [ASC | DESC], ... [WITH ROLLUP]]
        [HAVING where_condition]
        [ORDER BY {col_name | expr | position}
          [ASC | DESC], ...]
        [LIMIT {[offset,] row_count | row_count OFFSET offset}]
        [PROCEDURE procedure_name(argument_list)]
        [INTO OUTFILE 'file_name' export_options
          | INTO DUMPFILE 'file_name']
        [FOR UPDATE | LOCK IN SHARE MODE]]

`SELECT` wird zum Abrufen von Datensätzen verwendet, die aus einer oder mehreren Tabellen ausgewählt wurden, und kann `UNION`-Anweisungen und Unterabfragen enthalten. Siehe auch Abschnitt 13.2.7.2, „`UNION`“, und Abschnitt 13.2.8, „Syntax von Unterabfragen“.

Die meistverwendeten Klauseln für `SELECT` sind die folgenden:

- Jede `select_expr` gibt eine Spalte an, die Sie abrufen wollen. Es muss mindestens ein `select_expr` vorhanden sein.

- `table_references` gibt die Tabelle(n) an, aus der oder denen die Datensätze abgerufen werden sollen. Die Syntax ist in Abschnitt 13.2.7.1, „`JOIN`“, beschrieben.

- Die `WHERE`-Klausel gibt, soweit vorhanden, die Bedingung(en) an, die Datensätze erfüllen müssen, damit sie ausgewählt werden. `where_condition` ist ein Ausdruck, der für jeden auszuwählenden Datensatz wahr ist. Die Anweisung wählt, wenn keine `WHERE`-Klausel vorhanden ist, alle Datensätze aus.

  Sie können in der `WHERE`-Klausel alle von MySQL unterstützten Funktionen und Operatoren mit Ausnahme der Zusammenfassungsfunktionen einsetzen. Siehe auch Kapitel 12, Funktionen für die Benutzung in `SELECT`- und `WHERE`-Klauseln.

`SELECT` kann auch verwendet werden, um Datensätze abzurufen, die ohne Referenzierung einer Tabelle berechnet wurden.

Zum Beispiel:

    mysql> SELECT 1 + 1;
            -> 2

Sie können `DUAL` als Pseudotabellenname in Situationen angeben, in denen keine Tabellen referenziert werden:

    mysql> SELECT 1 + 1 FROM DUAL;
            -> 2

`DUAL` ist ausschließlich zum Zweck der Kompatibilität mit anderen Datenbankservern vorhanden, die eine `FROM`-Klausel erfordern. MySQL benötigt keine solche Klausel, wenn keine Tabellen referenziert werden.

Generell müssen Klauseln in genau der Reihenfolge angegeben werden, die in der Syntaxbeschreibung erscheint. So muss etwa eine `HAVING`-Klausel hinter den `GROUP BY`-Klauseln und vor den `ORDER BY`-Klauseln stehen. Die einzige Ausnahme ist die `INTO`-Klausel, die entweder wie in der Syntaxbeschreibung gezeigt oder unmittelbar vor der `FROM`-Klausel stehen kann.

- Einem Ausdruck `select_expr` lässt sich mit `AS `alias_name`` ein Alias zuweisen. Der Alias wird als Spaltenname des Ausdrucks benutzt und kann in `GROUP BY`-, `ORDER BY`- oder `HAVING`-Klauseln verwendet werden. Zum Beispiel:

      SELECT CONCAT(last_name,', ',first_name) AS full_name
        FROM mytable ORDER BY full_name;

  Das Schlüsselwort `AS` ist beim Zuweisen eines Alias zu `select_expr` optional. Das obige Beispiel hätte auch wie folgt geschrieben sein können:

      SELECT CONCAT(last_name,', ',first_name) full_name
        FROM mytable ORDER BY full_name;

  Allerdings kann, weil `AS` optional ist, ein kleines Problem auftreten, wenn Sie das Komma zwischen zwei `select_expr`-Ausdrücken vergessen: MySQL interpretiert den zweiten Ausdruck als Aliasnamen. Sie wird etwa in der folgenden Anweisung `columnb` als Aliasname behandelt:

      SELECT columna columnb FROM mytable;

  Aus diesem Grund hat es sich bewährt, `AS` beim Festlegen von Spaltenaliasen immer explizit anzugeben.

- Es ist nicht zulässig, einen Spaltenalias in einer `WHERE`-Klausel zu verwenden, weil der Spaltenwert unter Umständen nicht bestimmt werden kann, wenn die `WHERE`-Klausel ausgeführt wird. Siehe auch Abschnitt A.5.4, „Probleme mit `alias`“.

- Die Klausel `FROM `table_references`` gibt die Tabelle(n) an, aus der oder denen die Datensätze abgerufen werden sollen. Wenn Sie mehr als eine Tabelle angeben, führen Sie einen Join durch. Informationen zur Join-Syntax finden Sie in Abschnitt 13.2.7.1, „`JOIN`“. Für jede angegebene Tabelle können Sie optional einen Alias angeben.

      tbl_name [[AS] alias]
          [{USE|IGNORE|FORCE} INDEX (key_list)]

  Wie Sie dem Optimierer mit `USE INDEX`, `IGNORE INDEX` und `FORCE INDEX` Hinweise zur Auswahl der Indizes geben, ist in Abschnitt 13.2.7.1, „`JOIN`“, beschrieben.

  Sie können `SET max_seeks_for_key=`value`` als alternative Möglichkeit verwenden, um MySQL zur Verwendung von Schlüssel- statt Tabellenscans (sofern möglich) zu zwingen. Siehe auch Abschnitt 5.2.2, „Server-Systemvariablen“.

- Sie können eine Tabelle in der Standarddatenbank als `tbl_name` oder – wenn Sie eine Datenbank ausdrücklich angeben wollen – als `db_name`.`tbl_name` referenzieren. Eine Spalte können Sie als `col_name`, `tbl_name`.`col_name` oder `db_name`.`tbl_name`.`col_name` referenzieren. Sie müssen das Präfix `tbl_name` oder `db_name`.`tbl_name` für eine Spaltenreferenzierung nicht angeben, sofern die Referenzierung eindeutig ist. Beispiele für Mehrdeutigkeiten, die die spezifischeren Formen der Spaltenreferenzierung erfordern, finden Sie in Abschnitt 9.2, „Datenbank-, Tabellen-, Index-, Spalten- und Aliasnamen“.

- Für einen Tabellenverweis kann mit ``tbl_name` AS `alias_name`` oder `tbl_name alias_name` ein Alias erstellt werden:

      SELECT t1.name, t2.salary FROM employee AS t1, info AS t2
        WHERE t1.name = t2.name;

      SELECT t1.name, t2.salary FROM employee t1, info t2
        WHERE t1.name = t2.name;

- Spalten, die für die Ausgabe ausgewählt werden, lassen sich in `ORDER BY`- und `GROUP BY`-Klauseln als Spaltennamen, Spaltenaliase oder Spaltenpositionen referenzieren. Spaltenpositionen sind ganze Zahlen, die bei 1 beginnen:

      SELECT college, region, seed FROM tournament
        ORDER BY region, seed;

      SELECT college, region AS r, seed AS s FROM tournament
        ORDER BY r, s;

      SELECT college, region, seed FROM tournament
        ORDER BY 2, 3;

  Um in umgekehrter (absteigender) Reihenfolge zu sortieren, fügen Sie in der `ORDER BY`-Klausel das Schlüsselwort `DESC` zum Namen der Spalte zu, nach der die Sortierung erfolgt: Standardmäßig erfolgt die Sortierung aufsteigend. Dies kann mit dem Schlüsselwort `ASC` explizit festgelegt werden.

  Die Verwendung von Spaltenpositionen ist veraltet, weil die Syntax im SQL-Standard nicht mehr vorhanden ist.

- Wenn Sie `GROUP BY` verwenden, werden die Ausgabedatensätze entsprechend den `GROUP BY`-Spalten sortiert, so als ob Sie eine `ORDER BY`-Klausel für dieselben Spalten angegeben hätten. Um eine Mehrbelastung durch das Sortieren mit `GROUP BY` zu vermeiden, fügen Sie `ORDER BY NULL` hinzu:

      SELECT a, COUNT(b) FROM test_table GROUP BY a ORDER BY NULL;

- MySQL erweitert die `GROUP BY`-Klausel dahingehend, dass Sie `ASC` und `DESC` auch nach den in der Klausel benannten Spalten angeben können:

      SELECT a, COUNT(b) FROM test_table GROUP BY a DESC;

- MySQL erweitert die Verwendung von `GROUP BY` so, dass die Auswahl von Feldern möglich ist, die in der `GROUP BY`-Klausel nicht genannt sind. Wenn Sie bei einer Abfrage nicht die erwarteten Ergebnisse erhalten, lesen Sie bitte die Beschreibung von `GROUP BY` in Abschnitt 12.11, „Funktionen und Modifizierer für die Verwendung in `GROUP BY`-Klauseln“.

- `GROUP BY` unterstützt den Modifizierer `WITH ROLLUP`. Siehe auch Abschnitt 12.11.2, „`GROUP BY`-Modifizierer“.

- Die `HAVING`-Klausel wird fast als Letztes angewandt – unmittelbar bevor die Elemente an den Client gesendet werden, und ohne Optimierung. (Nur `LIMIT` wird noch nach `HAVING` angewandt.)

  Der SQL-Standard sieht vor, dass `HAVING` nur Spalten in der `GROUP BY`-Klausel oder solche Spalten referenzieren darf, die in Zusammenfassungsfunktionen verwendet werden. Allerdings unterstützt MySQL eine Erweiterung dieses Verhaltens und gestattet `HAVING` ferner die Referenzierung von Spalten in der `SELECT`-Liste und Spalten in äußeren Unterabfragen.

  Wenn die `HAVING`-Klausel eine Spalte referenziert, die mehrdeutig ist, erscheint eine Warnung. In der folgenden Anweisung ist `col2` mehrdeutig, weil es sowohl als Alias als auch als Spaltenname verwendet wird:

      SELECT COUNT(col1) AS col2 FROM t GROUP BY col2 HAVING col2 = 2;

  Hier wird das SQL-Standardverhalten angewandt, d. h., wenn ein `HAVING`-Spaltenname sowohl in einer `GROUP BY`-Klausel als auch als Spaltenalias in der Liste der Ausgabespalten enthalten ist, hat die Spalte in der `GROUP BY`-Spalte Vorrang.

- Verwenden Sie `HAVING` nicht für Elemente, die in der `WHERE`-Klausel aufgeführt sein sollten. So sollten Sie beispielsweise nicht Folgendes schreiben:

      SELECT col_name FROM tbl_name HAVING col_name > 0;

  Formulieren Sie stattdessen wie folgt:

      SELECT col_name FROM tbl_name WHERE col_name > 0;

- Die `HAVING`-Klausel kann Zusammenfassungsfunktionen referenzieren, was der `WHERE`-Klausel nicht möglich ist:

      SELECT user, MAX(salary) FROM users
        GROUP BY user HAVING MAX(salary) > 10;

  (Dies funktionierte bei einigen älteren MySQL-Versionen nicht.)

- Die `LIMIT`-Klausel kann zur Beschränkung der Anzahl der von der `SELECT`-Anweisung zurückgegebenen Datensätze verwendet werden. `LIMIT` nimmt ein oder zwei numerische Argumente entgegen, die (außer bei Verwendung vorbereiteter Anweisungen) beide nichtnegative Integer-Konstanten sein müssen.

  Von den beiden Argumenten gibt das erste den Versatz des ersten zurückzugebenden Datensatzes an, das zweite die maximale Anzahl zurückzugebender Datensätze. Der Versatz des ersten Datensatzes ist 0 (nicht 1):

      SELECT * FROM tbl LIMIT 5,10;  # Retrieve rows 6-15

  Um alle Datensätze beginnend bei einem bestimmten Versatz bis zum Ende der Ergebnismenge zurückzugeben, können Sie als zweiten Parameter eine sehr große Zahl angeben. Die folgende Anweisung ruft alle Datensätze beginnend beim 96. bis zum letzten Datensatz ab:

      SELECT * FROM tbl LIMIT 95,18446744073709551615;

  Sofern nur ein Argument angegeben ist, gibt der Wert die Anzahl der Datensätze an, die beginnend beim ersten Datensatz zurückgegeben werden sollen:

      SELECT * FROM tbl LIMIT 5;     # Retrieve first 5 rows

  Anders gesagt, ist `LIMIT `row_count`` äquivalent zu `LIMIT 0, `row_count``.

  Bei vorbereiteten Anweisungen können Sie Platzhalter verwenden. Die folgende Anweisung gibt genau einen Datensatz aus der Tabelle `tbl` zurück:

      SET @a=1;
      PREPARE STMT FROM 'SELECT * FROM tbl LIMIT ?';
      EXECUTE STMT USING @a;

  Die folgenden Anweisungen geben den zweiten bis sechsten Datensatz aus der Tabelle `tbl` zurück:

      SET @skip=1; SET @numrows=5;
      PREPARE STMT FROM 'SELECT * FROM tbl LIMIT ?, ?';
      EXECUTE STMT USING @skip, @numrows;

  Aus Gründen der Kompatibilität mit PostgreSQL unterstützt MySQL auch die Syntax `LIMIT `row_count` OFFSET `offset``.

- Die Form `SELECT ... INTO OUTFILE '`file_name`'` der `SELECT`-Anweisung schreibt die ausgewählten Datensätze in eine Datei. Die Datei wird auf dem Serverhost erstellt, d. h., Sie benötigen die Berechtigung `FILE`, um die Syntax verwenden zu können. `file_name` darf keine vorhandene Datei sein, wodurch u. a. verhindert werden soll, dass Dateien wie `/etc/passwd` und Datenbanktabellen zerstört werden.

  Die Anweisung `SELECT ... INTO OUTFILE` ist in erster Linie dazu vorgesehen, eine Tabelle sehr schnell in eine Textdatei auf dem Server zu speichern. Wenn Sie die resultierende Datei auf einem Clienthost statt auf dem Serverhost erstellen wollen, dürfen Sie `SELECT ... INTO OUTFILE` nicht verwenden. In diesem Fall sollten Sie stattdessen einen Befehl wie `mysql -e "SELECT ..." > `file_name`` benutzen, um die Datei auf dem Clienthost anzulegen.

  `SELECT ... INTO OUTFILE` ist das Gegenstück zu `LOAD DATA INFILE`. Die Syntax für den `export_options`-Teil der Anweisung umfasst dieselben `FIELDS`- und `LINES`-Klauseln, die bei `LOAD DATA INFILE` benutzt werden. Siehe auch Abschnitt 13.2.5, „`LOAD DATA INFILE`“.

  `FIELDS ESCAPED BY` steuert, wie Sonderzeichen geschrieben werden. Wenn das `FIELDS ESCAPED BY`-Zeichen nicht leer ist, dann wird es bei der Ausgabe als Präfix für die folgenden Zeichen verwendet:

  - `FIELDS ESCAPED BY`-Zeichen

  - `FIELDS [OPTIONALLY] ENCLOSED BY`-Zeichen

  - das erste Zeichen der Werte `FIELDS TERMINATED BY` und `LINES TERMINATED BY`

  - ASCII `NUL` (das Nullwertbyte; eigentlich wird auf das Escape-Zeichen folgend ASCII ‘`0`’ und kein Nullwertbyte geschrieben)

  Die `FIELDS TERMINATED BY`-, `ENCLOSED BY`-, `ESCAPED BY`- oder `LINES TERMINATED BY`-Zeichen müssen mit Escape-Zeichen gekennzeichnet werden, damit Sie die Datei zuverlässig wiedereinlesen können. ASCII `NUL` wird gekennzeichnet, um das Ablesen bei manchen Pagern zu vereinfachen.

  Die Ergebnisdatei muss nicht der SQL-Syntax entsprechen, weswegen weitere Zeichen nicht gekennzeichnet werden müssen.

  Ist das `FIELDS ESCAPED BY`-Zeichen leer, dann werden keinerlei Zeichen gekennzeichnet und `NULL` wird als `NULL` (und nicht als `\N`) ausgegeben. Es ist wahrscheinlich nicht angeraten, ein leeres Escape-Zeichen anzugeben; dies gilt insbesondere dann, wenn Feldwerte in Ihren Daten eines der in der obigen Liste enthaltenen Zeichen enthalten.

  Es folgt ein Beispiel, das eine Datei im CSV-Format erzeugt, welches von vielen Programmen verwendet wird:

      SELECT a,b,a+b INTO OUTFILE '/tmp/result.txt'
        FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'
        LINES TERMINATED BY '\n'
        FROM test_table;

- Wenn Sie `INTO DUMPFILE` statt `INTO OUTFILE` verwenden, schreibt MySQL nur einen Datensatz ohne Spalten- oder Zeilentrennzeichen und ohne Escape-Kennzeichnung in die Datei. Dies ist praktisch, wenn Sie einen `BLOB`-Wert in die Datei speichern wollen.

- Hinweis: In Dateien, die durch `INTO OUTFILE` oder `INTO DUMPFILE` erstellt wurden, kann von allen Benutzern geschrieben werden. Grund hierfür ist die Tatsache, dass der MySQL Server keine Datei erstellen kann, deren Besitzer jemand anders als der Benutzer ist, unter dessen Konto der Server ausgeführt wird. (Sie sollten aus diesem und anderen Gründen mysqld niemals als `root` ausführen.) Die Datei muss von allen schreibbar sein, damit Sie ihren Inhalt modifizieren können.

- Die Beschreibung der `SELECT`-Syntax am Anfang dieses Abschnitts zeigt die `INTO`-Klausel gegen Ende der Anweisung. `INTO OUTFILE` oder `INTO DUMPFILE` können auch unmittelbar auf die `FROM`-Klausel folgend angegeben werden.

- Eine `PROCEDURE`-Klausel benennt eine Prozedur, die die Daten in der Ergebnismenge verarbeitet. Ein Beispiel finden Sie in Abschnitt 26.4.1, „PROCEDURE ANALYSE“.

- Wenn Sie `FOR UPDATE` mit einer Speicher-Engine verwenden, die Seiten- oder Datensatzsperren verwendet, dann werden die von der Abfrage untersuchten Datensätze bis zum Ende der laufenden Transaktion schreibgesperrt. Mithilfe von `LOCK IN SHARE MODE` wird eine gemeinsame Sperre gesetzt, die anderen Transaktionen das Lesen, nicht jedoch das Ändern oder Löschen der untersuchten Datensätze gestattet. Siehe auch Abschnitt 14.2.10.5, „Lesevorgänge sperren“.

Sie können auf das Schlüsselwort `SELECT` folgend eine Reihe von Optionen angeben, die den Betrieb der Anweisung beeinflusst.

Die Optionen `ALL`, `DISTINCT` und `DISTINCTROW` geben an, ob doppelte Datensätze zurückgegeben werden sollen. Wird keine dieser Optionen angegeben, dann wird `ALL` als Vorgabe vorausgesetzt (d. h., alle passenden Datensätze werden zurückgegeben). `DISTINCT` und `DISTINCTROW` sind Synonyme; sie legen fest, dass doppelte Datensätze aus der Ergebnismenge entfernt werden.

`HIGH_PRIORITY`, `STRAIGHT_JOIN` und Optionen, die mit `SQL_` beginnen, sind MySQL-Erweiterungen zum SQL-Standard.

- `HIGH_PRIORITY` gibt `SELECT` Vorrang vor einer Anweisung, die eine Tabelle aktualisiert. Sie sollten die Option nur bei Abfragen verwenden, die sehr schnell sind und sofort erledigt werden müssen. Eine `SELECT HIGH_PRIORITY`-Anweisung, die abgesetzt wird, während die Tabelle zum Lesen gesperrt ist, wird auch ausgeführt, wenn eine Aktualisierungsanweisung darauf wartet, dass die Tabelle frei wird.

  `HIGH_PRIORITY` kann nicht bei `SELECT`-Anweisungen verwendet werden, die Teil einer Union sind.

- `STRAIGHT_JOIN` zwingt den Optimierer zur Verknüpfung der Tabellen in der Reihenfolge, in der sie in der `FROM`-Klausel angegeben sind. Sie können hiermit eine Abfrage beschleunigen, wenn der Optimierer die Tabellen nicht optimal anordnet. Siehe auch Abschnitt 7.2.1, „`EXPLAIN`-Syntax (Informationen über ein `SELECT` erhalten)“. `STRAIGHT_JOIN` kann auch in der `table_references`-Liste angegeben werden. Siehe auch Abschnitt 13.2.7.1, „`JOIN`“.

- `SQL_BIG_RESULT` kann mit `GROUP BY` oder `DISTINCT` verwendet werden. Sie teilen dem Optimierer hierdurch mit, dass die Ergebnismenge viele Datensätze enthält. In diesem Fall verwendet MySQL bei Bedarf direkt festplattenbasierte Temporärtabellen und zieht die Sortierung der Verwendung einer Temporärtabelle mit einem Schlüssel auf `GROUP BY`-Elemente vor.

- `SQL_BUFFER_RESULT` erzwingt das Ablegen des Ergebnisses in einer Temporärtabelle. Auf diese Weise kann MySQL die Tabellensperren schnell wieder aufheben. Die Option ist zudem in Fällen hilfreich, in denen die Übermittlung des Ergebnisses an den Client sehr lange dauert.

- `SQL_SMALL_RESULT` kann mit `GROUP BY` oder `DISTINCT` verwendet werden. Sie teilen dem Optimierer hierdurch mit, dass die Ergebnismenge klein ist. In diesem Fall verwendet MySQL schnelle Temporärtabellen zur Speicherung der Ergebnistabelle anstelle einer Sortierung. Normalerweise werden Sie diese Option nicht benötigen.

- `SQL_CALC_FOUND_ROWS` weist MySQL an, zu berechnen, wie viele Datensätze ohne Berücksichtigung einer ggf. vorhandenen `LIMIT`-Klausel in der Ergebnismenge enthalten wären. Die Anzahl der Datensätze kann dann mit `SELECT FOUND_ROWS()` abgerufen werden. Siehe auch Abschnitt 12.10.3, „Informationsfunktionen“.

- Mit `SQL_CACHE` weisen Sie MySQL an, das Abfrageergebnis im Abfrage-Cache zu speichern, wenn Sie einen `query_cache_type`-Wert von `2` oder `DEMAND` verwenden. Bei einer Abfrage, die `UNION` oder Unterabfragen verwendet, betrifft diese Option alle `SELECT`-Klauseln in der Abfrage. Siehe auch Abschnitt 5.14, „MySQL-Anfragen-Cache“.

- `SQL_NO_CACHE` weist MySQL an, das Abfrageergebnis nicht im Abfrage-Cache zu speichern. Siehe auch Abschnitt 5.14, „MySQL-Anfragen-Cache“. Bei einer Abfrage, die `UNION` oder Unterabfragen verwendet, betrifft diese Option alle `SELECT`-Klauseln in der Abfrage.

#### 13.2.7.1. `JOIN`

MySQL unterstützt die folgenden `JOIN`-Syntaxen für den `table_references`-Teil von `SELECT`-Anweisungen sowie von `DELETE`- und `UPDATE`-Anweisungen für mehrere Tabellen:

    table_references:
        table_reference [, table_reference] ...

    table_reference:
        table_factor
      | join_table

    table_factor:
        tbl_name [[AS] alias]
            [{USE|IGNORE|FORCE} INDEX (key_list)]
      | ( table_references )
      | { OJ table_reference LEFT OUTER JOIN table_reference
            ON conditional_expr }

    join_table:
        table_reference [INNER | CROSS] JOIN table_factor [join_condition]
      | table_reference STRAIGHT_JOIN table_factor
      | table_reference STRAIGHT_JOIN table_factor ON condition
      | table_reference LEFT [OUTER] JOIN table_reference join_condition
      | table_reference NATURAL [LEFT [OUTER]] JOIN table_factor
      | table_reference RIGHT [OUTER] JOIN table_reference join_condition
      | table_reference NATURAL [RIGHT [OUTER]] JOIN table_factor

    join_condition:
        ON conditional_expr
      | USING (column_list)

Eine Tabellenreferenzierung heißt auch Join-Ausdruck.

Die Syntax von `table_factor` ist im Vergleich zum SQL-Standard erweitert. SQL akzeptiert nur `table_reference`, nicht aber eine in Klammern gesetzte Liste mit Referenzierungen.

Dies ist eine konservative Erweiterung, sofern wir jedes Komma in einer Liste mit `table_reference`-Elementen als äquivalent zu einem inneren Join betrachten. Zum Beispiel:

    SELECT * FROM t1 LEFT JOIN (t2, t3, t4)
                     ON (t2.a=t1.a AND t3.b=t1.b AND t4.c=t1.c)

ist äquivalent mit

    SELECT * FROM t1 LEFT JOIN (t2 CROSS JOIN t3 CROSS JOIN t4)
                     ON (t2.a=t1.a AND t3.b=t1.b AND t4.c=t1.c)

In MySQL ist `CROSS JOIN` syntaktisch ein Äquivalent zu `INNER JOIN` (diese lassen sich gegeneinander austauschen). Nach SQL-Standard hingegen sind beide nicht äquivalent. `INNER JOIN` wird bei einer `ON`-Klausel und `CROSS JOIN` andernfalls verwendet.

Klammern können in Join-Ausdrücken, die nur innere Join-Operationen enthalten, ignoriert werden. MySQL unterstützt auch verschachtelte Joins (siehe auch Abschnitt 7.2.10, „Optimierung verschachtelter Joins“).

Im `ON`-Teil sollten keine Bedingungen vorhanden sein, die zur Beschränkung der Datensätze in der Ergebnismenge verwendet werden; geben Sie solche Bedingungen besser in der `WHERE`-Klausel an. Es gibt aber Ausnahmen zu dieser Regel.

Die oben gezeigte Syntax `{ OJ ... LEFT OUTER JOIN ...}` ist nur aus Gründen der Kompatibilität mit ODBC vorhanden. Die geschweiften Klammern in der Syntax sollten literal notiert werden, sind also keine Metasyntax, wie sie andernorts in Syntaxbeschreibungen verwendet wird.

- Für einen Tabellenverweis kann mit ``tbl_name` AS `alias_name`` oder `tbl_name alias_name` ein Alias erstellt werden:

      SELECT t1.name, t2.salary FROM employee AS t1, info AS t2
        WHERE t1.name = t2.name;

      SELECT t1.name, t2.salary FROM employee t1, info t2
        WHERE t1.name = t2.name;

- Die Bedingungsanweisung `ON` ist ein beliebiger Bedingungsausdruck der Form, die in einer `WHERE`-Klausel verwendet werden kann.

- Ist für die rechte Tabelle im `ON`- oder `USING`-Teil eines `LEFT JOIN` kein passender Datensatz vorhanden, dann wird für die rechte Tabelle ein Datensatz verwendet, bei dem alle Spalten auf `NULL` gesetzt sind. Sie können diesen Umstand nutzen, um Datensätze in einer Tabelle zu finden, die kein Gegenstück in einer anderen Tabelle aufweisen:

      SELECT table1.* FROM table1
        LEFT JOIN table2 ON table1.id=table2.id
        WHERE table2.id IS NULL;

  Dieses Beispiel findet alle Datensätze in `table1` mit einem `id`-Wert, der nicht in `table2` vorhanden ist (d. h. alle Datensätze in `table1` ohne entsprechenden Datensatz in `table2`). Dies setzt voraus, dass `table2.id` als `NOT NULL` deklariert wurde. Siehe auch Abschnitt 7.2.9, „Optimierung von `LEFT JOIN` und `RIGHT JOIN`“.

- Die `USING(`column_list`)`-Klausel benennt eine Liste mit Spalten, die in beiden Tabellen vorhanden sein müssen. Wenn die Tabellen `a` und `b` jeweils die Spalten `c1`, `c2` und `c3` enthalten, dann vergleicht der folgende Join die entsprechenden Spalten der beiden Tabellen:

      a LEFT JOIN b USING (c1,c2,c3)

- Der `NATURAL [LEFT] JOIN` beider Tabellen wird als semantisch äquivalent zu einem `INNER JOIN` oder einem `LEFT JOIN` mit einer `USING`-Klausel definiert, die alle Spalten aufführt, die in beiden Tabellen vorhanden sind.

- `INNER JOIN` und `,` (Komma) sind semantisch gleichwertig, wenn keine Join-Bedingung vorhanden ist: Beide erzeugen ein kartesisches Produkt zwischen den angegebenen Tabellen (d. h., jeder Datensatz in der ersten Tabelle wird mit jedem Datensatz in der zweiten Tabelle verknüpft).

- `RIGHT JOIN` funktioniert analog zu `LEFT JOIN`. Um den Code datenbankübergreifend portierbar zu halten, wird empfohlen, `LEFT JOIN` anstelle von `RIGHT JOIN` zu verwenden.

- `STRAIGHT_JOIN` ist bis auf die Tatsache, dass die linke Tabelle immer vor der rechten gelesen wird, identisch mit `JOIN`. Dies kann für die (wenigen) Fälle genutzt werden, in denen der Join-Optimierer die Tabellen in der falschen Reihenfolge anordnet.

Sie können Hinweise dazu angeben, welchen Index MySQL beim Abrufen von Informationen aus einer Tabelle verwenden soll. Durch Angabe von `USE INDEX (`key_list`)` können Sie MySQL anweisen, nur einen der möglichen Indizes zum Ermitteln von Datensätzen in der Tabelle zu verwenden. Mit der alternativen Syntax `IGNORE INDEX (`key_list`)` können Sie MySQL anweisen, einen bestimmten Index nicht zu verwenden. Solche Hinweise sind nützlich, wenn `EXPLAIN` zeigt, dass MySQL aus einer Liste möglicher Indizes den falschen verwendet.

Sie können auch `FORCE INDEX` verwenden. Diese Option agiert wie `USE INDEX (`key_list`)`, es wird aber zusätzlich vorausgesetzt, dass ein Tabellenscan sehr kostspielig ist. Anders gesagt: Ein Tabellenscan wird nur verwendet, wenn die Datensätze in der Tabelle nicht unter der Verwendung eines der gegebenen Indizes gefunden werden können.

`USE INDEX`, `IGNORE INDEX` und `FORCE INDEX` wirken sich erst darauf aus, welche Indizes verwendet werden, wenn MySQL entschieden hat, wie Datensätze in der Tabelle ermittelt werden und wie der Join durchgeführt wird. Sie haben keine Auswirkungen darauf, ob ein Index benutzt wird, wenn eine `ORDER BY`- oder `GROUP BY`-Klausel aufgelöst wird.

`USE KEY`, `IGNORE KEY` und `FORCE KEY` sind Synonyme von `USE INDEX`, `IGNORE INDEX` und `FORCE INDEX`.

Hier einige Beispiele für Joins:

    SELECT * FROM table1,table2 WHERE table1.id=table2.id;

    SELECT * FROM table1 LEFT JOIN table2 ON table1.id=table2.id;

    SELECT * FROM table1 LEFT JOIN table2 USING (id);

    SELECT * FROM table1 LEFT JOIN table2 ON table1.id=table2.id
      LEFT JOIN table3 ON table2.id=table3.id;

    SELECT * FROM table1 USE INDEX (key1,key2)
      WHERE key1=1 AND key2=2 AND key3=3;

    SELECT * FROM table1 IGNORE INDEX (key3)
      WHERE key1=1 AND key2=2 AND key3=3;

Hinweis: Natürliche Joins und Joins mit `USING` (einschließlich Varianten mit äußeren Joins) werden entsprechend Standard SQL:2003 verarbeitet. Diese Änderungen erhöhen die Kompatibilität von MySQL mit dem SQL-Standard. Allerdings kann es bei manchen Joins zu unterschiedlichen Ausgabespalten kommen. Ferner müssen einige Abfragen, die in älteren Versionen (vor 5.0.12) zu funktionieren schienen, neu geschrieben werden, um dem Standard zu entsprechen. Die folgende Liste enthält weitere Angaben zu verschiedenen Auswirkungen der aktuellen Join-Verarbeitung im Vergleich zur Verarbeitung in älteren Versionen. Der Begriff „älter“ bezeichnet hier Versionen vor MySQL 5.0.12.

- Die Spalten eines `NATURAL`- oder `USING`-Joins können sich von denen älterer Versionen unterscheiden. Insbesondere erscheinen keine redundanten Ausgabespalten mehr, und die Reihenfolge der Spalten für die Erweiterung `SELECT *` kann anders aussehen.

  Beachten Sie die folgenden Anweisungen:

      CREATE TABLE t1 (i INT, j INT);
      CREATE TABLE t2 (k INT, j INT);
      INSERT INTO t1 VALUES(1,1);
      INSERT INTO t2 VALUES(1,1);
      SELECT * FROM t1 NATURAL JOIN t2;
      SELECT * FROM t1 JOIN t2 USING (j);

  In den älteren Versionen erzeugten sie folgende Ausgabe:

      +------+------+------+------+
      | i    | j    | k    | j    |
      +------+------+------+------+
      |    1 |    1 |    1 |    1 |
      +------+------+------+------+
      +------+------+------+------+
      | i    | j    | k    | j    |
      +------+------+------+------+
      |    1 |    1 |    1 |    1 |
      +------+------+------+------+

  In der ersten `SELECT`-Anweisung erscheint Spalte `i` in beiden Tabellen und wird insofern eine Join-Spalte, d. h., sie sollte laut SQL-Standard nur einmal (und nicht zweimal) in der Ausgabe erscheinen. Ähnlich ist die Spalte `j` in der zweiten `SELECT`-Anweisung in der `USING`-Klausel aufgeführt und sollte ebenfalls nur einmal (und nicht zweimal) in der Ausgabe auftauchen. In beiden Fällen wird die redundante Spalte nicht beseitigt. Auch ist die Reihenfolge der Spalten nicht korrekt im Sinne des SQL-Standards.

  Heute erzeugen die Anweisungen folgende Ausgabe:

      +------+------+------+
      | j    | i    | k    |
      +------+------+------+
      |    1 |    1 |    1 |
      +------+------+------+
      +------+------+------+
      | j    | i    | k    |
      +------+------+------+
      |    1 |    1 |    1 |
      +------+------+------+

  Die redundante Spalte ist beseitigt. Auch die Spaltenreihenfolge ist nun korrekt im Sinne des SQL-Standards:

  - Zuerst werden die Spalten, die in beiden Tabellen vorhanden sind, in der Reihenfolge aufgeführt, in der sie in der ersten Tabelle erscheinen.

  - Als Zweites erscheinen Spalten, die nur in der ersten Tabelle vorhanden sind, und zwar in der Reihenfolge, in der sie in der Tabelle erscheinen.

  - Als Drittes erscheinen Spalten, die nur in der zweiten Tabelle vorhanden sind, und zwar in der Reihenfolge, in der sie in der Tabelle erscheinen.

- Die Auswertung eines natürlichen Vielfach-Joins unterscheidet sich auf eine Weise, die ein Neuformulieren von Abfragen erforderlich machen kann. Angenommen, Sie haben drei Tabellen `t1(a,b)`, `t2(c,b)` und `t3(a,c)`, die jeweils einen Datensatz aufweisen: `t1(1,2)`, `t2(10,2)` und `t3(7,10)`. Nehmen wir ferner an, dass Sie folgenden `NATURAL JOIN` auf die drei Tabellen haben:

      SELECT ... FROM t1 NATURAL JOIN t2 NATURAL JOIN t3;

  In älteren Versionen wurde der linke Operand des zweiten Joins als `t2` betrachtet, wohingegen er eigentlich der verschachtelte Join `(t1 NATURAL JOIN t2)` sein sollte. Infolgedessen werden die Spalten von `t3` nur auf gemeinsame Spalten in `t2` geprüft; hat `t3` gemeinsame Spalten mit `t1`, dann werden diese nicht als Equi-Join-Spalten betrachtet. Insofern wurde obige Abfrage bei älteren Versionen in den folgenden Equi-Join transformiert:

      SELECT ... FROM t1, t2, t3
        WHERE t1.b = t2.b AND t2.c = t3.c;

  Diesem Join fehlt aber ein weiteres Equi-Join-Prädikat `(t1.a = t3.a)`. Aufgrund dessen wird als Ergebnis ein Datensatz ausgegeben – und nicht das korrekte leere Ergebnis. Die korrekte äquivalente Abfrage sieht wie folgt aus:

      SELECT ... FROM t1, t2, t3
        WHERE t1.b = t2.b AND t2.c = t3.c AND t1.a = t3.a;

  Wenn Sie in aktuellen MySQL-Versionen dasselbe Abfrageergebnis wie bei den älteren Versionen erhalten, dann formulieren Sie den natürlichen Join als Equi-Join um.

- Früher hatten der Kommaoperator (`,`) und `JOIN` dieselbe Rangstufe, d. h., der Join-Ausdruck `t1, t2 JOIN t3` wurde als `((t1, t2) JOIN t3)` interpretiert. Jetzt hat `JOIN` Vorrang vor dem Komma, d. h., der Ausdruck wird als `(t1, (t2 JOIN t3))` ausgewertet. Diese Änderung betrifft Anweisungen, die eine `ON`-Klausel verwenden, denn diese Klausel kann nur Spalten in den Operanden des Joins referenzieren, und die Änderung in der Rangstufe wirkt sich darauf aus, wie interpretiert wird, was diese Operanden sind.

  Beispiel:

      CREATE TABLE t1 (i1 INT, j1 INT);
      CREATE TABLE t2 (i2 INT, j2 INT);
      CREATE TABLE t3 (i3 INT, j3 INT);
      INSERT INTO t1 VALUES(1,1);
      INSERT INTO t2 VALUES(1,1);
      INSERT INTO t3 VALUES(1,1);
      SELECT * FROM t1, t2 JOIN t3 ON (t1.i1 = t3.i3);

  In älteren Versionen war die `SELECT`-Anweisung aufgrund der impliziten Gruppierung von `t1,t2` als `(t1,t2)` zulässig. Jetzt hat `JOIN` Vorrang, d. h., die Operanden für die `ON`-Klausel sind `t2` und `t3`. Da `t1.i1` keine Spalte in einem der Operanden ist, ist das Ergebnis der Fehler `Unknown column 't1.i1' in 'on clause'`. Um die Verarbeitung des Joins zuzulassen, gruppieren Sie die ersten beiden Tabellen explizit mithilfe von Klammern, sodass die Operanden für die `ON`-Klausel `(t1,t2)` und `t3` sind:

      SELECT * FROM (t1, t2) JOIN t3 ON (t1.i1 = t3.i3);

  Alternativ umgehen Sie die Verwendung des Kommaoperators und verwenden stattdessen `JOIN`:

      SELECT * FROM t1 JOIN t2 JOIN t3 ON (t1.i1 = t3.i3);

  Diese Änderung gilt auch für `INNER JOIN`, `CROSS JOIN`, `LEFT JOIN` und `RIGHT JOIN`: Sie alle haben nun Vorrang vor dem Kommaoperator.

- Früher konnte die `ON`-Klausel Spalten in Tabellen referenzieren, die auf ihrer rechten Seite aufgeführt wurden. Jetzt kann eine `ON`-Klausel nur ihre Operanden referenzieren.

  Beispiel:

      CREATE TABLE t1 (i1 INT);
      CREATE TABLE t2 (i2 INT);
      CREATE TABLE t3 (i3 INT);
      SELECT * FROM t1 JOIN t2 ON (i1 = i3) JOIN t3;

  Früher war diese `SELECT`-Anweisung zulässig. Nun schlägt die Anweisung mit dem Fehler `Unknown column 'i3' in 'on clause'` fehl, weil `i3` eine Spalte in `t3` ist, die kein Operand der `ON`-Klausel ist. Die Anweisung sollte wie folgt umgeschrieben werden:

      SELECT * FROM t1 JOIN t2 JOIN t3 ON (i1 = i3);

- Früher konnte eine `USING`-Klausel als `ON`-Klausel neugeschrieben werden, die die entsprechenden Spalten vergleichen konnte. Die beiden folgenden Klauseln etwa sind semantisch identisch:

      a LEFT JOIN b USING (c1,c2,c3)
      a LEFT JOIN b ON a.c1=b.c1 AND a.c2=b.c2 AND a.c3=b.c3

  Heute haben diese beiden Klauseln nicht mehr dieselbe Bedeutung:

  - Bezüglich der Ermittlung, welche Datensätze die Join-Bedingung erfüllen, bleiben beide Joins semantisch identisch.

  - Allerdings ist diese semantische Identität nicht mehr in Bezug auf die Frage vorhanden, wie die für die `SELECT *`-Erweiterung anzuzeigenden Spalten bestimmt werden. Der `USING`-Join wählt den zusammengefassten Wert der entsprechenden Spalten, während der `ON`-Join alle Spalten aus allen Tabellen auswählt. Bei obigem `USING`-Join wählt `SELECT *` die folgenden Werte aus:

        COALESCE(a.c1,b.c1), COALESCE(a.c2,b.c2), COALESCE(a.c3,b.c3)

    Beim `ON`-Join wählt `SELECT *` die folgenden Werte aus:

        a.c1, a.c2, a.c3, b.c1, b.c2, b.c3

    Bei einem inneren Join ist `COALESCE(a.c1,b.c1)` das Gleiche wie `a.c1` oder `b.c1`, weil beide Spalten denselben Wert haben. Bei einem äußeren Join (wie `LEFT JOIN`) darf eine der beiden Spalten `NULL` sein. Diese Spalte wird im Ergebnis weggelassen.

#### 13.2.7.2. `UNION`

    SELECT ...
    UNION [ALL | DISTINCT] SELECT ...
    [UNION [ALL | DISTINCT] SELECT ...]

`UNION` wird verwendet, um das Ergebnis einer Anzahl von `SELECT`-Anweisungen zu einer Ergebnismenge zusammenzufassen.

Ausgewählte Spalten, die an den entsprechenden Positionen jeder `SELECT`-Anweisung aufgelistet sind, sollten vom selben Typ sein. (So sollte etwa die erste von der ersten Anweisung ausgewählte Spalte denselben Typ haben wie die erste von den anderen Anweisungen gewählte Spalte.) Die in der ersten `SELECT`-Anweisung verwendeten Spaltennamen werden als Spaltennamen für die zurückgegebenen Ergebnisse benutzt.

Die `SELECT`-Anweisungen sind normale Auswahlanweisungen, es gelten jedoch die folgenden Einschränkungen:

- Nur die letzte `SELECT`-Anweisung kann `INTO OUTFILE` verwenden.

- `HIGH_PRIORITY` kann nicht bei `SELECT`-Anweisungen verwendet werden, die Teil einer Union sind. Wenn Sie es für die erste `SELECT`-Anweisung angeben, hat dies keine Auswirkungen. Bei einer Angabe für eine nachfolgende `SELECT`-Anweisung tritt ein Syntaxfehler auf.

Geben Sie das Schlüsselwort `ALL` an, dann enthält das Ergebnis alle passenden Datensätze aus allen `SELECT`-Anweisungen. Wenn Sie `DISTINCT` angeben, werden doppelte Datensätze aus dem Ergebnis entfernt. Wird kein Schlüsselwort benutzt, dann entspricht das Standardverhalten dem von `DISTINCT` (Entfernung doppelter Datensätze).

Das Schlüsselwort `DISTINCT` ist optional ohne Wirkung, ist aber in der Syntax zulässig, da der SQL-Standard dies vorschreibt. (In MySQL stellt `DISTINCT` das Standardverhalten einer Union dar.)

Sie können `UNION ALL` und `UNION DISTINCT` in derselben Abfrage gemeinsam verwenden. Derart gemischte `UNION`-Typen werden dahingehend verarbeitet, dass eine `DISTINCT`-Union Vorrang vor einer `ALL`-Union zu ihrer Linken hat. Eine `DISTINCT`-Union kann explizit mit `UNION DISTINCT` oder implizit durch Verwendung von `UNION` ohne nachfolgende Schlüsselwörter `DISTINCT` oder `ALL` erzeugt werden.

Wenn Sie eine `ORDER BY`- oder `LIMIT`-Klausel zur Sortierung bzw. Beschränkung des gesamten Ergebnisses der Union benutzen wollen, setzen Sie die einzelnen `SELECT`-Anweisungen in Klammern und platzieren Sie die `ORDER BY`- oder `LIMIT`-Klausel an dem Ende. Das folgende Beispiel verwendet beide Klauseln:

    (SELECT a FROM t1 WHERE a=10 AND B=1)
    UNION
    (SELECT a FROM t2 WHERE a=11 AND B=2)
    ORDER BY a LIMIT 10;

Diese Art von `ORDER BY` kann keine Spaltenreferenzierungen verwenden, die einen Tabellennamen enthalten (d. h. Namen im Format `tbl_name`.`col_name`). Geben Sie stattdessen einen Spaltenalias in der ersten `SELECT`-Anweisung an und referenzieren Sie diesen Alias in der `ORDER BY`-Klausel. Alternativ können Sie die Spalten auch in der `ORDER BY`-Klausel unter Angabe ihrer Spaltenposition referenzieren. (Ein Alias ist allerdings vorzuziehen, weil das Angeben von Spaltenpositionen veraltet ist.)

Ferner muss, wenn einer zu sortierenden Spalte ein Alias zugewiesen wird, die `ORDER BY`-Klausel den Alias und nicht den Spaltennamen referenzieren. Die erste der folgenden Anweisungen funktioniert – im Gegensatz zur zweiten, die mit dem Fehler `Unknown column 'a' in 'order clause'` fehlschlägt:

    (SELECT a AS b FROM t) UNION (SELECT ...) ORDER BY b;
    (SELECT a AS b FROM t) UNION (SELECT ...) ORDER BY a;

Um `ORDER BY` oder `LIMIT` auf eine einzelne `SELECT`-Anweisung anzuwenden, setzen Sie die Klausel mit in die Klammern, die die `SELECT`-Anweisung umschließen:

    (SELECT a FROM tbl_name WHERE a=10 AND B=1 ORDER BY a LIMIT 10)
    UNION
    (SELECT a FROM tbl_name WHERE a=11 AND B=2 ORDER BY a LIMIT 10);

Das Einfügen von `ORDER BY` bei einzelnen `SELECT`-Anweisungen in Klammern hat nur in Kombination mit `LIMIT` Auswirkungen. Andernfalls wird `ORDER BY` wegoptimiert.

Typen und Längen der Spalten in der Ergebnismenge einer Union berücksichtigen Werte, die von allen `SELECT`-Anweisungen abgerufen wurden. Betrachten Sie etwa einmal Folgendes:

    mysql> SELECT REPEAT('a',1) UNION SELECT REPEAT('b',10);
    +---------------+
    | REPEAT('a',1) |
    +---------------+
    | a             |
    | bbbbbbbbbb    |
    +---------------+

In einigen früheren Versionen von MySQL würde der zweite Datensatz auf eine Länge von 1 gekürzt.

### 13.2.8. Syntax von Unterabfragen

Eine Unterabfrage ist eine `SELECT`-Anweisung innerhalb einer anderen Anweisung.

Seit MySQL 4.1 werden alle Unterabfrageformen und -operationen, die der SQL-Standard vorsieht, ebenso unterstützt wie einige weitere Funktionen, die MySQL-spezifisch sind.

Hier ein Beispiel für eine Unterabfrage:

    SELECT * FROM t1 WHERE column1 = (SELECT column1 FROM t2);

In diesem Beispiel ist `SELECT * FROM t1 ...` die äußere Abfrage (oder äußere Anweisung), und `(SELECT column1 FROM t2)` ist die Unterabfrage. Man sagt, die Unterabfrage ist in der äußeren Abfrage verschachtelt, und tatsächlich ist es möglich, Unterabfragen bis zu einer beträchtlichen Tiefe zu verschachteln. Eine Unterabfrage muss immer in Klammern stehen.

Unterabfragen haben die folgenden Vorteile:

- Sie gestatten Abfragen, die strukturiert sind. Auf diese Weise ist es möglich, jeden Teil einer Anweisung zu isolieren.

- Sie bieten alternative Wege zur Durchführung von Operationen, die andernfalls komplexe Joins und Unions erfordern würden.

- Sie sind – zumindest nach Meinung vieler – lesbar. Die Unterabfragen waren die eigentliche Innovation, aufgrund derer man auf die Idee kam, SQL seinerzeit als „strukturierte Abfragesprache“ zu bezeichnen.

Hier eine Beispielanweisung, die die wichtigsten Aspekte der Unterabfragensyntax zeigt, wie sie im SQL-Standard spezifiziert ist und von MySQL unterstützt wird:

    DELETE FROM t1
    WHERE s11 > ANY
    (SELECT COUNT(*) /* no hint */ FROM t2
    WHERE NOT EXISTS
    (SELECT * FROM t3
    WHERE ROW(5*t2.s1,77)=
    (SELECT 50,11*s1 FROM t4 UNION SELECT 50,77 FROM
    (SELECT * FROM t5) AS t5)));

Eine Unterabfrage kann einen Skalar (einen einzelnen Wert), einen einzelnen Datensatz, eine einzelne Spalte oder eine Tabelle (d. h. eine oder mehrere Spalten von einem oder mehreren Datensätzen) zurückgeben. Man bezeichnet diese als Skalar-, Spalten-, Datensatz- und Tabellenunterabfragen. Unterabfragen, die einen bestimmten Ergebnistyp zurückgeben, können häufig nur in bestimmten Kontexten verwendet werden, die in den folgenden Abschnitten beschrieben werden.

Es gibt ein paar wenige Einschränkungen bezüglich des Typs der Anweisungen, in denen Unterabfragen verwendet werden können. Eine Unterabfrage kann die gleichen Schlüsselwörter oder Klauseln enthalten wie eine gewöhnliche `SELECT`-Anweisung: `DISTINCT`, `GROUP BY`, `ORDER BY`, `LIMIT`, Joins, Indexhinweise, `UNION`-Konstrukte, Kommentare, Funktionen usw.

Eine Einschränkung besteht darin, dass die äußere Anweisung einer Unterabfrage einen der folgenden Typen aufweisen muss: `SELECT`, `INSERT`, `UPDATE`, `DELETE`, `SET` oder `DO`. Eine weitere Einschränkung ist die Tatsache, dass Sie eine Tabelle derzeit nicht ändern und gleichzeitig in einer Unterabfrage eine Auswahl aus dieser Tabelle treffen können. Dies gilt für Anweisungen wie `DELETE`, `INSERT`, `REPLACE`, `UPDATE` und (da Unterabfragen in der `SET`-Klausel verwendet werden können) `LOAD DATA INFILE`. Eine umfassendere Beschreibung der Einschränkungen bei Unterabfragen finden Sie in Abschnitt I.3, „Beschränkungen von Unterabfragen“.

#### 13.2.8.1. Die Unterabfrage als skalarer Operand

In ihrer einfachsten Form ist eine Unterabfrage eine Skalarunterabfrage, die einen Einzelwert zurückgibt. Eine Skalarunterabfrage ist ein einfacher Operand, und Sie können sie fast überall dort benutzen, wo ein einzelner Spaltenwert oder ein Literal zulässig ist. Sie können dabei voraussetzen, dass eine solche Unterabfrage die Eigenschaften aufweist, die alle Operanden haben: einen Datentyp, eine Länge, eine Angabe dazu, ob sie `NULL` sein darf oder nicht usw. Zum Beispiel:

    CREATE TABLE t1 (s1 INT, s2 CHAR(5) NOT NULL);
    INSERT INTO t1 VALUES(100, 'abcde');
    SELECT (SELECT s2 FROM t1);

Die Unterabfrage in dieser `SELECT`-Anweisung gibt einen einzelnen Wert (`'abcde'`) zurück, der den Datentyp `CHAR` und die Länge 5 aufweist, Zeichensatz und Sortierfolge den mit `CREATE TABLE` konfigurierten Vorgaben entnimmt und die Information enthält, dass der Wert in der Spalte auch `NULL` sein kann. Tatsächlich können fast alle Unterabfragen `NULL` werden. Wäre die im Beispiel verwendete Tabelle leer, dann wäre der Wert der Unterabfrage `NULL`.

Es gibt nur ganz wenig Kontexte, in denen eine skalare Unterabfrage nicht verwendet werden kann. Wenn eine Anweisung nur einen literalen Wert zulässt, können Sie keine Unterabfrage einsetzen. So erfordert beispielsweise `LIMIT` literale Integer-Argumente, und `LOAD DATA INFILE` verlangt einen literalen String für den Dateinamen. Zur Übermittlung solcher Werte können Sie Unterabfragen nicht benutzen.

Wenn die Beispiele in den folgenden Abschnitten das recht spartanische Konstrukt `(SELECT column1 FROM t1)` enthalten, dann vergegenwärtigen Sie sich, dass Ihr eigener Code wesentlich komplexere und unterschiedlichere Konstruktionen enthalten kann (und wird).

Nehmen wir an, wir erstellen zwei Tabellen:

    CREATE TABLE t1 (s1 INT);
    INSERT INTO t1 VALUES (1);
    CREATE TABLE t2 (s1 INT);
    INSERT INTO t2 VALUES (2);

Nun führen Sie eine `SELECT`-Anweisung aus:

    SELECT (SELECT s1 FROM t2) FROM t1;

Das Ergebnis ist `2`, weil in Tabelle `t2` eine Spalte `s1` vorhanden ist, die den Wert `2` hat.

Eine skalare Unterabfrage kann Teil eines Ausdrucks sein. Denken Sie aber immer an die Klammern – auch dann, wenn die Unterabfrage ein Operand ist, der ein Argument für eine Funktion bereitstellt. Zum Beispiel:

    SELECT UPPER((SELECT s1 FROM t1)) FROM t2;

#### 13.2.8.2. Vergleiche mit Unterabfragen

Die häufigste Form einer Unterabfrage hat das folgende Aussehen:

    non_subquery_operand comparison_operator (subquery)

Hierbei ist `comparison_operator` einer der folgenden Operatoren:

    =  >  <  >=  <=  <>

Zum Beispiel:

      ... 'a' = (SELECT column1 FROM t1)

Früher befand sich der einzige zulässige Ort für eine Unterabfrage auf der rechten Seite eines Vergleichs; einige wenige alte Datenbanksysteme halten nach wie vor an dieser Regel fest.

Hier ein Beispiel für einen Unterabfragenvergleich in der gängigen Form, den Sie mit einem Join nicht durchführen können. Hierbei werden alle Werte in Tabelle `t1` gefunden, die einem Maximalwert in Tabelle `t2` entsprechen:

    SELECT column1 FROM t1
    WHERE column1 = (SELECT MAX(column2) FROM t2);

Es folgt ein weiteres Beispiel, welches ebenfalls mit einem Join nicht zu realisieren ist, da für eine der Tabellen eine Zusammenfassung erfolgt. Gefunden werden hier alle Datensätze in der Tabelle `t1`, die einen Wert enthalten, der in einer gegebenen Spalte zweimal auftritt:

    SELECT * FROM t1 AS t
    WHERE 2 = (SELECT COUNT(*) FROM t1 WHERE t1.id = t.id);

Bei einem Vergleich, der mit einem dieser Operatoren durchgeführt wird, muss die Unterabfrage einen Skalar zurückgeben. Eine Ausnahme besteht lediglich darin, dass `=` mit Datensatzunterabfragen verwendet werden kann. Siehe auch Abschnitt 13.2.8.5, „Zeilenunterabfragen“.

#### 13.2.8.3. Unterabfragen mit `ANY`, `IN` und `SOME`

Syntax:

    operand comparison_operator ANY (subquery)
    operand IN (subquery)
    operand comparison_operator SOME (subquery)

Das Schlüsselwort `ANY`, das einem Vergleichsoperator folgen muss, bedeutet „Gib `TRUE` zurück, wenn der Vergleich für jeden beliebigen Wert in der Spalte, die die Unterabfrage zurückgibt, wahr ist“. Zum Beispiel:

    SELECT s1 FROM t1 WHERE s1 > ANY (SELECT s1 FROM t2);

Nehmen wir an, dass die Tabelle `t1` einen Datensatz mit dem Inhalt `(10)` umfasst. Der Ausdruck ist wahr, wenn Tabelle `t2` `(21,14,7)` enthält, weil ein Wert `7` in `t2` vorhanden ist, der kleiner als `10` ist. Der Ausdruck ist hingegen falsch, wenn Tabelle `t2` `(20,10)` enthält oder leer ist. Der Ausdruck ist schließlich unbekannt (`UNKNOWN`), wenn Tabelle `t2` `(NULL,NULL,NULL)` enthält.

Das Wort `IN` ist ein Alias für `= ANY`. Insofern sind die folgenden beiden Anweisungen gleichwertig:

    SELECT s1 FROM t1 WHERE s1 = ANY (SELECT s1 FROM t2);
    SELECT s1 FROM t1 WHERE s1 IN    (SELECT s1 FROM t2);

Allerdings ist `NOT IN` kein Alias für `<> ANY`, wohl aber für `<> ALL`. Siehe auch Abschnitt 13.2.8.4, „Unterabfragen mit `ALL`“.

Das Wort `SOME` ist ein Alias für `ANY`. Insofern sind die folgenden beiden Anweisungen gleichwertig:

    SELECT s1 FROM t1 WHERE s1 <> ANY  (SELECT s1 FROM t2);
    SELECT s1 FROM t1 WHERE s1 <> SOME (SELECT s1 FROM t2);

Das Wort `SOME` wird zwar nur selten verwendet, dieses Beispiel zeigt aber, wofür es nützlich sein kann. Die meisten Menschen fassen die Phrase „a ist nicht gleich irgendeinem b“ als „Es gibt kein b, welches gleich a ist“ auf, aber das ist bei der SQL-Syntax nicht gemeint. Hier bedeutet dies vielmehr „Es gibt (mindestens) ein b, dem a nicht gleich ist“. Indem Sie stattdessen `<> SOME` verwenden, gewährleisten Sie, dass jeder die tatsächliche Meinung der Abfrage versteht.

#### 13.2.8.4. Unterabfragen mit `ALL`

Syntax:

    operand comparison_operator ALL (subquery)

Das Wort `ALL`, das einem Vergleichsoperator folgen muss, bedeutet „Gib `TRUE` zurück, wenn der Vergleich für jeden beliebigen Wert in der Spalte, die die Unterabfrage zurückgibt, wahr ist“. Zum Beispiel:

    SELECT s1 FROM t1 WHERE s1 > ALL (SELECT s1 FROM t2);

Nehmen wir an, dass die Tabelle `t1` einen Datensatz mit dem Inhalt `(10)` umfasst. Der Ausdruck ist wahr, wenn Tabelle `t2` `(-5,0,+5)` enthält, weil `10` größer als alle drei Werte in `t2` ist. Der Ausdruck ist hingegen falsch, wenn Tabelle `t2` `(12,6,NULL,-100)` enthält, weil es einen Wert (`12`) in Tabelle `t2` gibt, der größer als `10` ist. Der Ausdruck ist unbekannt (d. h. `NULL`), wenn Tabelle `t2` `(0,NULL,1)` enthält.

Schließlich ist, wenn Tabelle `t2` leer ist, das Ergebnis wahr. Aufgrund dessen ist die folgende Anweisung wahr, wenn Tabelle `t2` leer ist:

    SELECT * FROM t1 WHERE 1 > ALL (SELECT s1 FROM t2);

Folgende Anweisung ist hingegen `NULL`, wenn Tabelle `t2` leer ist:

    SELECT * FROM t1 WHERE 1 > (SELECT s1 FROM t2);

Ferner ist auch folgende Anweisung `NULL`, wenn Tabelle `t2` leer ist:

    SELECT * FROM t1 WHERE 1 > ALL (SELECT MAX(s1) FROM t2);

Generell sind Tabellen, die `NULL`-Werte enthalten, und leere Tabellen Grenzfälle. Wenn Sie Unterabfragencode formulieren, vergewissern Sie sich immer, dass Sie diese beiden Fälle berücksichtigt haben.

`NOT IN` ist ein Alias für `<> ALL`. Insofern sind die folgenden beiden Anweisungen gleichwertig:

    SELECT s1 FROM t1 WHERE s1 <> ALL (SELECT s1 FROM t2);
    SELECT s1 FROM t1 WHERE s1 NOT IN (SELECT s1 FROM t2);

#### 13.2.8.5. Zeilenunterabfragen

Bis zu diesem Punkt haben wir ausschließlich Skalar- und Spaltenunterabfragen beschrieben, also Unterabfragen, die einen einzelnen Wert oder eine Wertespalte zurückgeben. Eine Datensatzunterabfrage ist eine Unterabfragenvariante, die einen einzelnen Datensatz zurückgibt – und insofern auch mehrere Spaltenwerte zurückgeben kann. Hier zwei Beispiele:

    SELECT * FROM t1 WHERE (1,2) = (SELECT column1, column2 FROM t2);
    SELECT * FROM t1 WHERE ROW(1,2) = (SELECT column1, column2 FROM t2);

Die gezeigten Abfragen sind beide wahr, wenn Tabelle `t2` einen Datensatz enthält, bei dem `column1 = 1` und `column2 = 2` sind.

Die Ausdrücke `(1,2)` und `ROW(1,2)` heißen manchmal auch Datensatzkonstruktoren. Beide sind äquivalent. Sie sind zudem auch in anderen Kontexten zulässig. So sind etwa die beiden folgenden Anweisungen semantisch äquivalent (obwohl derzeit nur die zweite optimiert werden kann):

      SELECT * FROM t1 WHERE (column1,column2) = (1,1);
      SELECT * FROM t1 WHERE column1 = 1 AND column2 = 1;

Der normale Anwendungsfall von Datensatzkonstruktoren sind Vergleiche mit Unterabfragen, die zwei oder mehr Spalten zurückgeben. So entspricht die folgende Abfrage der Aufforderung „Suche alle Datensätze in Tabelle `t1`, die auch in Tabelle `t2` vorhanden sind“:

    SELECT column1,column2,column3
    FROM t1
    WHERE (column1,column2,column3) IN
    (SELECT column1,column2,column3 FROM t2);

#### 13.2.8.6. `EXISTS` und `NOT EXISTS`

Wenn eine Unterabfrage irgendwelche Datensätze zurückgibt, ist `EXISTS `subquery`` wahr und `NOT EXISTS `subquery`` ist falsch. Zum Beispiel:

    SELECT column1 FROM t1 WHERE EXISTS (SELECT * FROM t2);

Traditionell beginnt eine `EXISTS`-Unterabfrage mit `SELECT *`, sie könnte aber auch mit `SELECT 5` oder `SELECT column1` oder etwas ganz anderem anfangen: MySQL ignoriert die `SELECT`-Liste in einer solchen Unterabfrage, mithin macht es keinen Unterschied.

Bei obigem Beispiel ist die Bedingung wahr, wenn `t2` überhaupt Datensätze enthält (und sogar dann, wenn es sich ausschließlich um `NULL`-Werte handelt). Dies ist aber ein recht abwegiges Beispiel, weil eine `[NOT] EXISTS`-Unterabfrage fast immer Korrelationen enthält. Hier einige pragmatischere Beispiele:

- Welche Arten von Geschäften sind in einer oder mehreren Städten vorhanden?

      SELECT DISTINCT store_type FROM stores
        WHERE EXISTS (SELECT * FROM cities_stores
                      WHERE cities_stores.store_type = stores.store_type);

- Welche Art von Geschäften ist in keiner Stadt vorhanden?

      SELECT DISTINCT store_type FROM stores
        WHERE NOT EXISTS (SELECT * FROM cities_stores
                          WHERE cities_stores.store_type = stores.store_type);

- Welche Art von Geschäften ist in allen Städten vorhanden?

      SELECT DISTINCT store_type FROM stores s1
        WHERE NOT EXISTS (
          SELECT * FROM cities WHERE NOT EXISTS (
            SELECT * FROM cities_stores
             WHERE cities_stores.city = cities.city
             AND cities_stores.store_type = stores.store_type));

Das letzte Beispiel ist eine doppelt verschachtelte `NOT EXISTS`-Abfrage: Sie enthält eine `NOT EXISTS`-Klausel in einer `NOT EXISTS`-Klausel. Formell beantwortet sie die Frage „Gibt es eine Stadt mit einem Geschäft, das nicht in `Stores` vorhanden ist?“. Aber es ist einfacher zu sagen, dass eine verschachtelte `NOT EXISTS`-Klausel die Frage „Ist `x` für alle `y` wahr?“ beantwortet.

#### 13.2.8.7. Korrelierte Unterabfragen

Eine korrelierte Unterabfrage ist eine Unterabfrage, die eine Tabelle referenziert, die auch in der äußeren Abfrage erscheint. Zum Beispiel:

    SELECT * FROM t1 WHERE column1 = ANY
    (SELECT column1 FROM t2 WHERE t2.column2 = t1.column2);

Beachten Sie, dass die Unterabfrage eine Spalte von `t1` referenziert, obwohl die `FROM`-Klausel der Unterabfrage keine Tabelle `t1` erwählt. Also sucht MySQL außerhalb der Unterabfrage und findet `t1` in der äußeren Abfrage.

Angenommen, Tabelle `t1` enthielte einen Datensatz, bei dem `column1 = 5` und `column2 = 6` sind. Gleichzeitig enthält Tabelle `t2` einen Datensatz, bei dem `column1 = 5` und `column2 = 7` sind. Der einfache Ausdruck `... WHERE column1 = ANY (SELECT column1 FROM t2)` wäre wahr, aber in diesem Beispiel ist die `WHERE`-Klausel innerhalb der Unterabfrage falsch (weil nämlich `(5,6)` nicht gleich `(5,7)`); also ist auch die Unterabfrage als Ganzes falsch.

Bereichsregel: MySQL wertet von innen nach außen aus. Zum Beispiel:

    SELECT column1 FROM t1 AS x
    WHERE x.column1 = (SELECT column1 FROM t2 AS x
    WHERE x.column1 = (SELECT column1 FROM t3
    WHERE x.column2 = t3.column1));

In dieser Anweisung muss `x.column2` eine Spalte in der Tabelle `t2` sein, weil `SELECT column1 FROM t2 AS x ...` `t2` umbenennt. Es ist keine Spalte in Tabelle `t1`, weil `SELECT column1 FROM t1 ...` eine äußere Abfrage ist, die weiter außen ist.

Bei Unterabfragen in `HAVING`- oder `ORDER BY`-Klauseln sucht MySQL auch nach Spaltennamen in der äußeren Auswahlliste.

In bestimmten Fällen wird eine korrelierte Unterabfrage optimiert. Zum Beispiel:

    val IN (SELECT key_val FROM tbl_name WHERE correlated_condition)

Andernfalls sind sie ineffizient und zudem wahrscheinlich recht langsam. Das Umschreiben der Abfrage als Join kann die Leistung unter Umständen verbessern.

Korrelierte Unterabfragen können Ergebnisse von Zusammenfassungsfunktionen in der äußeren Abfrage nicht referenzieren.

#### 13.2.8.8. Unterabfragen in der `FROM`-Klausel

Unterabfragen sind in der `FROM`-Klausel einer `SELECT`-Anweisung zulässig. Die eigentliche Syntax lautet:

    SELECT ... FROM (subquery) [AS] name ...

Die `[AS] `name``-Klausel ist obligatorisch, weil jede Tabelle in einer `FROM`-Klausel einen Namen haben muss. Alle Spalten, die in der `subquery`-Auswahlliste aufgeführt sind, benötigen eindeutige Namen. Sie finden diese Syntax an anderer Stelle in diesem Handbuch beschrieben. Dort wird der Begriff „abgeleitete Tabellen“ verwendet.

Zur Veranschaulichung nehmen wir an, dass Sie folgende Tabelle haben:

    CREATE TABLE t1 (s1 INT, s2 CHAR(5), s3 FLOAT);

Eine Unterabfrage in der `FROM`-Klausel verwenden Sie bei der Beispieltabelle wie folgt:

    INSERT INTO t1 VALUES (1,'1',1.0);
    INSERT INTO t1 VALUES (2,'2',2.0);
    SELECT sb1,sb2,sb3
    FROM (SELECT s1 AS sb1, s2 AS sb2, s3*2 AS sb3 FROM t1) AS sb
    WHERE sb1 > 1;

Ergebnis: `2, '2', 4.0`.

Es folgt ein weiteres Beispiel: Nehmen wir an, Sie wollen den Durchschnitt einer Anzahl von Summen für eine gruppierte Tabelle ermitteln. Folgendes funktioniert nicht:

    SELECT AVG(SUM(column1)) FROM t1 GROUP BY column1;

Die nächste Abfrage dagegen übermittelt die gewünschte Information:

    SELECT AVG(sum_column1)
    FROM (SELECT SUM(column1) AS sum_column1
    FROM t1 GROUP BY column1) AS t1;

Beachten Sie, dass der Spaltenname, der in der Unterabfrage verwendet wird (`sum_column1`), in der äußeren Abfrage erkannt wird.

Unterabfragen in der `FROM`-Klausel können einen Skalar, eine Spalte, einen Datensatz oder eine Tabelle zurückgeben. Unterabfragen in der `FROM`-Klausel dürfen keine korrelierten Unterabfragen sein.

Unterabfragen in der `FROM`-Klausel werden auch für die `EXPLAIN`-Anweisung ausgeführt (d. h., es werden abgeleitete Temporärtabellen erstellt). Grund hierfür ist, dass Abfragen höherer Ebenen während der Optimierungsphase Informationen zu allen Tabellen benötigen.

#### 13.2.8.9. Fehler bei Unterabfragen

Es gibt eine Reihe von Fehlern, die sich nur auf Unterabfragen beziehen. Sie werden in diesem Abschnitt beschrieben.

- Falsche Anzahl von Spalten aus der Unterabfrage:

      ERROR 1241 (ER_OPERAND_COL)
      SQLSTATE = 21000
      Message = "Operand should contain 1 column(s)"

  Dieser Fehler tritt in Fällen wie dem folgenden auf:

      SELECT (SELECT column1, column2 FROM t2) FROM t1;

  Sie können eine Unterabfrage verwenden, die mehrere Spalten zurückgibt, sofern das Ziel ein Vergleich ist. Siehe auch Abschnitt 13.2.8.5, „Zeilenunterabfragen“. Allerdings muss die Unterabfrage in anderen Kontexten ein skalarer Operand sein.

- Falsche Anzahl von Datensätzen aus der Unterabfrage:

      ERROR 1242 (ER_SUBSELECT_NO_1_ROW)
      SQLSTATE = 21000
      Message = "Subquery returns more than 1 row"

  Dieser Fehler tritt bei Anweisungen auf, bei denen die Unterabfrage mehr als einen Datensatz zurückgibt. Betrachten Sie einmal das folgende Beispiel:

      SELECT * FROM t1 WHERE column1 = (SELECT column1 FROM t2);

  Wenn `SELECT column1 FROM t2` nur einen Datensatz zurückgibt, funktioniert obige Abfrage. Gibt die Abfrage jedoch mehrere Datensätze zurück, dann tritt der Fehler 1242 auf. In diesem Fall sollten Sie die Abfrage wie folgt neu formulieren:

      SELECT * FROM t1 WHERE column1 = ANY (SELECT column1 FROM t2);

- Falsch verwendete Tabelle in der Unterabfrage:

      Error 1093 (ER_UPDATE_TABLE_USED)
      SQLSTATE = HY000
      Message = "You can't specify target table 'x'
      for update in FROM clause"

  Dieser Fehler tritt in Fällen wie dem folgenden auf:

      UPDATE t1 SET column2 = (SELECT MAX(column1) FROM t1);

  Sie können eine Unterabfrage zur Zuweisung innerhalb einer `UPDATE`-Anweisung verwenden, da Unterabfragen in `UPDATE`- und `DELETE`-Anweisungen ebenso zulässig sind wie in `SELECT`-Anweisungen. Allerdings können Sie nicht dieselbe Tabelle (in diesem Fall Tabelle `t1`) sowohl in der `FROM`-Klausel der Unterabfrage als auch als Aktualisierungsziel angeben.

Bei transaktionssicheren Speicher-Engines schlägt bei einem Fehlschlag einer Unterabfrage die gesamte Anweisung fehl. Bei nichttransaktionssicheren Speicher-Engines bleiben Datenänderungen, die vor Auftreten des Fehlers durchgeführt wurden, erhalten.

#### 13.2.8.10. Optimierung von Unterabfragen

Die Entwicklung erfolgt kontinuierlich, d. h., Optimierungstipps sind niemals auf Dauer gültig. Die folgende Liste zeigt einige interessante Tricks, mit denen Sie ein wenig herumprobieren können:

- Verwendung von Klauseln in Unterabfragen, die die Anzahl oder Reihenfolge der Datensätze in der Unterabfrage betreffen. Zum Beispiel:

      SELECT * FROM t1 WHERE t1.column1 IN
      (SELECT column1 FROM t2 ORDER BY column1);
      SELECT * FROM t1 WHERE t1.column1 IN
      (SELECT DISTINCT column1 FROM t2);
      SELECT * FROM t1 WHERE EXISTS
      (SELECT * FROM t2 LIMIT 1);

- Ersetzen Sie einen Join durch eine Unterabfrage. Probieren Sie z. B. Folgendes aus.

      SELECT DISTINCT column1 FROM t1 WHERE t1.column1 IN (
      SELECT column1 FROM t2);

  So hätte dies ursprünglich ausgesehen:

      SELECT DISTINCT t1.column1 FROM t1, t2
      WHERE t1.column1 = t2.column1;

- Einige Unterabfragen können aus Gründen der Kompatibilität mit älteren MySQL-Versionen, die Unterabfragen nicht unterstützen, in Joins umgewandelt werden. Allerdings wird hierdurch in einigen Fällen die Leistungsfähigkeit beeinträchtigt. Siehe auch Abschnitt 13.2.8.11, „Umschreiben von Unterabfragen in Joins für frühere MySQL-Versionen“.

- Verschieben Sie Klauseln von außen in die Unterabfrage. Verwenden Sie beispielsweise diese Abfrage …

      SELECT * FROM t1
      WHERE s1 IN (SELECT s1 FROM t1 UNION ALL SELECT s1 FROM t2);

  … statt dieser:

      SELECT * FROM t1
      WHERE s1 IN (SELECT s1 FROM t1) OR s1 IN (SELECT s1 FROM t2);

  Ein weiteres Beispiel: Verwenden Sie diese Abfrage …

      SELECT (SELECT column1 + 5 FROM t1) FROM t2;

  … statt dieser:

      SELECT (SELECT column1 FROM t1) + 5 FROM t2;

- Verwenden Sie eine Datensatzunterabfrage statt einer korrelierten Unterabfrage. Verwenden Sie beispielsweise diese Abfrage …

      SELECT * FROM t1
      WHERE (column1,column2) IN (SELECT column1,column2 FROM t2);

  … statt dieser:

      SELECT * FROM t1
      WHERE EXISTS (SELECT * FROM t2 WHERE t2.column1=t1.column1
      AND t2.column2=t1.column2);

- Verwenden Sie `NOT (a = ANY (...))` statt `a <> ALL (...)`.

- Verwenden Sie `x = ANY (`table containing (1,2)`)` statt `x=1 OR x=2`.

- Verwenden Sie `= ANY` statt `EXISTS`.

- Bei unkorrelierten Unterabfragen, die immer genau einen Datensatz zurückgeben, ist `IN` immer langsamer als `=`. Verwenden Sie beispielsweise diese Abfrage …

      SELECT * FROM t1 WHERE t1.col_name
      = (SELECT a FROM t2 WHERE b = some_const);

  … statt dieser:

      SELECT * FROM t1 WHERE t1.col_name
      IN (SELECT a FROM t2 WHERE b = some_const);

Aufgrund dieser Tricks können Programme schneller, aber auch langsamer werden. Mithilfe von MySQL-Funktionen wie `BENCHMARK()` können Sie überprüfen, was in Ihrer speziellen Situation hilfreich sein kann. Siehe auch Abschnitt 12.10.3, „Informationsfunktionen“.

Die folgenden Optimierungen nimmt MySQL selbst vor:

- MySQL führt nichtkorrelierte Unterabfragen nur einmal aus. Mit `EXPLAIN` können Sie sicherstellen, dass eine gegebene Unterabfrage wirklich nichtkorreliert ist.

- MySQL schreibt `IN`-, `ALL`-, `ANY`- und `SOME`-Unterabfragen neu, um möglichst davon zu profitieren, dass die Auswahllistenspalten in der Unterabfrage indiziert sind.

- MySQL ersetzt Unterabfragen der folgenden Form durch eine Indexsuchfunktion, die `EXPLAIN` als speziellen Join-Typ beschreibt (`unique_subquery` oder `index_subquery`):

      ... IN (SELECT indexed_column FROM single_table ...)

- MySQL erweitert Ausdrücke der folgenden Form mit einem Ausdruck mit `MIN()` oder `MAX()`, sofern `NULL`-Werte oder Leermengen vorhanden sind:

      value {ALL|ANY|SOME} {> | < | >= | <=} (non-correlated subquery)

  Betrachten Sie etwa folgende `WHERE`-Klausel:

      WHERE 5 > ALL (SELECT x FROM t)

  Diese könnte vom Optimierer wie folgt geändert werden:

      WHERE 5 > (SELECT MAX(x) FROM t)

Es gibt ein Kapitel „How MySQL Transforms Subqueries“ („Wie MySQL Unterabfragen transformiert“) im Handbuch „MySQL Internals“ (MySQL-Interna, derzeit nur auf Englisch verfügbar), welches Sie unter http://dev.mysql.com/doc/ erhalten.

#### 13.2.8.11. Umschreiben von Unterabfragen in Joins für frühere MySQL-Versionen

Bei älteren MySQL-Versionen (vor Version 4.1) wurden nur verschachtelte Abfragen der Formen `INSERT ... SELECT ...` und `REPLACE ... SELECT ...` unterstützt. Zwar trifft dies bei MySQL 5.1 nicht mehr zu, aber nach wie vor werden gelegentlich andere Möglichkeiten eingesetzt, um auf Mitgliedschaft in einer Wertemenge zu prüfen. Außerdem ist es unter bestimmten Umständen nicht nur möglich, eine Abfrage ohne Unterabfrage zu schreiben, sondern es kann auch effizienter sein, einige der folgenden Methoden zu verwenden, statt Unterabfragen einzusetzen. Eine dieser Methode ist das Konstrukt `IN()`:

Betrachten Sie etwa folgende Abfrage:

    SELECT * FROM t1 WHERE id IN (SELECT id FROM t2);

Sie kann wie folgt umgeschrieben werden:

    SELECT DISTINCT t1.* FROM t1, t2 WHERE t1.id=t2.id;

Ein anderes Beispiel sind folgende Abfragen:

    SELECT * FROM t1 WHERE id NOT IN (SELECT id FROM t2);
    SELECT * FROM t1 WHERE NOT EXISTS (SELECT id FROM t2 WHERE t1.id=t2.id);

Auch sie lassen sich mithilfe von `IN()` umschreiben:

    SELECT table1.* FROM table1 LEFT JOIN table2 ON table1.id=table2.id
    WHERE table2.id IS NULL;

Ein `LEFT [OUTER] JOIN` kann schneller sein als die äquivalente Unterabfrage, weil der Server unter Umständen in der Lage ist, ihn besser zu optimieren – eine Tatsache, die nicht nur für den MySQL Server gilt. Vor SQL-92 waren äußere Joins nicht vorhanden, d. h., Unterabfragen stellten für bestimmte Aufgaben die einzige Lösung dar. Heute bieten MySQL Server und viele andere moderne Datenbanksysteme eine Vielzahl von Typen für äußere Joins.

MySQL Server unterstützt `DELETE`-Anweisungen über mehrere Tabellen, die zur effizienten gleichzeitigen Löschung von Datensätzen basierend auf Daten in einer Tabelle (oder sogar mehreren Tabellen) benutzt werden. Auch `UPDATE`-Anweisungen über mehrere Tabellen werden unterstützt.

### 13.2.9. `TRUNCATE`

    TRUNCATE [TABLE] tbl_name

`TRUNCATE TABLE` leert eine Tabelle vollständig. Logisch gesehen ist dies äquivalent zu einer `DELETE`-Anweisung, die alle Datensätze löscht, aber es gibt unter bestimmten Umständen praktische Unterschiede.

Bei `InnoDB`-Tabellen wird `TRUNCATE TABLE` auf `DELETE` umgesetzt, sofern keine Fremdschlüssel-Constraints vorhanden sind, die die Tabelle referenzieren; andernfalls wird das schnelle Leeren (durch Löschen und Neuerstellen der Tabelle) verwendet. Der `AUTO_INCREMENT`-Zähler wird von `TRUNCATE TABLE` unabhängig vom Vorhandensein eines Fremdschlüssel-Constraints zurückgesetzt.

Bei anderen Speicher-Engines unterscheidet sich `TRUNCATE TABLE` in MySQL 5.1 wie folgt von `DELETE`:

- Leerungsoperationen löschen die Tabelle und erstellen sie dann neu, was wesentlich schneller ist als das aufeinander folgende Löschen aller Datensätze.

- Leerungsoperationen sind nicht transaktionssicher: Wenn Sie eine solche Operation während einer aktiven Transaktion oder einer aktiven Tabellensperrung durchführen wollen, tritt ein Fehler auf.

- Die Anzahl gelöschter Datensätze wird nicht zurückgegeben.

- Solange die Tabellenformatdatei ``tbl_name`.frm` gültig ist, lässt sich die Tabelle mit `TRUNCATE TABLE` auch dann als leere Tabelle neu erstellen, wenn die Daten- oder Indexdateien beschädigt wurden.

- Der Tabellen-Handler speichert den zuletzt verwendeten `AUTO_INCREMENT`-Wert nicht, sondern fängt mit der Zählung von vorne an. Dies gilt auch für `MyISAM`- und `InnoDB`-Tabellen, die Sequenzwerte normalerweise nicht erneut verwenden.

- Bei der Verwendung mit partitionierten Tabellen behält `TRUNCATE TABLE` die Partitionierung bei, d. h., Daten- und Indexdateien werden gelöscht und neu erstellt, während die Partitionsdefinitionsdatei (`.par`) hiervon unberührt bleibt.

`TRUNCATE TABLE` ist eine Oracle SQL-Erweiterung, die in MySQL übernommen wurde.

### 13.2.10. `UPDATE`

Syntax für eine Tabelle:

    UPDATE [LOW_PRIORITY] [IGNORE] tbl_name
        SET col_name1=expr1 [, col_name2=expr2 ...]
        [WHERE where_condition]
        [ORDER BY ...]
        [LIMIT row_count]

Syntax für mehrere Tabellen:

    UPDATE [LOW_PRIORITY] [IGNORE] table_references
        SET col_name1=expr1 [, col_name2=expr2 ...]
        [WHERE where_condition]

Bei der Ein-Tabellen-Syntax aktualisiert die `UPDATE`-Anweisung Spalten in vorhandenen Datensätzen in `tbl_name` mit neuen Werten. Die `SET`-Klausel gibt an, welche Spalten geändert werden und welche Werte diese erhalten sollen. Sofern angegeben, bestimmt die `WHERE`-Klausel die Bedingungen dafür, welche Datensätze geändert werden. Ohne `WHERE`-Klausel werden alle Datensätze aktualisiert. Wenn die `ORDER BY`-Klausel vorhanden ist, werden die Datensätze in der angegebenen Reihenfolge aktualisiert. Die `LIMIT`-Klausel kann die Anzahl der zu aktualisierenden Datensätze beschränken.

Bei der Mehrtabellensyntax aktualisiert `UPDATE` in jeder Tabelle `table_references` die Datensätze, die die Bedingungen erfüllen. In diesem Fall können `ORDER BY` und `LIMIT` nicht verwendet werden.

`where_condition` ist ein Ausdruck, der für jeden zu aktualisierenden Datensatz wahr ist. Er wird wie in Abschnitt 13.2.7, „`SELECT`“, beschrieben angegeben.

Die `UPDATE`-Anweisung unterstützt die folgenden Modifizierer:

- Wenn Sie das Schlüsselwort `LOW_PRIORITY` angeben, wird die Ausführung von `UPDATE` verzögert, bis kein Client mehr aus der Tabelle liest.

- Wenn Sie das Schlüsselwort `IGNORE` verwenden, bricht die `UPDATE`-Anweisung auch dann nicht ab, wenn während der Aktualisierung Fehler auftreten. Datensätze, bei denen Konflikte aufgrund von Schlüsseldubletten auftreten, werden nicht geändert. Datensätze, bei denen Spalten auf Werte gesetzt werden würden, die Datenkonvertierungsfehler zur Folge hätten, werden stattdessen auf den nächstgelegenen gültigen Wert gesetzt.

Wenn Sie in einem Ausdruck auf eine Spalte in der Tabelle `tbl_name` zugreifen, verwendet `UPDATE` den aktuellen Wert der Spalte. So erhöht die folgende Anweisung beispielsweise den aktuellen Wert in der Spalte `age` um 1:

    UPDATE persondata SET age=age+1;

`UPDATE`-Zuordnungen werden von links nach rechts ausgewertet. Die folgende Anweisung etwa verdoppelt die Spalte `age` und erhöht sie dann um 1:

    UPDATE persondata SET age=age*2, age=age+1;

Wenn Sie eine Spalte auf den Wert aktualisieren, den sie ohnehin gerade hat, dann bemerkt MySQL dies und führt keine Aktualisierung durch.

Wenn Sie eine als `NOT NULL` deklarierte Spalte aktualisieren, indem Sie sie auf `NULL` setzen, wird die Spalte stattdessen auf den für den jeweiligen Datentyp vorgesehenen Standardwert gesetzt und der Warnungszähler erhöht. Der Vorgabewert ist `0` bei numerischen Typen, der Leer-String (`''`) bei String-Typen und der „Nullwert“ für Datums- und Uhrzeittypen.

`UPDATE` gibt die Anzahl der tatsächlich geänderten Datensätze zurück. Die C-API-Funktion `mysql_info()` hingegen gibt die Anzahl der Datensätze, die gefunden und aktualisiert wurden, sowie die Anzahl der Warnungen zurück, die während der `UPDATE`-Operation aufgetreten sind.

Sie können `LIMIT `row_count`` verwenden, um den Geltungsbereich von `UPDATE` einzuschränken. Eine `LIMIT`-Klausel ist eine Beschränkung für Datensätze. Die Anweisung endet, sobald eine Anzahl von `row_count` Datensätzen gefunden wurde, die der `WHERE`-Klausel entsprechen – unabhängig davon, ob sie dann auch geändert wurden oder nicht.

Wenn eine `UPDATE`-Anweisung eine `ORDER BY`-Klausel enthält, werden die Datensätze in der in der Klausel angegebenen Reihenfolge aktualisiert.

Sie können auch `UPDATE`-Operationen durchführen, die sich auf mehrere Tabellen beziehen. Allerdings können Sie `ORDER BY` oder `LIMIT` nicht in einer `UPDATE`-Anweisung für mehrere Tabellen verwenden. Die Klausel `table_references` listet die Tabellen auf, die im Join berücksichtigt werden. Die Syntax ist in Abschnitt 13.2.7.1, „`JOIN`“, beschrieben. Hier ein Beispiel:

    UPDATE items,month SET items.price=month.price
    WHERE items.id=month.id;

Das obige Beispiel zeigt einen inneren Join, der den Kommaoperator verwendet. `UPDATE`-Anweisungen für mehrere Tabellen können jedoch einen beliebigen Join-Typ verwenden, der für `SELECT`-Anweisungen zulässig ist, also etwa `LEFT JOIN`.

Sie benötigen die Berechtigung `UPDATE` nur für diejenigen in einer `UPDATE`-Anweisung für mehrere Tabellen referenzierten Spalten, die tatsächlich geändert werden. Die Berechtigung `SELECT` hingegen benötigen Sie für alle Spalten, die gelesen, aber nicht modifiziert werden.

Wenn Sie eine `UPDATE`-Anweisung für mehrere Tabellen verwenden, die auch `InnoDB`-Tabellen einbezieht, für die Fremdschlüssel-Constraints vorhanden sind, dann verarbeitet der MySQL-Optimierer die Tabellen unter Umständen in einer Reihenfolge, die sich von der ihrer Parent/Child-Beziehung unterscheidet. In diesem Fall schlägt die Anweisung fehl, und es wird ein Rollback durchgeführt. Stattdessen sollten Sie die Änderung dann in nur einer Tabelle durchführen und sich auf die `ON UPDATE`-Funktionalität verlassen, die `InnoDB` bietet, um andere Tabellen entsprechend zu ändern. Siehe auch Abschnitt 14.2.6.4, „Fremdschlüssel-Beschränkungen“.

Zurzeit können Sie in einer Unterabfrage keine Aktualisierungsoperation in einer Tabelle durchführen und gleichzeitig eine Auswahl in einer anderen Tabelle treffen.

## 13.3. Grundlegende Befehle des MySQL-Dienstprogramms für Benutzer

### 13.3.1. `DESCRIBE` (Informationen über Spalten abrufen)

    {DESCRIBE | DESC} tbl_name [col_name | wild]

`DESCRIBE` vermittelt Informationen zu Spalten in einer Tabelle. Es handelt sich um ein Synonym für `SHOW COLUMNS FROM`. Diese Anweisungen erlauben auch die Anzeige von Informationen zu Views. (Siehe auch Abschnitt 13.5.4.3, „`SHOW COLUMNS`“.)

`col_name` kann ein Spaltenname oder aber ein String sein, der die SQL-Jokerzeichen ‘`%`’ und ‘`_`’ enthält, um eine Ausgabe nur zu Spalten zu erhalten, die dem String entsprechen. Sie müssen den String nicht in Anführungszeichen setzen, sofern er nicht Leerzeichen oder andere Sonderzeichen enthält.

    mysql> DESCRIBE city;
    +------------+----------+------+-----+---------+----------------+
    | Field      | Type     | Null | Key | Default | Extra          |
    +------------+----------+------+-----+---------+----------------+
    | Id         | int(11)  | NO   | PRI | NULL    | auto_increment |
    | Name       | char(35) | NO   |     |         |                |
    | Country    | char(3)  | NO   | UNI |         |                |
    | District   | char(20) | YES  | MUL |         |                |
    | Population | int(11)  | NO   |     | 0       |                |
    +------------+----------+------+-----+---------+----------------+
    5 rows in set (0.00 sec)

`Field` gibt den Spaltennamen an.

Das Feld `Null` zeigt an, ob `NULL`-Werte in der Spalte gespeichert werden können.

Das Feld `Key` gibt an, ob die Spalte indiziert ist. Mit `PRI` wird angegeben, dass die Spalte Teil des Primärschlüssels der Tabelle ist, mit `UNI` hingegen, dass sie Teil eines eindeutigen Indexes ist. Der Wert `MUL` schließlich signalisiert, dass mehrere Instanzen eines gegebenen Werts innerhalb der Spalte zulässig sind.

Ein möglicher Grund für die Anzeige von `MUL` in einem eindeutigen Index besteht darin, dass mehrere Spalten einen zusammengesetzten eindeutigen Index bilden. Dann ist die Kombination der Spalten eindeutig, während die einzelnen Spalten durchaus mehrere Instanzen eines gegebenen Werts enthalten können. Beachten Sie, dass in einem zusammengesetzten Index nur die links stehende Spalte einen Eintrag im Feld `Key` hat.

Das Feld `Default` gibt den Standardwert der Spalte an.

Das Feld `Extra` enthält zusätzliche Angaben, die zu einer gegebenen Spalte verfügbar sind. Im gezeigten Beispiel gibt `Extra` an, dass die Spalte `Id` mit dem Schlüsselwort `AUTO_INCREMENT` erstellt wurde.

Die Anweisung `DESCRIBE` ist aus Gründen der Kompatibilität mit Oracle vorhanden.

Auch die Anweisungen `SHOW CREATE TABLE` und `SHOW TABLE STATUS` bieten Informationen zu Tabellen. Siehe auch Abschnitt 13.5.4, „`SHOW`“.

### 13.3.2. `USE`

    USE db_name

Die Anweisung `USE `db_name`` weist MySQL an, die Datenbank `db_name` als Standarddatenbank (d. h. als aktuelle Datenbank) zu benutzen, auf die sich nachfolgende Anweisungen beziehen. Die Datenbank wird bis zum Ende der Sitzung oder aber so lange als Vorgabe verwendet, bis eine andere `USE`-Anweisung abgesetzt wird:

    USE db1;
    SELECT COUNT(*) FROM mytable;   # selects from db1.mytable
    USE db2;
    SELECT COUNT(*) FROM mytable;   # selects from db2.mytable

Wenn Sie eine bestimmte Datenbank mit `USE` zur Standarddatenbank machen, können Sie trotzdem auf Tabellen in anderen Datenbanken zugreifen. Im folgenden Beispiel wird auf die Tabelle `author` in der Datenbank `db1` und die Tabelle `editor` in der Datenbank `db2` zugegriffen:

    USE db1;
    SELECT author_name,editor_name FROM author,db2.editor
      WHERE author.editor_id = db2.editor.editor_id;

Die Anweisung `USE` ist aus Gründen der Kompatibilität mit Sybase vorhanden.

## 13.4. Transaktionale und Sperrbefehle von MySQL

MySQL unterstützt lokale Transaktionen (über eine gegebene Clientverbindung) unter Verwendung von Anweisungen wie `SET AUTOCOMMIT`, `START TRANSACTION`, `COMMIT` und `ROLLBACK`. Siehe auch Abschnitt 13.4.1, „`BEGIN/COMMIT/ROLLBACK`“. Die Unterstützung von XA-Transaktionen erlaubt MySQL außerdem die Teilnahme an verteilten Transaktionen. Siehe auch Abschnitt 13.4.7, „XA-Transaktionen“.

### 13.4.1. `BEGIN/COMMIT/ROLLBACK`

    START TRANSACTION | BEGIN [WORK]
    COMMIT [WORK] [AND [NO] CHAIN] [[NO] RELEASE]
    ROLLBACK [WORK] [AND [NO] CHAIN] [[NO] RELEASE]
    SET AUTOCOMMIT = {0 | 1}

Die Anweisungen `START TRANSACTION` und `BEGIN` starten eine neue Transaktion. `COMMIT` übergibt die aktuelle Transaktion, macht also die entsprechenden Änderungen permanent. Mit `ROLLBACK` machen Sie die laufende Transaktion rückgängig, d. h., alle Änderungen werden zurückgenommen. Die Anweisung `SET AUTOCOMMIT` schließlich aktiviert oder deaktiviert den standardmäßigen Autocommit-Modus für die aktuelle Verbindung.

Das optionale Schlüsselwort `WORK` wird für `COMMIT` und `RELEASE` unterstützt, ebenso die `CHAIN`- und `RELEASE`-Klauseln. `CHAIN` und `RELEASE` können verwendet werden, um den Transaktionsabschluss besser steuern zu können. Der Wert der Systemvariablen `completion_type` bestimmt das Standardverhalten beim Transaktionsabschluss. Siehe auch Abschnitt 5.2.2, „Server-Systemvariablen“.

Die `AND CHAIN`-Klausel bewirkt, dass eine neue Transaktion beginnt, sobald die aktuelle endet. Die neue Transaktion hat dabei dieselbe Isolierungsstufe wie die zuvor beendete Transaktion. Die `RELEASE`-Klausel bewirkt, dass der Server die aktuelle Clientverbindung nach Abschluss der aktuellen Transaktion beendet. Das Schlüsselwort `NO` unterdrückt den Abschluss von `CHAIN` oder `RELEASE`. Dies kann nützlich sein, wenn aufgrund der Einstellung der Systemvariablen `completion_type` der Abschluss von `CHAIN` oder `RELEASE` standardmäßig erzwungen wird.

Standardmäßig läuft MySQL im Autocommit-Modus. Das bedeutet, dass, sobald eine Anweisung ausgeführt wird, die eine Tabelle aktualisiert (also ändert), MySQL diese Änderung auf Festplatte speichert.

Verwenden Sie eine transaktionssichere Speicher-Engine (wie `InnoDB`, `BDB` oder `NDB Cluster`), dann können Sie den Autocommit-Modus mit der folgenden Anweisung deaktivieren:

    SET AUTOCOMMIT=0;

Nach der Deaktivierung des Autocommit-Modus durch Setzen der `AUTOCOMMIT`-Variablen auf Null müssen Sie Ihre Änderungen mit `COMMIT` auf Festplatte speichern oder mit `ROLLBACK` rückgängig machen, wenn Sie die seit Beginn der Transaktion vorgenommenen Änderungen nicht übernehmen wollen.

Um den Autocommit-Modus für eine einzelne Abfolge von Anweisungen zu deaktivieren, verwenden Sie die Anweisung `START TRANSACTION`:

    START TRANSACTION;
    SELECT @A:=SUM(salary) FROM table1 WHERE type=1;
    UPDATE table2 SET summary=@A WHERE type=1;
    COMMIT;

Bei `START TRANSACTION` bleibt Autocommit deaktiviert, bis Sie die Transaktion mit `COMMIT` oder `ROLLBACK` beenden. Der Autocommit-Modus kehrt dann in seinen vorherigen Status zurück.

`BEGIN` und `BEGIN WORK` werden als Aliase für `START TRANSACTION` benutzt, um eine Transaktion zu starten. `START TRANSACTION` ist die SQL-Standardsyntax und wird als Möglichkeit zur Durchführung spontaner Transaktionen empfohlen.

Die `BEGIN`-Anweisung unterscheidet sich von der Verwendung des Schlüsselworts `BEGIN`, welches eine mehrteilige `BEGIN ... END`-Anweisung einleitet. Mit Letzterem wird keine Transaktion begonnen. Siehe auch Abschnitt 19.2.5, „`BEGIN ... END`-Syntax für komplexe Anweisungen“.

Sie können eine Transaktion auch wie folgt einleiten:

    START TRANSACTION WITH CONSISTENT SNAPSHOT;

Die Klausel `WITH CONSISTENT SNAPSHOT` startet eine konsistente Leseoperation für Speicher-Engines, die diese unterstützen. Derzeit betrifft dies nur `InnoDB`. Der Effekt ist derselbe wie beim Absetzen einer `START TRANSACTION`-Anweisung gefolgt von einer `SELECT`-Anweisung für eine beliebige `InnoDB`-Tabelle. Siehe auch Abschnitt 14.2.10.4, „Konsistentes Lesen“.

Die Klausel `WITH CONSISTENT SNAPSHOT` ändert die aktuelle Isolationsstufe der Transaktion nicht, d. h., eine konsistente Momentaufnahme wird nur dann erstellt, wenn die aktuelle Isolationsstufe konsistente Leseoperationen gestattet (`REPEATABLE READ` oder `SERIALIZABLE`).

Bei Beginn einer Transaktion wird implizit `UNLOCK TABLES` ausgeführt.

Beste Ergebnisse erhalten Sie, wenn Sie Transaktionen nur bei Tabellen durchführen, die mit einer einzelnen transaktionssicheren Speicher-Engine verwaltet werden. Andernfalls können die folgenden Probleme auftreten:

- Wenn Ihre Tabellen mehrere transaktionssichere Speicher-Engines verwenden (z. B. `InnoDB` und `BDB`) und die Isolationsstufe nicht `SERIALIZABLE` ist, besteht die Möglichkeit, dass, wenn eine Transaktion übergeben wird, eine andere laufende Transaktion, die dieselben Tabellen benutzt, nur einen Teil der durch die erste Transaktion vorgenommenen Änderungen erkennt. Die Atomizität der Transaktionen ist mithin bei Verwendung mehrerer Engines nicht gewährleistet, und es können Inkonsistenzen auftreten. (Wenn Transaktionen mehrerer Engines nicht häufig vorkommen, können Sie die Isolationsstufe mit `SET TRANSACTION ISOLATION LEVEL` für eine Transaktion nach Bedarf auf `SERIALIZABLE` setzen.)

- Verwenden Sie in einer Transaktion nichttransaktionssichere Tabellen, dann werden alle Änderungen an diesen Tabellen unabhängig vom Status des Autocommit-Modus sofort gespeichert.

  Wenn Sie nach Aktualisierung einer nichttransaktionssicheren Tabelle in einer Transaktion eine `ROLLBACK`-Anweisung absetzen, erscheint die Warnung `ER_WARNING_NOT_COMPLETE_ROLLBACK`. Änderungen an transaktionssicheren Tabellen werden in diesem Fall rückgängig gemacht, nicht jedoch Änderungen an nichttransaktionssicheren Tabellen.

Jede Transaktion wird nach Absetzen von `COMMIT` am Stück in das Binärlog geschrieben. Transaktionen, die per Rollback rückgängig gemacht wurden, werden nicht geloggt. (Ausnahme: Für Modifikationen an nicht transaktionssicheren Tabellen kann kein Rollback durchgeführt werden. Wenn eine Transaktion, für die ein Rollback erfolgt, Änderungen an nicht transaktionssicheren Tabellen enthält, dann wird die gesamte Transaktion am Ende mit einer `ROLLBACK`-Anweisung geloggt, um sicherzustellen, dass die Modifikationen an diesen Tabellen repliziert werden.) Siehe auch Abschnitt 5.12.3, „Die binäre Update-Logdatei“.

Sie können die Isolationsstufe für Transaktionen mit `SET TRANSACTION ISOLATION LEVEL` ändern. Siehe auch Abschnitt 13.4.6, „`SET TRANSACTION`“.

Ein Rollback kann ein relativ langsamer Vorgang sein, der zudem stattfinden kann, ohne dass der Benutzer dies explizit angefordert hat (z. B. wenn ein Fehler aufgetreten ist). Aufgrund dieser Tatsache zeigt `SHOW PROCESSLIST` in der Spalte `State` für die Verbindung `Rolling back` an, solange implizite oder (durch die SQL-Anweisung `ROLLBACK`) explizite Rollbacks durchgeführt werden.

### 13.4.2. Statements können nicht zurückgerollt werden

Es gibt Anweisungen, für die kein Rollback möglich ist. Hierzu gehören DDL-Anweisungen (Data Definition Language), z. B. solche, mit denen Datenbanken erstellt oder gelöscht oder Tabellen oder gespeicherte Routinen erstellt, gelöscht oder geändert werden.

Sie sollten Ihre Transaktionen so entwickeln, dass solche Anweisungen nicht vorhanden sind. Wenn Sie eine Anweisung früh in einer Transaktion absetzen, für die kein Rollback möglich ist, und dann später eine andere Anweisung fehlschlägt, dann können durch Absetzen der `ROLLBACK`-Anweisung nicht alle Auswirkungen der Transaktion rückgängig gemacht werden.

### 13.4.3. Anweisungen, die implizite Commits verursachen

Alle folgenden Anweisungen (und ggf. auch ihre Synonyme) beenden eine Transaktion implizit – so als ob Sie vor Ausführung der Anweisung eine `COMMIT`-Anweisung abgesetzt hätten:

- `ALTER FUNCTION`, `ALTER PROCEDURE`, `ALTER TABLE`, `BEGIN`, `CREATE DATABASE`, `CREATE FUNCTION`, `CREATE INDEX`, `CREATE PROCEDURE`, `CREATE TABLE`, `DROP DATABASE`, `DROP FUNCTION`, `DROP INDEX`, `DROP PROCEDURE`, `DROP TABLE`, `LOAD MASTER DATA`, `LOCK TABLES`, `RENAME TABLE`, `SET AUTOCOMMIT=1`, `START TRANSACTION`, `TRUNCATE TABLE`, `UNLOCK TABLES`.

- `UNLOCK TABLES` übergibt eine Transaktion nur dann, wenn zum betreffenden Zeitpunkt Tabellen gesperrt sind.

- Die Anweisung `CREATE TABLE` in `InnoDB` wird als einzelne Transaktion verarbeitet. Das bedeutet, dass eine `ROLLBACK`-Anweisung seitens des Benutzers die `CREATE TABLE`-Anweisungen, die der Benutzer während der Transaktion abgesetzt hat, nicht rückgängig machen kann.

Transaktionen können nicht verschachtelt werden. Dies ist eine Folge des impliziten `COMMIT`, das für jede laufende Transaktion ausgeführt wird, wenn Sie eine `START TRANSACTION`-Anweisung (oder ein entsprechendes Synonym) absetzen.

### 13.4.4. `SAVEPOINT` und `ROLLBACK TO SAVEPOINT`

    SAVEPOINT identifier
    ROLLBACK [WORK] TO SAVEPOINT identifier
    RELEASE SAVEPOINT identifier

`InnoDB` unterstützt die SQL-Anweisungen `SAVEPOINT`, `ROLLBACK TO SAVEPOINT`, `RELEASE SAVEPOINT` und das optionale Schlüsselwort `WORK` für `ROLLBACK`.

Die `SAVEPOINT`-Anweisung setzt einen benannten Transaktionsspeicherpunkt mit dem Namen `identifier`. Hat die laufende Transaktion einen Speicherpunkt gleichen Namens, dann wird der alte Speicherpunkt gelöscht und ein neuer gesetzt.

Die Anweisung `ROLLBACK TO SAVEPOINT` macht eine Transaktion bis zum benannten Speicherpunkt rückgängig. Änderungen, die die aktuelle Transaktion an Datensätzen nach dem Speicherpunkt vorgenommen hat, werden im Rollback rückgängig gemacht; allerdings hebt `InnoDB` Datensatzsperren, die nach dem Speicherpunkt im Speicher abgelegt wurden, nicht auf. (Beachten Sie, dass bei einem neu eingefügten Datensatz die Sperrinformation in dem im Datensatz gespeicherten Transaktionsbezeichner enthalten ist, d. h., die Sperre wird nicht separat im Speicher abgelegt. In diesem Fall wird die Datensatzsperre beim Rückgängigmachen aufgehoben.) Speicherpunkte, die zeitlich nach dem genannten Speicherpunkt liegen, werden gelöscht.

Wenn die `ROLLBACK TO SAVEPOINT`-Anweisung den folgenden Fehler zurückgibt, heißt das, dass es keinen Speicherpunkt des angegebenen Namens gibt:

    ERROR 1181: Got error 153 during ROLLBACK

Die Anweisung `RELEASE SAVEPOINT` entfernt den genannten Speicherpunkt aus der Menge der Speicherpunkte für die laufende Transaktion. Es findet weder eine Übergabe noch ein Rollback statt. Existiert der Speicherpunkt nicht, dann tritt ein Fehler auf.

Alle Speicherpunkte der aktuellen Transaktion werden gelöscht, wenn Sie eine `COMMIT`- oder `ROLLBACK`-Anweisung absetzen, die keinen Speicherpunkt benennt.

Seit MySQL 5.0.17 wird eine neue Speicherpunktstufe erstellt, wenn eine gespeicherte Funktion aufgerufen oder ein Trigger aktiviert wird. Die Speicherpunkte der vorherigen Stufen sind dann nicht mehr verfügbar, damit Konflikte mit Speicherpunkten der neuen Stufe vermieden werden. Wenn die Funktion oder der Trigger beendet wird, werden alle hierdurch erstellten Speicherpunkte gelöscht und die vorherige Speicherpunktstufe wird wiederhergestellt.

### 13.4.5. `LOCK TABLES` und `UNLOCK TABLES`

    LOCK TABLES
        tbl_name [AS alias] {READ [LOCAL] | [LOW_PRIORITY] WRITE}
        [, tbl_name [AS alias] {READ [LOCAL] | [LOW_PRIORITY] WRITE}] ...
    UNLOCK TABLES

`LOCK TABLES` sperrt Tabellen für den aktuellen Thread. Wenn eine Tabelle von anderen Threads gesperrt ist, wird der laufende Vorgang angehalten, bis alle Sperren erwirkt werden können. `UNLOCK TABLES` hebt Sperren auf, die vom aktuellen Thread gehalten werden. Die Sperren aller Tabellen, die vom aktuellen Thread gesperrt werden, werden implizit aufgehoben, wenn der Thread eine andere `LOCK TABLES`-Anweisung absetzt oder die Verbindung zum Server geschlossen wird.

Eine Tabellensperre schützt nur gegen unangemessene Lese- und Schreiboperationen durch andere Clients. Der Client, der die Sperre (auch eine Lesesperre) hält, kann Operationen auf Tabellenebene – wie etwa `DROP TABLE` – durchführen.

Beachten Sie die folgenden Angaben zur Verwendung von `LOCK TABLES` bei transaktionssicheren Tabellen:

- `LOCK TABLES` ist nicht transaktionssicher und übergibt implizit alle aktiven Transaktionen, bevor versucht wird, die Sperre für die Tabelle zu erwirken. Auch das Starten einer Transaktion (z. B. bei `START TRANSACTION`) führt implizit eine `UNLOCK TABLES`-Anweisung aus. (Siehe auch Abschnitt 13.4.3, „Anweisungen, die implizite Commits verursachen“.)

- Die korrekte Vorgehensweise bei der Verwendung von `LOCK TABLES` in Verbindung mit transaktionssicheren Tabellen wie `InnoDB` besteht darin, `AUTOCOMMIT = 0` zu setzen und `UNLOCK TABLES` erst dann aufzurufen, wenn die Transaktion explizit übergeben werden soll. Wenn Sie `LOCK TABLES` aufrufen, setzt `InnoDB` intern eine eigene Tabellensperre. Auch MySQL setzt eine eigene Tabellensperre. `InnoDB` hebt seine Sperre beim nächsten Commit-Vorgang auf; damit MySQL seinerseits die Sperre aufhebt, müssen Sie `UNLOCK TABLES` aufrufen. Sie sollten `AUTOCOMMIT = 1` nicht setzen, weil `InnoDB` dann seine Tabellensperre direkt nach dem Aufruf von `LOCK TABLES` aufhebt; auf diese Weise kann es zu einer vollständigen Sperrung kommen. Beachten Sie, dass bei `AUTOCOMMIT = 1` die `InnoDB`-Tabellensperre überhaupt nicht gesetzt wird, damit ältere Anwendungen sich nicht versehentlich vollständig ausschließen.

- `ROLLBACK` hebt die Sperren bei den nichttransaktionssicheren Tabellen von MySQL nicht auf.

Um `LOCK TABLES` zu verwenden, benötigen Sie die Berechtigungen `LOCK TABLES` und `SELECT` für die betreffenden Tabellen.

Die wichtigsten Gründe zur Verwendung von `LOCK TABLES` sind die Emulation von Transaktionen oder die Beschleunigung der Aktualisierung von Tabellen. Wir werden dies weiter unten ausführlicher erläutern.

Wenn ein Thread eine Lesesperre für eine Tabelle erwirkt, kann dieser Thread (wie auch alle übrigen Threads) aus der Tabelle nur lesen. Wenn ein Thread eine Schreibsperre für eine Tabelle erwirkt, dann kann nur der Thread, der die Sperre hält, in die Tabelle schreiben. Anderen Threads wird dies untersagt, bis die Sperre aufgehoben ist.

Der Unterschied zwischen `READ LOCAL` und `READ` besteht darin, dass `READ LOCAL` bei aktiver Sperre die Ausführung von `INSERT`-Anweisungen (also nebenläufigen Einfügeoperationen) zulässt, sofern sie keine Konflikte auslösen. Allerdings kann diese Funktion nicht verwendet werden, um die Datenbankdateien bei aktiver Sperre außerhalb von MySQL zu manipulieren. Bei `InnoDB`-Tabellen entspricht `READ LOCAL` `READ`.

Wenn Sie `LOCK TABLES` einsetzen, müssen Sie alle Tabellen sperren, die Sie in Ihren Abfragen zu benutzen beabsichtigen. Solange die mit einer `LOCK TABLES`-Anweisung erwirkten Sperren gültig sind, können Sie nicht auf Tabellen zugreifen, die nicht durch die Anweisung gesperrt wurden. Ferner können Sie eine gesperrte Tabelle auch nicht mehrfach in derselben Abfrage verwenden. Benutzen Sie stattdessen Aliase. In diesem Fall müssen Sie allerdings für jeden Alias separat eine Sperre erwirken.

    mysql> LOCK TABLE t WRITE, t AS t1 WRITE;
    mysql> INSERT INTO t SELECT * FROM t;
    ERROR 1100: Table 't' was not locked with LOCK TABLES
    mysql> INSERT INTO t SELECT * FROM t AS t1;

Wenn Ihre Abfragen eine Tabelle unter Verwendung eines Alias referenzieren, müssen Sie die Tabelle sperren, die denselben Alias benutzt. Die Tabelle zu sperren, ohne den Alias anzugeben, funktioniert nicht:

    mysql> LOCK TABLE t READ;
    mysql> SELECT * FROM t AS myalias;
    ERROR 1100: Table 'myalias' was not locked with LOCK TABLES

Umgekehrt müssen Sie, wenn Sie eine Tabelle unter Verwendung eines Alias sperren, diese Tabelle unter Verwendung dieses Alias in Ihren Abfragen referenzieren:

    mysql> LOCK TABLE t AS myalias READ;
    mysql> SELECT * FROM t;
    ERROR 1100: Table 't' was not locked with LOCK TABLES
    mysql> SELECT * FROM t AS myalias;

`WRITE`-Sperren haben in der Regel Vorrang vor `READ`-Sperren. Hierdurch soll sichergestellt werden, dass Aktualisierungen so schnell wie möglich verarbeitet werden. Das bedeutet, dass, wenn ein Thread eine `READ`-Sperre erwirkt und dann ein anderer Thread eine `WRITE`-Sperre anfordert, nachfolgende `READ`-Sperranforderungen warten müssen, bis der `WRITE`-Thread die Sperre wieder aufgehoben hat. Sie können mit `LOW_PRIORITY WRITE`-Sperren anderen Threads das Erwirken von `READ`-Sperren gestatten, während der Thread auf die `WRITE`-Sperre wartet. `LOW_PRIORITY WRITE`-Sperren sollten Sie nur dann verwenden, wenn Sie sicher sind, dass zu einem nachfolgenden Zeitpunkt keine Threads mehr eine `READ`-Sperre halten werden.

`LOCK TABLES` funktioniert wie folgt:

1. Alle zu sperrenden Tabellen werden in einer intern definierten Reihenfolge sortiert. Aus Sicht des Benutzers ist diese Reihenfolge undefiniert.

2. Wenn eine Tabelle mit einer Lese- und einer Schreibsperre gesperrt ist, wird die Schreib- vor der Lesesperre gesetzt.

3. Es wird immer nur eine Tabelle gleichzeitig gesperrt, bis der Thread alle Sperren erhalten hat.

Diese Vorgehensweise gewährleistet, dass ein Aussperren ausgeschlossen ist. Es gibt jedoch ein paar andere Aspekte, die Sie bezüglich der Vorgehensweise beachten sollten:

Wenn Sie eine `LOW_PRIORITY WRITE`-Sperre für eine Tabelle verwenden, bedeutet dies lediglich, dass MySQL auf diese bestimmte Sperre wartet, bis keine Threads mehr vorhanden sind, die eine `READ`-Sperre benötigen. Wenn der Thread die `WRITE`-Sperre erwirkt hat und darauf wartet, die Sperre für die nächste Tabelle in der Sperrliste zu erwirken, warten alle anderen Threads darauf, dass die `WRITE`-Sperre aufgehoben wird. Wenn dies in Bezug auf Ihre Anwendung ein schwerwiegendes Problem darstellen sollte, dann sollten Sie in Betracht ziehen, einige Ihrer Tabellen in transaktionssichere Tabellen umzuwandeln.

Sie können einen Thread, der auf eine Tabellensperre wartet, problemlos mit `KILL` terminieren. Siehe auch Abschnitt 13.5.5.3, „`KILL`“.

Beachten Sie, dass Sie keine Tabellen sperren sollen, die Sie mit `INSERT DELAYED` verwenden, weil die Einfügeoperation in diesem Fall durch einen separaten Thread durchgeführt wird.

Normalerweise müssen Sie Tabellen nicht sperren, weil alle `UPDATE`-Anweisungen für sich atomisch sind: Kein anderer Thread kann eine andere derzeit ausgeführte SQL-Anweisung unterbrechen. Allerdings gibt es einige wenige Fälle, in denen das Sperren von Tabellen von Vorteil sein kann:

- Wenn Sie viele Operationen für eine Anzahl von `MyISAM`-Tabellen ausführen wollen, geht dies schneller, wenn Sie die zu verwendenden Tabellen sperren. Das Sperren von `MyISAM`-Tabellen beschleunigt das Einfügen, Aktualisieren und Löschen in diesen Tabellen. Der Nachteil besteht darin, dass kein Thread eine `READ`-gesperrte Tabelle ändern kann (einschließlich derjenigen, die die Sperre hält) und dass kein Thread auf eine `WRITE`-gesperrte Tabelle mit Ausnahme derjenigen zugreifen kann, die die Sperre hält.

  Der Grund dafür, dass `MyISAM`-Operationen unter `LOCK TABLES` schneller ausgeführt werden, besteht darin, dass MySQL den Schlüssel-Cache gesperrter Tabellen erst beim Aufruf von `UNLOCK TABLES` synchronisiert. Normalerweise wird der Schlüssel-Cache nach jeder SQL-Anweisung synchronisiert.

- Wenn Sie eine Speicher-Engine in MySQL verwenden, die Transaktionen nicht unterstützt, müssen Sie `LOCK TABLES` einsetzen, um sicherzustellen, dass kein anderer Thread zwischen eine `SELECT`- und eine `UPDATE`-Anweisung gelangt. Folgendes Beispiel erfordert `LOCK TABLES`, um sicher ausgeführt werden zu können:

      LOCK TABLES trans READ, customer WRITE;
      SELECT SUM(value) FROM trans WHERE customer_id=some_id;
      UPDATE customer
        SET total_value=sum_from_previous_statement
        WHERE customer_id=some_id;
      UNLOCK TABLES;

  Ohne `LOCK TABLES` könnte ein anderer Thread unter Umständen zwischen der Ausführung der `SELECT`- und der Ausführung der `UPDATE`-Anweisung einen neuen Datensatz in die `trans`-Tabelle einfügen.

Sie können die Verwendung von `LOCK TABLES` in vielen Fällen umgehen, indem Sie relative Updates (`UPDATE customer SET `value`=`value`+`new_value``) oder die Funktion `LAST_INSERT_ID()` verwenden. Siehe auch Abschnitt 1.9.5.3, „Transaktionen“.

Sie können das Sperren von Tabellen in manchen Fällen auch umgehen, indem Sie Funktionen für beratende Sperrungen auf Benutzerebene (`GET_LOCK()` und `RELEASE_LOCK()`) verwenden. Diese Sperren werden in einer Hash-Tabelle auf dem Server gespeichert und mit `pthread_mutex_lock()` und `pthread_mutex_unlock()` mit dem Ziel einer hohen Geschwindigkeit implementiert. Siehe auch Abschnitt 12.10.4, „Verschiedene Funktionen“.

Weitere Informationen zu Methoden beim Sperren finden Sie in Abschnitt 7.3.1, „Wie MySQL Tabellen sperrt“.

Sie können mit der Anweisung `FLUSH TABLES WITH READ LOCK` Lesesperren für alle Tabellen in allen Datenbanken setzen. Siehe auch Abschnitt 13.5.5.2, „`FLUSH`“. Dies ist eine recht praktische Möglichkeit der Datensicherung, wenn Sie ein Dateisystem wie Veritas einsetzen, das rechtzeitig Schnappschüsse erstellt.

Hinweis: Wenn Sie `ALTER TABLE` für eine gesperrte Tabelle ausführen, kann die Sperre unter Umständen aufgehoben werden. Siehe auch Abschnitt A.7.1, „Probleme mit `ALTER TABLE`“.

### 13.4.6. `SET TRANSACTION`

    SET [GLOBAL | SESSION] TRANSACTION ISOLATION LEVEL
    { READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE }

Diese Anweisung bestimmt die Transaktionsisolationsstufe für die nächste Transaktion, global oder für die aktuelle Sitzung.

Das Standardverhalten von `SET TRANSACTION` besteht darin, die Isolationsstufe für die nächste (d. h. noch nicht gestartete) Transaktion einzustellen. Wenn Sie das Schlüsselwort `GLOBAL` verwenden, setzt die Anweisung die Standardtransaktionsstufe global für alle neuen Verbindungen, die nachfolgend hergestellt werden. Vorhandene Verbindungen werden hiervon nicht berührt. Für diesen Zweck benötigen Sie die Berechtigung `SUPER`. Bei Verwendung des Schlüsselworts `SESSION` wird die standardmäßige Transaktionsstufe für alle zukünftigen Transaktionen gesetzt, die über die aktuelle Verbindung durchgeführt werden.

Beschreibungen aller `InnoDB`-Transaktionsisolationsstufen finden Sie in Abschnitt 14.2.10.3, „`InnoDB` und `TRANSACTION ISOLATION LEVEL`“. `InnoDB` unterstützt in MySQL 5.1 alle Stufen. Die Standardstufe ist `REPEATABLE READ`.

Um die globale Standardisolationsstufe für mysqld festzulegen, verwenden Sie die Option `--transaction-isolation`. Siehe auch Abschnitt 5.2.1, „Befehlsoptionen für mysqld“.

### 13.4.7. XA-Transaktionen

Die Unterstützung von XA-Transaktionen ist für die `InnoDB`-Speicher-Engine verfügbar. Die XA-Implementierung bei MySQL basiert auf dem X/Open CAE-Dokument Distributed Transaction Processing: The XA Specification („Verteilte Transaktionsverarbeitung: Die XA-Spezifikation“). Dieses Dokument wurde von The Open Group veröffentlicht und ist unter http://www.opengroup.org/public/pubs/catalog/c193.htm erhältlich. Die Grenzen der aktuellen XA-Implementierung sind in Abschnitt I.5, „Beschränkungen bei XA-Transaktionen“ beschrieben.

Clientseitig gibt es keine besonderen Anforderungen. Die XA-Schnittstelle zu einem MySQL Server besteht aus SQL-Anweisungen, die mit dem Schlüsselwort `XA` beginnen. MySQL-Clientprogramme müssen SQL-Anweisungen senden und die Semantik der XA-Anweisungsschnittstelle verstehen können. Sie müssen nicht mit einer aktuellen Clientbibliothek verknüpft sein: Es können auch ältere Clientbibliotheken verwendet werden.

Derzeit unterstützt MySQL Connector/J 5.0.0 XA direkt (mithilfe einer Klassenschnittstelle, die die XA-SQL-Anweisungsschnittstelle für Sie verwaltet).

XA unterstützt verteilte Transaktionen, d. h., mehrere separate transaktionssichere Ressourcen können an einer globalen Transaktion teilnehmen. Transaktionssichere Ressourcen sind häufig relationale Datenbanksysteme, es gibt aber auch andere Ressourcentypen.

Eine globale Transaktion umfasst mehrere Aktionen, die für sich transaktionssicher sind; sie alle aber müssen entweder als Gruppe erfolgreich abgeschlossen werden, oder sie werden im Rahmen eines Rollbacks gemeinsam rückgängig gemacht. Im Endeffekt erweitert dies die ACID-Eigenschaften um eine „Ebene nach oben“, sodass mehrere ACID-Transaktionen konzertiert als Komponenten einer globalen Operation ausgeführt werden, die ebenfalls ACID-Eigenschaften hat. (Allerdings müssen Sie bei einer verteilten Transaktion die Isolationsstufe `SERIALIZABLE` benutzen, um ACID-Eigenschaften zu erhalten. Bei nichtverteilten Transaktionen ist `REPEATABLE READ` ausreichend, nicht aber bei verteilten Transaktionen.)

Es folgen einige Beispiele für verteilte Transaktionen:

- Eine Anwendung kann als Integrations-Tool agieren, welches einen Messaging-Dienst mit einem relationalen Datenbanksystem kombiniert. Die Anwendung stellt sicher, dass Transaktionen, die Versand, Abruf und Verarbeitung von Mitteilungen in Verbindung mit einer transaktionssicheren Datenbank regeln, auch alle in einer globalen Transaktion erfolgen. Man könnte sich dies als „transaktionssichere E-Mail“ vorstellen.

- Eine Anwendung führt Aktionen durch, die verschiedene Datenbankserver betrifft, z. B. einen MySQL und einen Oracle-Server (oder auch mehrere MySQL Server). Hierbei müssen Aktionen, die mehrere Server betreffen, als Teil einer globalen Transaktion statt als separate Transaktionen stattfinden, die auf jedem Server getrennt ausgeführt werden.

- Eine Bank speichert Kontendaten in einem relationalen Datenbanksystem. Empfang und Versand von Geld erfolgen über Bankautomaten. Es muss dabei gewährleistet sein, dass alle Vorgänge an den Automaten auf den Konten umgesetzt werden. Dies ist aber nicht allein mit dem Datenbanksystem möglich: Ein globaler Transaktionsmanager integriert Bankautomat- und Datenbankressourcen, um die Gesamtkonsistenz der Finanztransaktionen sicherzustellen.

Anwendungen, die globale Transaktionen verwenden, umfassen einen oder mehrere Ressourcenmanager und einen Transaktionsmanager:

- Der Ressourcenmanager (RM) ermöglicht den Zugriff auf transaktionssichere Ressourcen. Ein Datenbankserver ist eine Art von Ressourcenmanager. Transaktionen, die vom RM verwaltet werden, müssen entweder im Rahmen eines Commits geschrieben oder im Zuge eines Rollbacks rückgängig gemacht werden können.

- Ein Transaktionsmanager (TM) koordiniert die Transaktionen, die Teil einer globalen Transaktion sind. Er kommuniziert mit den RMs, die die einzelnen Transaktionen verwalten. Die einzelnen Transaktionen innerhalb einer globalen Transaktion sind die „Verzweigungen“ der globalen Transaktion. Globale Transaktionen und ihre Verzweigungen werden anhand eines Namensschemas unterschieden, welches weiter unten beschrieben werden wird.

Die MySQL-Implementierung von XA erlaubt es einem MySQL Server, als RM zu agieren, der XA-Transaktionen innerhalb einer globalen Transaktion verwaltet. Ein Clientprogramm, das eine Verbindung mit dem MySQL Server herstellt, agiert als TM.

Um eine globale Transaktion auszuführen, ist es erforderlich zu wissen, welche Komponenten betroffen sind, und jede dieser Komponenten an einen Punkt zu bringen, an dem sie übergeben oder rückgängig gemacht werden kann. Abhängig davon, was jede Komponente bezüglich ihres Erfolgs oder Fehlschlags meldet, müssen sie alle als atomische Gruppe übergeben oder rückgängig gemacht werden: Es müssen also entweder alle Komponenten geschrieben werden oder alle Komponenten werden im Zuge eines Rollbacks ungeschehen gemacht. Um eine globale Transaktion verwalten zu können, muss berücksichtigt werden, dass jede Komponente fehlschlagen oder auch das sie verbindende Netzwerk ausfallen kann.

Der Prozess zur Ausführung einer globalen Transaktion basiert auf 2PC (2-Phase Commit, Übergabe in zwei Phasen). Dies findet statt, nachdem die von den Verzweigungen der globalen Transaktion durchgeführten Vorgänge erledigt sind.

1. In der ersten Phase werden alle Verzweigungen vorbereitet: Sie werden vom TM angewiesen, sich für die Übergabe bereitzuhalten. Normalerweise bedeutet dies, dass jeder RM, der eine Verzweigung verwaltet, die Aktionen für diese Verzweigung in einem zuverlässigen Speicher ablegt. Die Verzweigungen geben an, ob dies jeweils für sie möglich ist. Die Ergebnisse werden in der zweiten Phase verwendet.

2. In der zweiten Phase weist der TM die RMs an, eine Übergabe oder einen Rollback durchzuführen. Wenn alle Verzweigungen bei der Vorbereitung angegeben haben, dass sie für eine Übergabe bereit sind, werden sie alle zur Übergabe angewiesen. Hat jedoch mindestens eine Verzweigung im Zuge der Vorbereitung gemeldet, dass bei ihr keine Übergabe möglich ist, dann werden alle Verzweigungen zu einem Rollback angewiesen.

In manchen Fällen verwendet eine globale Transaktion unter Umständen nur eine einphasige Übergabe (1PC). Stellt beispielsweise ein TM fest, dass eine globale Transaktion nur eine einzige transaktionssichere Ressource (also nur eine Verzweigung) umfasst, dann kann diese Ressource zur selben Zeit zur Vorbereitung und Übergabe angewiesen werden.

#### 13.4.7.1. SQL-Syntax von XA-Transaktionen

Um XA-Transaktionen in MySQL durchzuführen, verwenden Sie die folgenden Anweisungen:

    XA {START|BEGIN} xid [JOIN|RESUME]

    XA END xid [SUSPEND [FOR MIGRATE]]

    XA PREPARE xid

    XA COMMIT xid [ONE PHASE]

    XA ROLLBACK xid

    XA RECOVER

Bei `XA START` werden die Klauseln `JOIN` und `RESUME` nicht unterstützt.

Bei `XA END` wird die Klausel `SUSPEND [FOR MIGRATE]` nicht unterstützt.

Jede XA-Anweisung beginnt mit dem Schlüsselwort `XA`. Die meisten dieser Anweisungen erfordern einen `xid`-Wert. `xid` ist ein XA-Transaktionsbezeichner. Er gibt an, für welche Transaktion die Anweisung gilt. `xid`-Werte werden vom Client übergeben oder auf dem MySQL Server erzeugt. Ein `xid`-Wert besteht aus einem bis drei Teilen:

    xid: gtrid [, bqual [, formatID ]]

`gtrid` ist ein globaler Transaktionsbezeichner, `bqual` ein Verzweigungsbezeichner und `formatID` eine Zahl, die das Format angibt, welches von den `gtrid`- und `bqual`-Werten verwendet wird. Wie aus der Syntax hervorgeht, sind `bqual` und `formatID` optional. Der Standardwert von `bqual` ist `''`, sofern nichts anderes angegeben ist. Der Standardwert von `formatID` ist 1, sofern nichts anderes angegeben ist.

`gtrid` und `bqual` müssen String-Literale sein, die jeweils bis zu 64 Byte (nicht Zeichen) lang sein dürfen. `gtrid` und `bqual` können auf unterschiedliche Art und Weise angegeben werden. Sie können einen String in Anführungszeichen (`'ab'`), einen Hexadezimal-String (`0x6162`, `X'ab'`) oder einen Bitwert (`b'`nnnn`'`) angeben.

`formatID` ist ein vorzeichenloser Integer.

Die `gtrid` - und `bqual`-Werte werden von den XA-Supportroutinen auf dem MySQL Server als Bytewerte interpretiert. Allerdings benutzt der Server bei der Analyse einer SQL-Anweisung, die eine XA-Anweisung enthält, einen speziellen Zeichensatz. Wenn Sie sichergehen wollen, notieren Sie `gtrid` und `bqual` als Hexadezimal-String.

`xid`-Werte werden normalerweise vom TM erzeugt. Die Werte, die von einem TM erzeugt werden, müssen sich von denen unterscheiden, die von anderen TMs gebildet werden. Ein gegebener TM muss seine eigenen `xid`-Werte in einer Werteliste, die von der Anweisung `XA RECOVER` zurückgegeben wird, erkennen können.

`XA START `xid`` startet eine XA-Transaktion mit dem gegebenen `xid`-Wert. Jede XA-Transaktion benötigt einen eindeutigen `xid`-Wert, d. h., der Wert darf nicht gleichzeitig von einer anderen XA-Transaktion verwendet werden. Diese Eindeutigkeit wird mithilfe der Werte `gtrid` und `bqual` erzielt. Alle nachfolgenden XA-Anweisungen für die XA-Transaktion müssen unter Verwendung desselben `xid`-Werts angegeben werden, der in der `XA START`-Anweisung übergeben wurde. Verwenden Sie eine dieser Anweisungen und geben dabei keinen `xid`-Wert an, der einer laufenden XA-Transaktion entspricht, dann tritt ein Fehler auf.

Eine oder mehrere XA-Transaktionen können Teil derselben globalen Transaktion sein. Alle XA-Transaktionen in einer gegebenen globalen Transaktion müssen denselben `gtrid`-Wert im `xid`-Wert benutzen. Aus diesem Grund müssen `gtrid`-Werte global eindeutig sein, damit keine Mehrdeutigkeiten darüber aufkommen können, zu welcher globalen Transaktion eine gegebene XA-Transaktion gehört. Der Teil `bqual` des `xid`-Werts muss sich für jede XA-Transaktion innerhalb einer globalen Transaktion unterscheiden. (Die Anforderung, dass `bqual`-Werte unterschiedlich sein müssen, stellt eine Einschränkung der aktuellen XA-Implementierung in MySQL dar. Sie ist nicht Teil der XA-Spezifikation.)

Die Anweisung `XA RECOVER` gibt Informationen zu denjenigen XA-Transaktionen auf dem MySQL Server zurück, die den Status `PREPARED` haben. (Siehe auch Abschnitt 13.4.7.2, „XA-Transaktionszustände“.) Die Ausgabe enthält einen Datensatz für jede derartige XA-Transaktion auf dem Server – unabhängig davon, welcher Client sie gestartet hat.

Die Ausgabedatensätze von `XA RECOVER` sehen wie folgt aus (für einen `xid`-Beispielwert, der aus den Teilen `'abc'`, `'def'` und `7` besteht):

    mysql> XA RECOVER;
    +----------+--------------+--------------+--------+
    | formatID | gtrid_length | bqual_length | data   |
    +----------+--------------+--------------+--------+
    |        7 |            3 |            3 | abcdef |
    +----------+--------------+--------------+--------+

Die Ausgabespalten haben die nachfolgend beschriebenen Bedeutungen:

- `formatID` ist der `formatID`-Teil der Transaktion `xid`.

- `gtrid_length` ist die Länge des `gtrid`-Teils der Transaktion `xid` in Byte.

- `bqual_length` ist die Länge des `bqual`-Teils der Transaktion `xid` in Byte.

- `data` ist die Verkettung der Teile `gtrid` und `bqual` der Transaktion `xid`.

#### 13.4.7.2. XA-Transaktionszustände

Eine XA-Transaktion umfasst die folgenden Phasen:

1. Starten Sie mit `XA START` eine XA-Transaktion und versetzen Sie sie in den Status `ACTIVE`.

2. Sobald die XA-Transaktion aktiv ist, setzen Sie die SQL-Anweisungen für die Transaktion ab. Zuletzt setzen Sie eine `XA END`-Anweisung ab, mit der Sie die Transaktion in den Zustand `IDLE` versetzen.

3. Bei einer XA-Transaktion in diesem Zustand können Sie entweder eine `XA PREPARE`-Anweisung oder eine `XA COMMIT ... ONE PHASE`-Anweisung absetzen:

   - `XA PREPARE` versetzt die Transaktion in den Zustand `PREPARED`. Bei Eingabe einer `XA RECOVER` -Anweisung an dieser Stelle wird der `xid`-Wert der Transaktion in die Ausgabe integriert, weil `XA RECOVER` alle XA-Transaktionen auflistet, deren Zustand `PREPARED` ist.

   - `XA COMMIT ... ONE PHASE` bereit die Transaktion vor und übergibt sie dann direkt. Der `xid`-Wert wird von `XA RECOVER` nicht aufgelistet, weil die Transaktion endet.

4. Bei einer XA-Transaktion im Zustand `PREPARED` können Sie eine `XA COMMIT`-Anweisung absetzen, um sie zu übergeben und zu beenden, oder Sie machen sie mit einer `XA ROLLBACK`-Anweisung rückgängig (sie wird dann ebenfalls beendet).

Es folgt eine einfache XA-Transaktion, die im Rahmen einer globalen Transaktion einen Datensatz in eine Tabelle einfügt:

    mysql> XA START 'xatest';
    Query OK, 0 rows affected (0.00 sec)

    mysql> INSERT INTO mytable (i) VALUES(10);
    Query OK, 1 row affected (0.04 sec)

    mysql> XA END 'xatest';
    Query OK, 0 rows affected (0.00 sec)

    mysql> XA PREPARE 'xatest';
    Query OK, 0 rows affected (0.00 sec)

    mysql> XA COMMIT 'xatest';
    Query OK, 0 rows affected (0.00 sec)

Im Kontext einer gegebenen Clientverbindung schließen sich XA-Transaktionen und lokale Transaktionen (also Nicht-XA-Transaktionen) gegenseitig aus. Wenn beispielsweise mit `XA START` eine XA-Transaktion gestartet wurde, dann kann eine lokale Transaktion erst begonnen werden, wenn die XA-Transaktion übergeben oder rückgängig gemacht wurde. Umgekehrt können, wenn eine lokale Transaktion mit `START TRANSACTION` begonnen wurde, XA-Anweisungen erst dann verwendet werden, wenn die Transaktion übergeben oder rückgängig gemacht wurde.

## 13.5. Anweisungen zur Datenbankadministration

### 13.5.1. Anweisungen zur Benutzerkontenverwaltung

MySQL-Kontendaten sind in Tabellen der Datenbank `mysql` gespeichert. Diese Datenbank und das Zugriffssteuerungssystem sind in Kapitel 5, Datenbankverwaltung, ausführlich beschrieben. Sie finden dort weitere Informationen.

Wichtig: Einige Releases von MySQL enthalten Änderungen an der Struktur der Grant-Tabellen, damit neue Berechtigungen oder Funktionen hinzugefügt werden können. Wenn Sie ein Upgrade auf eine neue MySQL-Version durchführen, sollten Sie Ihre Grant-Tabellen aktualisieren, damit sichergestellt ist, dass diese auf der aktuellen Struktur basieren und auf diese Weise neue Funktionalitäten nutzen können. Siehe auch Abschnitt 5.6, „mysql_fix_privilege_tables — Upgrade von MySQL-Systemtabellen“.

#### 13.5.1.1. `CREATE USER`

    CREATE USER user [IDENTIFIED BY [PASSWORD] 'password']
        [, user [IDENTIFIED BY [PASSWORD] 'password']] ...

Die `CREATE USER`-Anweisung erstellt neue MySQL-Konten. Um sie zu verwenden, benötigen Sie die globale Berechtigung `CREATE USER` oder die Berechtigung `INSERT` für die Datenbank `mysql`. Für jedes Konto richtet `CREATE USER` einen neuen Datensatz in der Tabelle `mysql.user` ein, der keine Berechtigungen hat. Ist das Konto bereits vorhanden, dann tritt ein Fehler auf. Jedes Konto wird im selben Format wie bei der `GRANT`-Anweisung benannt (z. B. `'jeffrey'@'localhost'`). Die Benutzer- und Hostbestandteile des Kontonamens entsprechen den Werten der Spalten `User` und `Host` des kontenspezifischen Datensatzes in der Tabelle `user`.

Das Konto erhält ein Passwort mit der optionalen `IDENTIFIED BY`-Klausel. Der Wert `user` und das Passwort werden auf gleiche Weise übergeben wie bei der `GRANT`-Anweisung. Insbesondere müssen Sie das Schlüsselwort `PASSWORD` weglassen, um das Passwort im Klartext angeben zu können. Wenn Sie das Passwort hingegen als von der Funktion `PASSWORD()` zurückgegebenen Hash-Wert angeben wollen, schließen Sie das Schlüsselwort `PASSWORD` mit ein. Siehe auch Abschnitt 13.5.1.3, „`GRANT` und `REVOKE`“.

#### 13.5.1.2. `DROP USER`

    DROP USER user [, user] ...

Die Anweisung `DROP USER` entfernt ein oder mehrere MySQL-Konten. Sie löscht die Berechtigungsdatensätze des Kontos aus allen Grant-Tabellen. Um diese Anweisung zu verwenden, benötigen Sie die globale Berechtigung `CREATE USER` oder die Berechtigung `DELETE` für die Datenbank `mysql`. Jedes Konto wird im selben Format wie bei der `GRANT`-Anweisung benannt (z. B. `'jeffrey'@'localhost'`). Die Benutzer- und Hostbestandteile des Kontonamens entsprechen den Werten der Spalten `User` und `Host` des kontenspezifischen Datensatzes in der Tabelle `user`.

Mit `DROP USER` können Sie ein Konto und seine Berechtigungen wie folgt entfernen:

    DROP USER user;

Wichtig : `DROP USER` schließt offene Benutzersitzungen nicht automatisch. Stattdessen wird, wenn ein zu löschender Benutzer gerade eine offene Sitzung hat, die Anweisung erst umgesetzt, wenn die Sitzung dieses Benutzers beendet wurde. Sobald die Sitzung beendet ist, wird der Benutzer gelöscht: Nachfolgende Versuche des Benutzers, sich anzumelden, schlagen dann fehl. Dies ist bewusst so implementiert.

#### 13.5.1.3. `GRANT` und `REVOKE`

    GRANT priv_type [(column_list)] [, priv_type [(column_list)]] ...
        ON [object_type] {tbl_name | * | *.* | db_name.*}
        TO user [IDENTIFIED BY [PASSWORD] 'password']
            [, user [IDENTIFIED BY [PASSWORD] 'password']] ...
        [REQUIRE
            NONE |
            [{SSL| X509}]
            [CIPHER 'cipher' [AND]]
            [ISSUER 'issuer' [AND]]
            [SUBJECT 'subject']]
        [WITH with_option [with_option] ...]

    object_type =
        TABLE
      | FUNCTION
      | PROCEDURE

    with_option =
        GRANT OPTION
      | MAX_QUERIES_PER_HOUR count
      | MAX_UPDATES_PER_HOUR count
      | MAX_CONNECTIONS_PER_HOUR count
      | MAX_USER_CONNECTIONS count

Die `GRANT`-Anweisung erlaubt Systemadministratoren die Erstellung von MySQL-Benutzerkonten und die Vergabe von Rechten an diese Konten. Um `GRANT` verwenden zu können, benötigen Sie die Berechtigung `GRANT OPTION` sowie alle Berechtigungen, die Sie selbst gewähren. Die `REVOKE`-Anweisung ist in diesem Zusammenhang ebenfalls zu nennen: Sie gestattet Administratoren das Entfernen von Kontenberechtigungen. Siehe auch Abschnitt 13.5.1.5, „`REVOKE`“.

MySQL-Kontendaten sind in Tabellen der Datenbank `mysql` gespeichert. Diese Datenbank und das Zugriffssteuerungssystem sind in Kapitel 5, Datenbankverwaltung, ausführlich beschrieben. Sie finden dort weitere Informationen.

Wichtig: Einige Releases von MySQL enthalten Änderungen an der Struktur der Grant-Tabellen, damit neue Berechtigungen oder Funktionen hinzugefügt werden können. Wenn Sie ein Upgrade auf eine neue MySQL-Version durchführen, sollten Sie Ihre Grant-Tabellen aktualisieren, damit sichergestellt ist, dass diese auf der aktuellen Struktur basieren und auf diese Weise neue Funktionalitäten nutzen können. Siehe auch Abschnitt 5.6, „mysql_fix_privilege_tables — Upgrade von MySQL-Systemtabellen“.

Wenn in den Grant-Tabellen Berechtigungsdatensätze vorhanden sind, die Datenbank- oder Tabellennamen mit gemischter Groß-/Kleinschreibung enthalten, und die Systemvariable `lower_case_table_names` auf einen Nicht-Null-Wert gesetzt ist, dann können diese Berechtigungen nicht mit `REVOKE` widerrufen werden. Es ist dann erforderlich, die Grant-Tabellen direkt zu manipulieren. (`GRANT` erstellt solche Datensätze zwar nicht, wenn `lower_case_table_names` eingestellt ist, aber unter Umständen wurden derartige Datensätze bereits vor Einstellen der Variablen erstellt.)

Berechtigungen können auf unterschiedlichen Ebenen gewährt werden:

- Globale Ebene

  Globale Berechtigungen gelten für alle Datenbanken auf einem gegebenen Server. Sie werden in der Tabelle `mysql.user` gespeichert. `GRANT ALL ON *.*` und `REVOKE ALL ON *.*` gewähren bzw. widerrufen nur globale Berechtigungen.

- Datenbankebene

  Datenbankberechtigungen gelten für alle Objekte in einer gegebenen Datenbank. Sie werden in den Tabellen `mysql.db` und `mysql.host` gespeichert. `GRANT ALL ON `db_name`.*` und `REVOKE ALL ON `db_name`.*` gewähren bzw. widerrufen nur Datenbankberechtigungen.

- Tabellenebene

  Tabellenberechtigungen gelten für alle Spalten in einer gegebenen Tabelle. Sie werden in der Tabelle `mysql.tables_priv` gespeichert. `GRANT ALL ON `db_name.tbl_name`` und `REVOKE ALL ON `db_name.tbl_name`` gewähren bzw. widerrufen nur Tabellenberechtigungen.

- Spaltenebene

  Spaltenberechtigungen gelten für einzelne Spalten in einer gegebenen Tabelle. Sie werden in der Tabelle `mysql.columns_priv` gespeichert. Wenn Sie `REVOKE` verwenden, müssen Sie dieselben Spalten angeben, denen die Berechtigungen zuvor gewährt wurden.

- Routinenebene

  Die Berechtigungen `CREATE ROUTINE`, `ALTER ROUTINE`, `EXECUTE` und `GRANT` gelten für gespeicherte Routinen (Funktionen und Prozeduren). Sie können auf der globalen und der Datenbankebene gewährt werden. Ferner lassen sich diese Berechtigungen mit Ausnahme von `CREATE ROUTINE` auf Routinenebene für einzelne Routinen gewähren und werden in der Tabelle `mysql.procs_priv` gespeichert.

Die Klausel `object_type` sollte als `TABLE`, `FUNCTION` bzw. als `PROCEDURE` angegeben werden, wenn das nachfolgende Objekt eine Tabelle, eine gespeicherte Funktion oder eine gespeicherte Prozedur ist.

Für die Anweisungen `GRANT` und `REVOKE` kann `priv_type` wie folgt angegeben werden:

Berechtigung | Bedeutung
`ALL [PRIVILEGES]` | Setzt alle einfachen Berechtigungen außer `GRANT OPTION`.
`ALTER` | Erlaubt die Verwendung von `ALTER TABLE`.
`ALTER ROUTINE` | Erlaubt die Änderung oder Löschung gespeicherter Routinen.
`CREATE` | Erlaubt die Verwendung von `CREATE TABLE`.
`CREATE ROUTINE` | Erlaubt die Erstellung gespeicherter Routinen.
`CREATE TEMPORARY TABLES` | Erlaubt die Verwendung von `CREATE TEMPORARY TABLE`.
`CREATE USER` | Erlaubt die Verwendung von `CREATE USER`, `DROP USER`, `RENAME USER` und `REVOKE ALL PRIVILEGES`.
`CREATE VIEW` | Erlaubt die Verwendung von `CREATE VIEW`.
`DELETE` | Erlaubt die Verwendung von `DELETE`.
`DROP` | Erlaubt die Verwendung von `DROP TABLE`.
`EVENT` | Erlaubt die Erstellung von Ereignissen für den Ereignisplaner.
`EXECUTE` | Erlaubt dem Benutzer die Ausführung gespeicherter Routinen.
`FILE` | Erlaubt die Verwendung von `SELECT ... INTO OUTFILE` und `LOAD DATA INFILE`.
`INDEX` | Erlaubt die Verwendung von `CREATE INDEX` und `DROP INDEX`.
`INSERT` | Erlaubt die Verwendung von `INSERT`.
`LOCK TABLES` | Erlaubt die Verwendung von `LOCK TABLES` für Tabellen, für die Sie die Berechtigung `SELECT` haben.
`PROCESS` | Erlaubt die Verwendung von `SHOW FULL PROCESSLIST`.
`REFERENCES` | Nicht implementiert.
`RELOAD` | Erlaubt die Verwendung von `FLUSH`.
`REPLICATION CLIENT` | Erlaubt dem Benutzer, die Positionen von Slave- oder Master-Servern zu erfragen.
`REPLICATION SLAVE` | Für Replikationsslaves erforderlich (zum Lesen von Binärlogeinträgen auf dem Master).
`SELECT` | Erlaubt die Verwendung von `SELECT`.
`SHOW DATABASES` | `SHOW DATABASES` zeigt alle Datenbanken.
`SHOW VIEW` | Erlaubt die Verwendung von `SHOW CREATE VIEW`.
`SHUTDOWN` | Erlaubt die Verwendung von mysqladmin shutdown.
`SUPER` | Erlaubt die Verwendung der Anweisungen `CHANGE MASTER`, `KILL`, `PURGE MASTER LOGS` und `SET GLOBAL` und des Befehls mysqladmin debug. Erlaubt ferner die (einmalige) Verbindungsherstellung auch in dem Fall, dass der Wert für `max_connections` erreicht wurde.
`TRIGGER` | Erlaubt dem Benutzer das Erstellen und Löschen von Triggern.
`UPDATE` | Erlaubt die Verwendung von `UPDATE`.
`USAGE` | Synonym für „keine Berechtigungen“
`GRANT OPTION` | Erlaubt die Gewährung von Berechtigungen.

Die Berechtigungen `EVENT` und `TRIGGER` wurden in MySQL 5.1.6 hinzugefügt. Ein Trigger ist mit einer Tabelle verknüpft, d. h., um einen Trigger zu erstellen oder zu löschen, benötigen Sie die Berechtigung `TRIGGER` für die Tabelle, nicht für den Trigger. (Vor MySQL 5.1.6 war für das Erstellen und Löschen von Triggern die Berechtigung `SUPER` erforderlich.)

Die Berechtigung `REFERENCES` wird derzeit nicht benutzt.

`USAGE` kann angegeben werden, wenn Sie einen Benutzer ohne Berechtigungen erstellen wollen.

Verwenden Sie `SHOW GRANTS`, um zu bestimmen, welche Berechtigungen ein Konto hat. Siehe auch Abschnitt 13.5.4.11, „`SHOW GRANTS`“.

Sie können globale Berechtigungen mit der Syntax `ON *.*` oder Berechtigungen auf Datenbankebene mit der Syntax `ON `db_name`.*` konfigurieren. Wenn Sie `ON *` angeben und eine Standarddatenbank festgelegt haben, werden die Berechtigungen in dieser Datenbank gewährt. (Warnung: Wenn Sie `ON *` angeben und keine Standarddatenbank ausgewählt haben, werden die Berechtigungen global gewährt.)

Die Berechtigungen `FILE`, `PROCESS`, `RELOAD`, `REPLICATION CLIENT`, `REPLICATION SLAVE`, `SHOW DATABASES`, `SHUTDOWN` und `SUPER` sind administrative Berechtigungen, die nur global gewährt werden können (hierzu wird die Syntax `ON *.*` verwendet).

Andere Berechtigungen können wahlweise global oder auf individuellen Ebenen festgelegt werden.

Die `priv_type`-Werte, die Sie für eine Tabelle angeben können, sind `SELECT`, `INSERT`, `UPDATE`, `DELETE`, `CREATE`, `DROP`, `GRANT OPTION`, `INDEX`, `ALTER`, `CREATE VIEW`, `SHOW VIEW` und `TRIGGER`.

Die `priv_type`-Werte, die Sie (bei Verwendung einer `column_list`-Klausel) für eine Spalte angeben können, sind `SELECT`, `INSERT` und `UPDATE`.

Die `priv_type`-Werte, die Sie auf der Routinenebene angeben können, sind `ALTER ROUTINE`, `EXECUTE` und `GRANT OPTION`. `CREATE ROUTINE` ist keine Berechtigung auf Routinenebene, weil Sie diese Berechtigung bereits zur Erstellung einer Routine benötigen.

Auf der globalen, der Datenbank-, der Tabellen- und der Routinenebene weist `GRANT ALL` nur diejenigen Berechtigungen zu, die auf der gewährten Ebene vorhanden sind. So ist beispielsweise `GRANT ALL ON `db_name`.*` eine Anweisung auf Datenbankebene, d. h., es lassen sich hiermit keine nur auf globaler Ebene vorhandenen Berechtigungen (wie z. B. `FILE`) gewähren.

MySQL gestattet die Konfiguration von Berechtigungen auch für Datenbankobjekte, die nicht existieren. In diesen Fällen muss zu den zu gewährenden Berechtigungen auch die Berechtigung `CREATE` gehören. Dies ist bewusst so implementiert und soll es dem Datenbankadministrator gestatten, Benutzerkonten und Berechtigungen für Datenbankobjekte vorzubereiten, die erst später erstellt werden.

Wichtig: Wenn Sie eine Tabelle oder Datenbank löschen, widerruft MySQL Berechtigungen nicht automatisch. Wenn Sie allerdings eine Routine löschen, werden alle Berechtigungen auf Routinenebene widerrufen, die für diese Routine gewährt wurden.

Hinweis: Die Jokerzeichen ‘`_`’ und ‘`%`’ sind bei der Angabe von Datenbanknamen in `GRANT`-Anweisungen, die Berechtigungen auf der globalen und der Datenbankebene gewähren, zulässig. Das bedeutet beispielsweise, dass Sie, wenn Sie das Zeichen ‘`_`’ als Bestandteil eines Datenbanknamens verwenden wollen, dieses Zeichen als ‘`\_`’ in der `GRANT`-Anweisung angeben müssen, damit der Benutzer nicht auf weitere Datenbanken zugreifen kann, die dem entstandenen Muster entsprechen (z. B. `GRANT ... ON `foo\_bar`.* TO ...`).

Um das Gewähren von Rechten an Benutzer über beliebige Hosts zu gestatten, unterstützt MySQL die Angabe des `user`-Werts in der Form ``user_name`@`host_name``. Wenn ein `user_name`- oder `host_name`-Wert als vorzeichenloser Bezeichner zulässig ist, müssen Sie ihn nicht in Anführungszeichen setzen. Allerdings sind Anführungszeichen erforderlich, um einen `user_name`-String mit Sonderzeichen (z. B. ‘`-`’) oder einen `host_name`-String mit Sonder- oder Jokerzeichen (wie ‘`%`’) anzugeben. Ein Beispiel hierfür wäre `'test-user'@'test-hostname'`. Setzen Sie Benutzer- und Hostnamen separat in Anführungszeichen.

Sie können Jokerzeichen im Hostnamen verwenden. So bezeichnet etwa ``user_name`@'%.loc.gov'` jeden `user_name` auf einem beliebigen Host in der Domäne `loc.gov`, und ``user_name`@'144.155.166.%'` bezeichnet `user_name` auf einem beliebigen Host im Klasse-C-Subnetz `144.155.166`.

Die einfache Form `user_name` ist ein Synonym für ``user_name`@'%'`.

MySQL unterstützt keine Jokerzeichen in Benutzernamen. Anonyme Benutzer werden durch Einfügen von Einträgen mit `User=''` in die Tabelle `mysql.user` oder durch Erstellen eines Benutzers mit einem leeren Namen mit der `GRANT`-Anweisung definiert:

    GRANT ALL ON test.* TO ''@'localhost' ...

Wenn Sie Werte in Anführungszeichen angeben, setzen Sie Datenbank-, Tabellen-, Spalten- und Routinenamen als Bezeichner in Backticks (‘```’). Host- und Benutzernamen sowie Passwörter werden als Strings in einfache Anführungszeichen (‘`'`’) gesetzt.

Warnung: Wenn Sie anonymen Benutzern eine Verbindung zum MySQL Server gestatten wollen, sollten Sie auch allen lokalen Benutzern als ``user_name`@localhost` Berechtigungen gewähren. Andernfalls wird das anonyme Benutzerkonto für `localhost` in der Tabelle `mysql.user` verwendet, wenn benannte Benutzer versuchen, sich über das lokale System am MySQL Server anzumelden (die Tabelle wird bei der Installation von MySQL erstellt). Detaillierte Informationen finden Sie in Abschnitt 5.8.5, „Zugriffskontrolle, Phase 1: Verbindungsüberprüfung“.

Sie können feststellen, ob dies für Sie zutrifft, indem Sie die folgende Abfrage ausführen, die alle ggf. vorhandenen anonymen Benutzer auflistet:

    SELECT Host, User FROM mysql.user WHERE User='';

Wenn Sie das lokale anonyme Benutzerkonto löschen wollen, um das beschriebene Problem zu umgehen, dann verwenden Sie folgende Anweisungen:

    DELETE FROM mysql.user WHERE Host='localhost' AND User='';
    FLUSH PRIVILEGES;

`GRANT` unterstützt Hostnamen mit einer Länge von bis zu 60 Zeichen. Die Namen von Datenbanken, Tabellen, Spalten und Routinen dürfen bis zu 64 Zeichen lang sein. Benutzernamen können bis zu 16 Zeichen umfassen. Hinweis: Die zulässige Länge für Benutzernamen kann nicht durch Änderungen an der Tabelle `mysql.user` modifiziert werden. Wenn Sie dies dennoch versuchen, kann dies zu unvorhersehbaren Folgen führen, die schlimmstenfalls sogar ein Anmelden von Benutzern am MySQL Server verhindern können. Sie sollten die Tabellen in der `mysql`-Datenbank grundsätzlich nicht auf eine andere als die von MySQL AB vorgeschriebene, in Abschnitt 5.6, „mysql_fix_privilege_tables — Upgrade von MySQL-Systemtabellen“, geschilderte Weise ändern.

Die Berechtigungen für eine Tabelle, eine Spalte oder eine Routine werden kumulativ über ein logisches `OR` der Berechtigungen auf jeder der einzelnen Ebenen gebildet. Wenn die Tabelle `mysql.user` beispielsweise angibt, dass ein Benutzer die globale Berechtigung `SELECT` hat, kann ihm diese Berechtigung nicht auf der Datenbank-, der Tabellen- oder der Spaltenebene verweigert werden.

Die Berechtigungen für eine Spalte lassen sich wie folgt berechnen:

    global privileges
    OR (database privileges AND host privileges)
    OR table privileges
    OR column privileges
    OR routine privileges

In den meisten Fällen gewähren Sie einem Benutzer nur auf einer dieser Berechtigungsebenen Rechte – das Leben ist also normalerweise nicht so kompliziert. Ausführlich beschrieben wird die Überprüfung von Berechtigungen in Abschnitt 5.8, „Allgemeine Sicherheitsaspekte und das MySQL-Zugriffsberechtigungssystem“.

Wenn Sie Berechtigungen für eine Kombination aus Benutzer- und Hostnamen gewähren, die nicht in der Tabelle `mysql.user` vorhanden ist, wird ein Eintrag hinzugefügt und verbleibt dort, bis er mit einer `DELETE`-Anweisung gelöscht wird. Anders gesagt, `GRANT` kann Einträge in der Tabelle `user` erstellen; diese lassen sich aber nicht mit `REVOKE` entfernen, sondern müssen explizit mit `DROP USER` oder `DELETE` gelöscht werden.

Warnung: Wenn Sie einen neuen Benutzer ohne `IDENTIFIED BY`-Klausel erstellen, hat der Benutzer kein Passwort. Dies ist sehr unsicher. Sie können jedoch den SQL-Modus `NO_AUTO_CREATE_USER` aktivieren: Hierbei wird verhindert, dass `GRANT` Benutzer automatisch erstellt, wenn diesem nicht mit der `IDENTIFIED BY`-Klausel ein nichtleeres Passwort zugewiesen wird.

Wenn ein neuer Benutzer erstellt wird oder Sie globale Gewährungsberechtigungen haben, dann wird das Passwort des Benutzers auf das in der `IDENTIFIED BY`-Klausel gewählte Passwort gesetzt (sofern vorhanden). Hat der Benutzer bereits ein Passwort, so wird dieses durch das neue Passwort ersetzt.

Passwörter können auch mit der Anweisung `SET PASSWORD` eingestellt werden. Siehe auch Abschnitt 13.5.1.6, „`SET PASSWORD`“.

In der `IDENTIFIED BY`-Klausel sollte das Passwort als literaler Passwortwert übergeben werden. Es ist – anders als bei der `SET PASSWORD`-Anweisung – nicht erforderlich, die Funktion `PASSWORD()` zu verwenden. Zum Beispiel:

    GRANT ... IDENTIFIED BY 'mypass';

Wenn Sie das Passwort nicht unverschlüsselt senden wollen und den Hash-Wert kennen, den `PASSWORD()` für das Passwort zurückgeben würde, dann können Sie diesen Hash-Wert nach dem Schlüsselwort `PASSWORD` angeben:

    GRANT ...
    IDENTIFIED BY PASSWORD '*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF4';

In einem C-Programm können Sie den Hash-Wert mit der C-API-Funktion `make_scrambled_password()` ermitteln.

Wenn Sie Berechtigungen für eine Datenbank gewähren, wird bei Bedarf ein Eintrag in der Tabelle `mysql.db` erstellt. Wenn alle Berechtigungen für die Datenbank mit `REVOKE` entfernt werden, wird dieser Eintrag gelöscht.

Die Berechtigung `SHOW DATABASES` ermöglicht dem Konto die Anzeige von Datenbanknamen durch Absetzen einer `SHOW DATABASE`-Anweisung. Konten, die diese Berechtigung nicht haben, sehen nur solche Datenbanken, für die sie Berechtigungen haben; wurde der Server mit der Option `--skip-show-database` gestartet, dann kann die Anweisung überhaupt nicht verwendet werden.

Wenn ein Benutzer keine Berechtigungen für eine Tabelle hat, wird, wenn er (z. B. mit `SHOW TABLES`) eine Liste der Tabellen anfordert, der Name der betreffenden Tabelle nicht angezeigt.

Die `WITH GRANT OPTION`-Klausel gibt dem Benutzer die Möglichkeit, anderen Benutzern beliebige Berechtigungen zu gewähren, die der Benutzer selbst auf einer bestimmten Berechtigungsebene hat. Sie sollten bei der Vergabe der Berechtigung `GRANT OPTION` mit Umsicht vorgehen, weil zwei Benutzer mit unterschiedlichen Berechtigungen sich diese unter Umständen gegenseitig gewähren können!

Sie können einem anderen Benutzer keine Berechtigung gewähren, die Sie selbst nicht haben – mit `GRANT OPTION` können Sie nur solche Berechtigungen vergeben, über die Sie selbst auch verfügen.

Beachten Sie, dass, wenn Sie einem Benutzer die Berechtigung `GRANT OPTION` für eine bestimmte Berechtigungsebene gewähren, dieser Benutzer alle Berechtigungen, die er für diese Ebene hat (oder in Zukunft erhält), beliebig anderen Benutzern zuweisen kann. Angenommen, Sie gewähren einem Benutzer die Berechtigung `INSERT` für eine Datenbank. Wenn Sie nachfolgend die Berechtigung `SELECT` für die Datenbank gewähren und `WITH GRANT OPTION` angeben, dann kann dieser Benutzer anderen Benutzern nicht nur die Berechtigung `SELECT` gewähren, sondern auch die Berechtigung `INSERT`. Wenn Sie dann dem Benutzer die Berechtigung `UPDATE` für die Datenbank gewähren, kann der Benutzer die Berechtigungen `INSERT`, `SELECT` und `UPDATE` gewähren.

Einem nichtadministrativen Benutzer sollten Sie die Berechtigung `ALTER` weder global noch für die Datenbank `mysql` gewähren. Andernfalls kann der Benutzer das Berechtigungssystem unterlaufen, indem er Tabellen umbenennt!

Die Optionen `MAX_QUERIES_PER_HOUR `count``, `MAX_UPDATES_PER_HOUR `count`` und `MAX_CONNECTIONS_PER_HOUR `count`` begrenzen die Anzahl der Abfrage-, Update- und Anmeldevorgänge, die ein Benutzer im Verlauf einer Stunde ausführen kann. Wenn `count` `0` ist (Standardeinstellung), dann heißt das, dass für den Benutzer keine Beschränkung gilt.

Die Option `MAX_USER_CONNECTIONS `count`` schränkt die maximale Anzahl gleichzeitiger Verbindungen ein, die das Konto herstellen kann. Wenn `count` `0` ist (Standardeinstellung), dann bestimmt die Systemvariable `max_user_connections` die Anzahl gleichzeitiger Verbindungen für das Konto.

Hinweis: Um für einen vorhandenen Benutzer eine solche Option zur Ressourcenbeschränkung anzugeben, ohne vorhandene Berechtigungen einzuschränken, verwenden Sie `GRANT USAGE ON *.* ... WITH MAX_...`.

Siehe auch Abschnitt 5.9.4, „Begrenzen von Benutzer-Ressourcen“.

MySQL kann zusätzlich zur normalen, auf Benutzernamen und Passwörtern basierenden Authentifizierung Attribute von X509-Zertifikaten überprüfen. Um SSL-spezifische Optionen für ein MySQL-Konto anzugeben, verwenden Sie die `REQUIRE`-Klausel der `GRANT`-Anweisung. (Hintergrundinformationen zur Verwendung von SSL mit MySQL finden Sie in Abschnitt 5.9.7, „Verwendung sicherer Verbindungen“.)

Es gibt mehrere verschiedene Gründe zur Beschränkung der Verbindungstypen für ein gegebenes Konto:

- Wenn für das Konto keine SSL- oder X509-Anforderungen vorhanden sind, sind unverschlüsselte Verbindungen zulässig, sofern Benutzername und Passwort gültig sind. Allerdings können nach Maßgabe des Clients auch verschlüsselte Verbindungen benutzt werden, sofern der Client über die entsprechenden Zertifikats- und Schlüsseldateien verfügt.

- Die Option `REQUIRE SSL` weist den Server an, nur SSL-verschlüsselte Verbindungen für das Konto zuzulassen. Beachten Sie, dass diese Option weggelassen werden kann, wenn Zugriffssteuerungs-Datensätze vorhanden sind, die Nicht-SSL-Verbindungen zulassen.

      GRANT ALL PRIVILEGES ON test.* TO 'root'@'localhost'
        IDENTIFIED BY 'goodsecret' REQUIRE SSL;

- `REQUIRE X509` bedeutet, dass der Client ein gültiges Zertifikat vorweisen muss, dass aber das Zertifikat selbst, der Aussteller und der Zweck keine Rolle spielen. Erforderlich ist einzig und allein, dass die Signatur bei einem Zertifikat geprüft werden können muss.

      GRANT ALL PRIVILEGES ON test.* TO 'root'@'localhost'
        IDENTIFIED BY 'goodsecret' REQUIRE X509;

- `REQUIRE ISSUER '`issuer`'` schränkt Verbindungsversuche dahingehend ein, dass der Client ein gültiges X509-Zertifikat vorweisen muss, welches von der Zertifizierungsstelle `'`issuer`'` ausgestellt wurde. Wenn der Client ein Zertifikat vorweist, das zwar gültig ist, aber von einem anderen Anbieter stammt, dann weist der Server die Verbindung ab. Die Verwendung von X509-Zertifikaten impliziert immer auch eine Verschlüsselung, d. h., die Option `SSL` wird in diesem Fall nicht benötigt.

      GRANT ALL PRIVILEGES ON test.* TO 'root'@'localhost'
        IDENTIFIED BY 'goodsecret'
        REQUIRE ISSUER '/C=FI/ST=Some-State/L=Helsinki/
          O=MySQL Finland AB/CN=Tonu Samuel/Email=tonu@example.com';

  Beachten Sie, dass die `'`issuer`'`-Werte als einzelner String eingegeben werden sollten.

- `REQUIRE SUBJECT '`subject`'` schränkt Verbindungsversuche dahingehend ein, dass der Client ein gültiges X509-Zertifikat vorweisen muss, bei dem als Zweck `subject` angegeben ist. Wenn der Client ein Zertifikat vorweist, das zwar gültig ist, aber einen anderen Zweck angibt, dann weist der Server die Verbindung ab.

      GRANT ALL PRIVILEGES ON test.* TO 'root'@'localhost'
        IDENTIFIED BY 'goodsecret'
        REQUIRE SUBJECT '/C=EE/ST=Some-State/L=Tallinn/
          O=MySQL demo client certificate/
          CN=Tonu Samuel/Email=tonu@example.com';

  Beachten Sie, dass die `'`subject`'`-Werte als einzelner String eingegeben werden sollten.

- `REQUIRE CIPHER '`cipher`'` ist erforderlich, um sicherzustellen, dass Chiffren und Schlüssellängen ausreichender Stärke verwendet werden. SSL selbst kann schwach sein, wenn alte Algorithmen kurze Schlüssel zur Verschlüsselung einsetzen. Mit dieser Option können Sie die Verwendung einer bestimmten Chiffriermethode vorsehen, damit die Verbindung zulässig ist.

      GRANT ALL PRIVILEGES ON test.* TO 'root'@'localhost'
        IDENTIFIED BY 'goodsecret'
        REQUIRE CIPHER 'EDH-RSA-DES-CBC3-SHA';

Die Optionen `SUBJECT`, `ISSUER` und `CIPHER` können in der `REQUIRE`-Klausel wie folgt kombiniert werden:

    GRANT ALL PRIVILEGES ON test.* TO 'root'@'localhost'
      IDENTIFIED BY 'goodsecret'
      REQUIRE SUBJECT '/C=EE/ST=Some-State/L=Tallinn/
        O=MySQL demo client certificate/
        CN=Tonu Samuel/Email=tonu@example.com'
      AND ISSUER '/C=FI/ST=Some-State/L=Helsinki/
        O=MySQL Finland AB/CN=Tonu Samuel/Email=tonu@example.com'
      AND CIPHER 'EDH-RSA-DES-CBC3-SHA';

Das Schlüsselwort `AND` zwischen den `REQUIRE`-Optionen ist optional.

Die Reihenfolge der Optionen ist unerheblich, allerdings darf keine Option zweimal angegeben werden.

Wenn mysqld startet, werden alle Berechtigungen in den Speicher eingelesen. Detaillierte Informationen finden Sie in Abschnitt 5.8.7, „Wann Berechtigungsänderungen wirksam werden“.

Beachten Sie, dass, wenn Sie Tabellen-, Spalten- oder Routineberechtigungen auch für nur einen einzigen Benutzer verwenden, der Server die Tabellen-, Spalten- und Routineberechtigungen für alle Benutzer prüft. Dies kann MySQL ein wenig verlangsamen. Analog muss der Server, wenn Sie die Anzahl von Abfragen, Updates oder Verbindungen für Benutzer beschränken wollen, auch diese Werte überwachen.

Die wesentlichsten Unterschiede zwischen dem SQL-Standard und den MySQL-Versionen von `GRANT` sind die folgenden:

- In MySQL werden Berechtigungen mit einer Kombination aus Host- und Benutzernamen (und nicht nur mit einem Benutzernamen) verknüpft.

- Der SQL-Standard bietet keine Berechtigungen auf globaler oder Datenbankebene und unterstützt auch nicht alle von MySQL unterstützten Berechtigungstypen.

- MySQL unterstützt die Berechtigungen `TRIGGER` und `UNDER` des SQL-Standards nicht.

- Berechtigungen nach SQL-Standard sind hierarchisch strukturiert. Wenn Sie einen Benutzer entfernen, werden alle Berechtigungen widerrufen, die dieser Benutzer hatte. Dies gilt auch für MySQL, wenn Sie `DROP USER` verwenden. Siehe auch Abschnitt 13.5.1.2, „`DROP USER`“.

- Wenn Sie in Standard-SQL eine Tabelle löschen, werden alle Berechtigungen für die Tabelle widerrufen. Wenn Sie in Standard-SQL eine Berechtigung widerrufen, werden alle Berechtigungen, die basierend auf dieser Berechtigung gewährt wurden, ebenfalls widerrufen. In MySQL können Berechtigungen nur mit expliziten `REVOKE`-Anweisungen oder durch Manipulation der in den MySQL-Grant-Tabellen gespeicherten Werte gelöscht werden.

- In MySQL können `INSERT`-Berechtigungen auch für nur einige der Spalten in einer Tabelle gewährt werden. In diesem Fall können Sie `INSERT`-Anweisungen für die Tabelle trotzdem ausführen, sofern Sie diejenigen Spalten weglassen, für die Sie keine `INSERT`-Berechtigung haben. Die übergangenen Spalten können auf ihre impliziten Vorgabewerte gesetzt werden, sofern der strikte SQL-Modus nicht aktiviert ist. Im strikten Modus wird die Anweisung abgewiesen, wenn eine der übergangenen Spalten keinen Vorgabewert hat. (Der SQL-Standard sieht vor, dass Sie die `INSERT`-Berechtigung für alle Spalten benötigen.) Abschnitt 5.2.5, „Der SQL-Modus des Servers“, beschreibt den strikten Modus. Abschnitt 11.1.4, „Vorgabewerte von Datentypen“, erläutert implizite Vorgabewerte.

#### 13.5.1.4. `RENAME USER`

    RENAME USER old_user TO new_user
        [, old_user TO new_user] ...

Die `RENAME USER`-Anweisung benennt MySQL-Konten um. Um sie zu verwenden, benötigen Sie die globale Berechtigung `CREATE USER` oder die Berechtigung `UPDATE` für die Datenbank `mysql`. Ein Fehler tritt auf, wenn ein Konto mit dem alten oder neuen Namen bereits existiert. Jedes Konto wird im selben Format wie bei der `GRANT`-Anweisung benannt (z. B. `'jeffrey'@'localhost'`). Die Benutzer- und Hostbestandteile des Kontonamens entsprechen den Werten der Spalten `User` und `Host` des kontenspezifischen Datensatzes in der Tabelle `user`.

#### 13.5.1.5. `REVOKE`

    REVOKE priv_type [(column_list)] [, priv_type [(column_list)]] ...
        ON [object_type] {tbl_name | * | *.* | db_name.*}
        FROM user [, user] ...

    REVOKE ALL PRIVILEGES, GRANT OPTION FROM user [, user] ...

Die `REVOKE`-Anweisung erlaubt Systemadministratoren das Widerrufen von Berechtigungen für MySQL-Konten. Um `REVOKE` verwenden zu können, benötigen Sie die Berechtigung `GRANT OPTION` sowie alle Berechtigungen, die Sie widerrufen.

Informationen zu den Ebenen, auf denen Berechtigungen vorhanden sind, den zulässigen Werten für `priv_type` und der Syntax zur Angabe von Benutzern und Passwörtern finden Sie in Abschnitt 13.5.1.3, „`GRANT` und `REVOKE`“.

Wenn in den Grant-Tabellen Berechtigungsdatensätze vorhanden sind, die Datenbank- oder Tabellennamen mit gemischter Groß-/Kleinschreibung enthalten, und die Systemvariable `lower_case_table_names` auf einen Nicht-Null-Wert gesetzt ist, dann können diese Berechtigungen nicht mit `REVOKE` widerrufen werden. Es ist dann erforderlich, die Grant-Tabellen direkt zu manipulieren. (`GRANT` erstellt solche Datensätze zwar nicht, wenn `lower_case_table_names` eingestellt ist, aber unter Umständen wurden derartige Datensätze bereits vor Einstellen der Variablen erstellt.)

Um alle Berechtigungen zu widerrufen, verwenden Sie die folgende Syntax. Hiermit löschen Sie alle globalen Berechtigungen sowie alle Berechtigungen auf Datenbank-, Tabellen- und Spaltenebene für den oder die aufgeführten Benutzer:

    REVOKE ALL PRIVILEGES, GRANT OPTION FROM user [, user] ...

Um diese `REVOKE`-Syntax zu verwenden, benötigen Sie die globale Berechtigung `CREATE USER` oder die Berechtigung `UPDATE` für die Datenbank `mysql`.

#### 13.5.1.6. `SET PASSWORD`

    SET PASSWORD = PASSWORD('some password')
    SET PASSWORD FOR user = PASSWORD('some password')

Die Anweisung `SET PASSWORD` weist einem vorhandenen MySQL-Benutzerkonto ein Passwort zu.

Die erste Syntax stellt das Passwort für den aktuellen Benutzer ein. Ein Client, der über ein nichtanonymes Konto eine Verbindung mit dem Server hergestellt hat, kann das Passwort für dieses Konto ändern.

Die zweite Syntax stellt das Passwort für ein bestimmtes Konto auf dem aktuellen Serverhost ein. Nur Clients mit der Berechtigung `UPDATE` für die Datenbank `mysql` können dies tun. Der Wert `user` sollte im Format ``user_name`@`host_name`` angegeben werden, wobei `user_name` und `host_name` exakt so aufgeführt werden müssen, wie sie in den Spalten `User` bzw. `Host` des entsprechenden Eintrags in der Tabelle `mysql.user` notiert sind. Wenn Sie beispielsweise einen Eintrag mit den Werten `'bob'` und `'%.loc.gov'` in den Spalten `User` bzw. `Host` haben, dann würden Sie die Anweisung wie folgt schreiben:

    SET PASSWORD FOR 'bob'@'%.loc.gov' = PASSWORD('newpass');

Dies entspricht den folgenden Anweisungen:

    UPDATE mysql.user SET Password=PASSWORD('newpass')
      WHERE User='bob' AND Host='%.loc.gov';
    FLUSH PRIVILEGES;

Hinweis: Wenn Sie mit einem Clientprogramm vor Version 4.1 eine Verbindung zu einem Server unter MySQL 4.1 oder höher herstellen, verwenden Sie die obigen Anweisungen `SET PASSWORD` oder `UPDATE` erst, wenn Sie Abschnitt 5.8.9, „Kennwort-Hashing ab MySQL 4.1“, gelesen haben. Das Passwortformat wurde in MySQL 4.1 geändert, und unter bestimmten Bedingungen ist es möglich, dass Sie, wenn Sie Ihr Passwort ändern, nachfolgend keine Serververbindung mehr herstellen können.

Sie können anzeigen, unter welchem Konto der Server Sie authentifiziert hat, indem Sie `SELECT CURRENT_USER()` ausführen.

### 13.5.2. Anweisungen für die Tabellenwartung

#### 13.5.2.1. `ANALYZE TABLE`

    ANALYZE [LOCAL | NO_WRITE_TO_BINLOG] TABLE tbl_name [, tbl_name] ...

`ANALYZE TABLE` analysiert und speichert die Schlüsselverteilung für eine Tabelle. Während der Analyse ist die Tabelle mit einer Lesesperre versehen. Diese Anweisung funktioniert nur bei `MyISAM`-, `BDB`- und `InnoDB`-Tabellen. Bei `MyISAM`-Tabellen ist sie äquivalent zur Verwendung von myisamchk -a.

MySQL verwendet die gespeicherte Schlüsselverteilung, um die Reihenfolge zu ermitteln, in der die Tabellen verknüpft werden sollen, wenn Sie einen Join mit etwas anderem als einer Konstante durchführen.

`ANALYZE TABLE` gibt eine Ergebnismenge mit den folgenden Spalten zurück:

Spalte | Wert
`Table` | der Tabellenname
`Op` | ist immer `analyze`
`Msg_type` | `status`, `error`, `info` oder `warning`
`Msg_text` | die Nachricht

Sie können die gespeicherte Schlüsselverteilung mit der `SHOW INDEX`-Anweisung vergleichen. Siehe auch Abschnitt 13.5.4.12, „`SHOW INDEX`“.

Wenn die Tabelle seit der letzten `ANALYZE TABLE`-Anweisung nicht geändert wurde, wird die Tabelle nicht erneut analysiert.

`ANALYZE TABLE`-Anweisungen werden in das Binärlog geschrieben, sofern das optionale Schlüsselwort `NO_WRITE_TO_BINLOG` (oder sein Alias `LOCAL`) nicht verwendet wird. Dies wird gemacht, damit `ANALYZE TABLE`-Anweisungen, die auf einem MySQL Server verwendet werden, der als Replikationsmaster agiert, standardmäßig auf den Replikationsslave repliziert werden.

#### 13.5.2.2. `BACKUP TABLE`

    BACKUP TABLE tbl_name [, tbl_name] ... TO '/path/to/backup/directory'

Hinweis: Diese Anweisung ist veraltet. Wir arbeiten derzeit an einem besseren Ersatz, der auch die Online-Sicherung unterstützt. In der Zwischenzeit kann stattdessen das Skript mysqlhotcopy verwendet werden.

`BACKUP TABLE` kopiert die minimale Anzahl an Tabellendateien, die zur Wiederherstellung der Tabelle benötigt werden, in das Sicherungsverzeichnis, nachdem ggf. gepufferte Änderungen auf Festplatte geschrieben wurden. Die Anweisung funktioniert nur bei `MyISAM`-Tabellen. Sie kopiert die Definitionsdatei (`.frm`) und die Datendatei (`.MYD`). Die `.MYI`-Indexdatei kann aus diesen beiden Dateien neu erstellt werden. Das Verzeichnis sollte als vollständiger Pfadname angegeben werden. Um die Tabelle wiederherzustellen, verwenden Sie `RESTORE TABLE`.

Während des Backups wird für jede Tabelle für den Verlauf des Sicherungsvorgangs eine Lesesperre gehalten (d. h. immer für eine Tabelle gleichzeitig). Wenn Sie mehrere Tabellen als Momentaufnahme sichern wollen (und dabei vermeiden wollen, dass diese während der Sicherung geändert werden), setzen Sie zunächst eine `LOCK TABLES`-Anweisung ab, um eine Lesesperre für alle betreffenden Tabellen zu erwirken.

`BACKUP TABLE` gibt eine Ergebnismenge mit den folgenden Spalten zurück:

Spalte | Wert
`Table` | der Tabellenname
`Op` | ist immer `backup`
`Msg_type` | `status`, `error`, `info` oder `warning`
`Msg_text` | die Nachricht

#### 13.5.2.3. `CHECK TABLE`

    CHECK TABLE tbl_name [, tbl_name] ... [option] ...

    option = {QUICK | FAST | MEDIUM | EXTENDED | CHANGED}

`CHECK TABLE` prüft eine oder mehrere Tabellen auf Fehler. `CHECK TABLE` funktioniert bei `MyISAM`- und `InnoDB`-Tabellen. Bei `MyISAM`-Tabellen werden auch die Schlüsselstatistiken aktualisiert.

`CHECK TABLE` kann auch Views auf Probleme prüfen, z. B. in der View-Definition referenzierte Tabellen, die nicht mehr vorhanden sind.

`CHECK TABLE` gibt eine Ergebnismenge mit den folgenden Spalten zurück:

Spalte | Wert
`Table` | der Tabellenname
`Op` | ist immer `check`
`Msg_type` | `status`, `error`, `info` oder `warning`
`Msg_text` | die Nachricht

Beachten Sie, dass die Anweisung unter Umständen viele Datensätze für die überprüfte Tabelle ausgeben kann. Der letzte Datensatz hat den `Msg_type`-Wert `status`; `Msg_text` sollte normalerweise den Wert `OK` haben. Wenn Sie nicht den Wert `OK` oder aber die Meldung `Table is already up to date` erhalten, sollten Sie eine Reparatur der Tabelle durchführen. Siehe auch Abschnitt 5.10.4, „Benutzung von `myisamchk` für Tabellenwartung und Absturzreparatur“. `Table is already up to date` bedeutet, dass die Speicher-Engine für die Tabelle angegeben hat, dass es keine Notwendigkeit zur Überprüfung gibt.

Die verschiedenen Prüfoptionen, die angegeben werden können, sind in der folgenden Tabelle aufgeführt. Die Optionen dienen nur der Überprüfung von `MyISAM`-Tabellen; bei `InnoDB`-Tabellen und Views werden sie ignoriert.

Typ | Bedeutung
`QUICK` | überprüft Datensätze nicht auf falsche Verknüpfungen.
`FAST` | Überprüft nur Tabellen, die nicht ordnungsgemäß geschlossen wurden.
`CHANGED` | überprüft nur solche Tabellen, die seit der letzten Überprüfung geändert oder aber nicht korrekt geschlossen wurden.
`MEDIUM` | prüft Datensätze, um sicherzustellen, dass gelöschte Verknüpfungen gültig sind. Hierbei wird auch eine Schlüsselprüfsumme für die Datensätze berechnet, die dann mit einer berechneten Prüfsumme für die Schlüssel verglichen wird.
`EXTENDED` | führt eine vollständige Schlüsselsuche für alle Schlüssel in jedem Datensatz durch. Hierdurch wird sichergestellt, dass die Tabelle hundertprozentig konsistent ist, der Vorgang dauert aber sehr lange.

Wenn keine der Optionen `QUICK`, `MEDIUM` oder `EXTENDED` angegeben wird, wird standardmäßig `MEDIUM` als Prüftyp für dynamische `MyISAM`-Tabellen verwendet. Dies hat dieselben Auswirkungen wie die Ausführung von myisamchk --medium-check `tbl_name` für die Tabelle. Auch bei statischen `MyISAM`-Tabellen ist `MEDIUM` der Standardtyp, sofern nicht `CHANGED` oder `FAST` angegeben wurde. (In diesen Fällen ist `QUICK` der Vorgabewert.) Der Datensatzscan wird bei `CHANGED` und `FAST` übersprungen, weil die Datensätze sehr selten beschädigt sind.

Sie können Prüfoptionen auch kombinieren. Im folgenden Beispiel etwa erfolgt eine schnelle Prüfung der Tabelle, um zu ermitteln, ob sie korrekt geschlossen wurde:

    CHECK TABLE test_table FAST QUICK;

Hinweis: In manchen Fällen verändert `CHECK TABLE` die Tabelle. Dies geschieht, wenn die Tabelle als „beschädigt“ oder „nicht korrekt geschlossen“ gekennzeichnet wurde, aber `CHECK TABLE` keine Probleme in der Tabelle findet. In diesem Fall kennzeichnet `CHECK TABLE` die Tabelle als fehlerfrei.

Wenn eine Tabelle beschädigt ist, liegt das Problem wahrscheinlich bei den Indizes und nicht im Datenteil vor. Alle bislang genannten Prüftypen führen eine umfassende Indexprüfung durch und sollten aufgrund dessen die meisten Fehler finden.

Wenn Sie eine Tabelle, bei der Sie davon ausgehen, dass sie in Ordnung ist, nur sicherheitshalber überprüfen wollen, dann sollten Sie entweder keine Prüfoption oder die Option `QUICK` angeben. Letzteres sollten Sie tun, wenn Sie sehr in Eile sind und das sehr geringe Risiko in Kauf nehmen wollen, dass `QUICK` einen Fehler in der Datendatei nicht findet. (In den meisten Fällen sollte MySQL bei normaler Verwendung alle ggf. in der Datendatei vorhandenen Fehler finden. Geschieht dies, so wird die Tabelle als „beschädigt“ gekennzeichnet und kann erst wieder verwendet werden, nachdem sie repariert wurde.)

`FAST` und `CHANGED` sollen in erster Linie aus Skripten (die etwa mit cron ausgeführt werden) heraus verwendet werden, wenn Sie Ihre Tabellen von Zeit zu Zeit überprüfen wollen. In den meisten Fällen ist `FAST` `CHANGED` vorzuziehen. (Der einzige Fall, wo dies nicht zutrifft, liegt vor, wenn Sie annehmen, einen Bug im `MyISAM`-Code gefunden zu haben.)

`EXTENDED` sollte erst verwendet werden, wenn Sie bereits eine normale Überprüfung durchgeführt haben, aber immer noch merkwürdige Fehler zu einer Tabelle erhalten, sobald MySQL versucht, einen Datensatz zu aktualisieren oder einen Datensatz nach seinem Schlüssel zu finden. Die Wahrscheinlichkeit, dass so etwas nach einer normalen Überprüfung passiert, ist sehr gering.

Einige Probleme, die von `CHECK TABLE` gemeldet werden, können nicht automatisch behoben werden:

- `Found row where the auto_increment column has the value 0`.

  Das bedeutet, dass Sie einen Datensatz in der Tabelle haben, bei dem die `AUTO_INCREMENT`-Indexspalte den Wert 0 enthält. (Ein Datensatz, bei dem die `AUTO_INCREMENT`-Spalte 0 ist, kann tatsächlich erzeugt werden, indem die Spalte mit `UPDATE` explizit auf 0 gesetzt wird.)

  Dies ist an sich kein Fehler, kann aber Probleme verursachen, wenn Sie beschließen, die Tabelle zu speichern und sie dann wiederherzustellen, oder eine `ALTER TABLE`-Anweisung an die Tabelle absetzen. In diesem Fall ändert die `AUTO_INCREMENT`-Spalte ihren Wert entsprechend den Regeln für `AUTO_INCREMENT`-Spalten, was Probleme wie beispielsweise Schlüsseldubletten verursachen kann.

  Um die Warnung zu beseitigen, führen Sie einfach eine `UPDATE`-Anweisung aus, um die Spalte auf einen anderen Wert als 0 zu setzen.

#### 13.5.2.4. `CHECKSUM TABLE`

    CHECKSUM TABLE tbl_name [, tbl_name] ... [ QUICK | EXTENDED ]

`CHECKSUM TABLE` meldet eine Tabellenprüfsumme.

Bei `QUICK` wird – sofern möglich – die mitlaufende Prüfsumme gemeldet, andernfalls `NULL`. Dies ist sehr schnell. Eine mitlaufende Prüfsumme wird durch Angabe der Tabellenoption `CHECKSUM = 1` bei Erstellung der Tabelle aktiviert. Zurzeit wird dies nur bei `MyISAM`-Tabellen unterstützt. Siehe auch Abschnitt 13.1.5, „`CREATE TABLE`“.

Bei `EXTENDED` wird die gesamte Tabelle Datensatz für Datensatz gelesen und die Prüfsumme berechnet. Dies kann bei großen Tabellen sehr lange dauern.

Wenn weder `QUICK` noch `EXTENDED` angegeben sind, gibt MySQL eine mitlaufende Prüfsumme zurück, wenn die Speicher-Engine der Tabelle dies unterstützt; andernfalls wird die Tabelle gescannt.

Bei einer nichtexistenten Tabelle gibt `CHECKSUM TABLE` `NULL` zurück und erzeugt eine Warnung.

#### 13.5.2.5. `OPTIMIZE TABLE`

    OPTIMIZE [LOCAL | NO_WRITE_TO_BINLOG] TABLE tbl_name [, tbl_name] ...

`OPTIMIZE TABLE` sollte verwendet werden, wenn Sie einen umfangreichen Teil einer Tabelle gelöscht oder viele Änderungen an einer Tabelle mit Datensätzen variabler Länge (also Tabellen mit `VARCHAR`-, `VARBINARY`-, `BLOB`- oder `TEXT`-Spalten) vorgenommen haben. Gelöschte Datensätze werden zu einer verknüpften Liste hinzugefügt. Nachfolgende `INSERT`-Operationen verwenden die alten Datensatzpositionen neu. Sie können mit `OPTIMIZE TABLE` nichtverwendeten Speicher in der Tabelle freigeben und die Datendatei defragmentieren.

In den meisten Konfigurationen müssen Sie `OPTIMIZE TABLE` gar nicht ausführen. Auch wenn Sie viele Änderungen an Datensätzen variabler Länge vorgenommen haben, ist die Wahrscheinlichkeit, dass Sie dies häufiger als einmal in der Woche oder im Monat tun müssen, sehr gering – und selbst dies nur bei bestimmten Tabellen.

`OPTIMIZE TABLE` funktioniert nur bei `MyISAM`-, `BDB`- und `InnoDB`-Tabellen.

Bei `MyISAM`-Tabellen funktioniert `OPTIMIZE TABLE` wie folgt:

1. Wenn die Tabelle gelöschte oder geteilte Datensätze aufweist, wird die Tabelle repariert.

2. Wenn die Indexseiten nicht sortiert sind, werden sie sortiert.

3. Wenn die Tabellenstatistiken nicht aktuell sind (und eine Reparatur durch Sortierung des Indexes nicht erfolgreich war), werden sie aktualisiert.

Bei `BDB` wird `OPTIMIZE TABLE` zurzeit auf `ANALYZE TABLE` umgesetzt. Siehe auch Abschnitt 13.5.2.1, „`ANALYZE TABLE`“.

Bei `InnoDB` wird `OPTIMIZE TABLE` auf `ALTER TABLE` umgesetzt, wodurch die Tabelle neu erstellt wird, um Indexstatistiken zu aktualisieren und ungenutzten Speicher im Cluster-Index freizugeben.

Sie können `OPTIMIZE TABLE` auch bei anderen Speicher-Engines zum Laufen bringen, indem Sie mysqld mit den Optionen `--skip-new` oder `--safe-mode` starten. In diesem Fall wird `OPTIMIZE TABLE` einfach auf `ALTER TABLE` umgesetzt.

`OPTIMIZE TABLE` gibt eine Ergebnismenge mit den folgenden Spalten zurück:

Spalte | Wert
`Table` | der Tabellenname
`Op` | ist immer `optimize`
`Msg_type` | `status`, `error`, `info` oder `warning`
`Msg_text` | die Nachricht

Beachten Sie, dass MySQL die Tabelle während der Laufzeit von `OPTIMIZE TABLE` sperrt.

`OPTIMIZE TABLE`-Anweisungen werden in das Binärlog geschrieben, sofern das optionale Schlüsselwort `NO_WRITE_TO_BINLOG` (oder sein Alias `LOCAL`) nicht verwendet wird. Dies wird gemacht, damit `OPTIMIZE TABLE`-Anweisungen, die auf einem MySQL Server verwendet werden, der als Replikationsmaster agiert, standardmäßig auf den Replikationsslave repliziert werden.

#### 13.5.2.6. `REPAIR TABLE`

    REPAIR [LOCAL | NO_WRITE_TO_BINLOG] TABLE
        tbl_name [, tbl_name] ... [QUICK] [EXTENDED] [USE_FRM]

`REPAIR TABLE` repariert eine unter Umständen beschädigte Tabelle. Standardmäßig hat dies dieselbe Wirkung wie myisamchk --recover `tbl_name`. `REPAIR TABLE` funktioniert bei `MyISAM`- und `ARCHIVE`-Tabellen. Siehe auch Abschnitt 14.1, „Die `MyISAM`-Speicher-Engine“, und Abschnitt 14.8, „Die `ARCHIVE`-Speicher-Engine“.

Im Normalfall werden Sie diese Anweisung niemals ausführen. Im Katastrophenfall kann `REPAIR TABLE` Ihnen aber sehr wahrscheinlich alle Daten aus einer `MyISAM`-Tabelle wiederherstellen. Treten bei Ihren Tabellen häufig Beschädigungen auf, dann sollten Sie versuchen, den Grund dafür zu ermitteln, um `REPAIR TABLE` nicht mehr fortlaufend einsetzen zu müssen. Siehe auch Abschnitt A.4.2, „Was zu tun ist, wenn MySQL andauernd abstürzt“, und Abschnitt 14.1.4, „MyISAM-Tabellenprobleme“.

Warnung: Wenn sich der Server während eines `REPAIR TABLE`-Vorgangs aufhängt, ist es unabdingbar, unmittelbar nach dem Neustart eine neue `REPAIR TABLE`-Anweisung für die Tabelle abzusetzen, bevor Sie weitere Operationen an ihr vornehmen. (Es bietet sich ohnehin immer an, zuallererst ein Backup zu erstellen.) Im schlimmsten Fall haben Sie unter Umständen eine neue saubere Indexdatei ohne Informationen zur Datendatei – und könnten im nächsten Schritt möglicherweise Ihre Datendatei überschreiben! Dies ist ein unwahrscheinliches, aber durchaus mögliches Szenario.

`REPAIR TABLE` gibt eine Ergebnismenge mit den folgenden Spalten zurück:

Spalte | Wert
`Table` | der Tabellenname
`Op` | ist immer `repair`
`Msg_type` | `status`, `error`, `info` oder `warning`
`Msg_text` | die Nachricht

Die Anweisung `REPAIR TABLE` kann unter Umständen viele Datensätze für die reparierte Tabelle ausgeben. Der letzte Datensatz hat den `Msg_type`-Wert `status`; `Msg_test` sollte normalerweise den Wert `OK` haben. Wenn Sie einen anderen Status als `OK` erhalten, sollten Sie die Tabelle mit myisamchk --safe-recover zu reparieren versuchen. (`REPAIR TABLE` implementiert noch nicht alle Optionen von myisamchk. Wir beabsichtigen aber, die Anweisung in Zukunft flexibler zu gestalten.) Mit myisamchk --safe-recover können Sie auch Optionen verwenden, die `REPAIR TABLE` nicht unterstützt (z. B. `--max-record-length`).

Wenn `QUICK` angegeben wird, versucht `REPAIR TABLE`, nur den Indexbaum zu reparieren. Dieser Reparaturtyp ähnelt dem von myisamchk --recover --quick.

Wenn Sie `EXTENDED` verwenden, erstellt MySQL den Index Datensatz für Datensatz, statt einen Index gleichzeitig beim Sortieren zu erzeugen. Dieser Reparaturtyp ähnelt dem von myisamchk --safe-recover.

Es gibt auch einen Modus `USE_FRM` für `REPAIR TABLE`. Diesen verwenden Sie, wenn die `.MYI`-Indexdatei fehlt oder ihr Header beschädigt ist. In diesem Modus erstellt MySQL die `.MYI`-Datei auf der Basis der Daten aus der `.frm`-Datei neu. Diese Art der Reparatur ist mit myisamchk nicht möglich. Hinweis: Verwenden Sie diesen Modus nur, wenn Sie die regulären `REPAIR`-Modi nicht einsetzen können. Der `.MYI`-Header enthält wichtige Tabellenmetadaten (insbesondere etwa den `AUTO_INCREMENT`-Wert und `Delete link`), die bei `REPAIR ... USE_FRM` verloren gehen. Verwenden Sie `USE_FRM` nicht für eine komprimierte Tabelle, weil diese Informationen auch in der `.MYI`-Datei gespeichert sind.

`REPAIR TABLE`-Anweisungen werden in das Binärlog geschrieben, sofern das optionale Schlüsselwort `NO_WRITE_TO_BINLOG` (oder sein Alias `LOCAL`) nicht verwendet wird. Dies wird gemacht, damit `REPAIR TABLE`-Anweisungen, die auf einem MySQL Server verwendet werden, der als Replikationsmaster agiert, standardmäßig auf den Replikationsslave repliziert werden.

#### 13.5.2.7. `RESTORE TABLE`

    RESTORE TABLE tbl_name [, tbl_name] ... FROM '/path/to/backup/directory'

`RESTORE TABLE` stellt eine oder mehrere Tabellen aus einer Sicherung, die mit `BACKUP TABLE` erstellt wurde, wieder her. Vorhandene Tabellen werden nicht überschrieben: Wenn Sie versuchen, eine vorhandene Tabelle durch Wiederherstellen zu überschreiben, dann tritt ein Fehler auf. Wie `BACKUP TABLE` funktioniert auch `RESTORE TABLE` derzeit nur für `MyISAM`-Tabellen. Das Verzeichnis sollte als vollständiger Pfadname angegeben werden.

Das Backup einer Tabelle besteht aus ihrer `.frm`-Formatdatei und der `.MYD`-Datendatei. Beim Wiederherstellungsvorgang werden diese Dateien zunächst wiederhergestellt; darauf basierend wird dann die `.MYI`-Indexdatei erstellt. Die Wiederherstellung dauert länger als die Sicherung, weil die Indizes neu erstellt werden müssen. Je mehr Indizes die Tabelle hat, desto länger dauert der Vorgang.

`RESTORE TABLE` gibt eine Ergebnismenge mit den folgenden Spalten zurück:

Spalte | Wert
`Table` | der Tabellenname
`Op` | ist immer `restore`
`Msg_type` | `status`, `error`, `info` oder `warning`
`Msg_text` | die Nachricht

### 13.5.3. `SET`

    SET variable_assignment [, variable_assignment] ...

    variable_assignment:
          user_var_name = expr
        | [GLOBAL | SESSION] system_var_name = expr
        | [@@global. | @@session. | @@]system_var_name = expr

Die Anweisung `SET` weist verschiedenen Arten von Variablen, die sich auf den Betrieb des Servers oder Ihres Clients auswirken, Werte zu.

Dieser Abschnitt beschreibt die Verwendung von `SET` zur Zuweisung von Werten an System- oder Benutzervariablen. Allgemeine Informationen zu diesen Variablentypen finden Sie in Abschnitt 5.2.2, „Server-Systemvariablen“, und Abschnitt 9.3, „Benutzerdefinierte Variablen“. Eine Liste der Systemvariablen, die dynamisch zur Laufzeit geändert werden können, finden Sie in Abschnitt 5.2.3.2, „Dynamische Systemvariablen“.

Hinweis: Ältere Versionen von MySQL verwendeten `SET OPTION`. Diese Funktionalität ist jedoch veraltet – mittlerweile wird `SET` nur noch ohne `OPTION` benutzt.

Es gibt auch Varianten der `SET`-Syntax, die in anderen Kontexten verwendet werden:

- `SET PASSWORD` weist Kontenpasswörter zu. Siehe auch Abschnitt 13.5.1.6, „`SET PASSWORD`“.

- `SET TRANSACTION ISOLATION LEVEL` bestimmt die Isolierungsstufe für die Transaktionsverarbeitung. Siehe auch Abschnitt 13.4.6, „`SET TRANSACTION`“.

- `SET` wird in gespeicherten Routinen benutzt, um lokalen Routinenvariablen Werte zuzuweisen. Siehe auch Abschnitt 19.2.7.2, „Variable `SET`-Anweisung“.

Die folgende Erläuterung zeigt die verschiedenen `SET`-Syntaxen, die zur Einstellung von Variablen benutzt werden können. In den Beispielen wird jeweils der Zuweisungsoperator `=` benutzt, der Operator `:=` ist aber ebenfalls zulässig.

Eine Benutzervariable wird als `@`var_name`` geschrieben und kann wie folgt eingestellt werden:

    SET @var_name = expr;

Systemvariablen werden in `SET`-Anweisungen als `var_name` referenziert. Unter Umständen kann ihnen auch ein Modifizierer vorangestellt sein:

- Um explizit anzugeben, dass eine Variable eine globale Variable ist, stellen Sie dem Namen `GLOBAL` oder `@@global.` voran. Zum Einstellen globaler Variablen ist die Berechtigung `SUPER` erforderlich.

- Um explizit anzugeben, dass eine Variable eine Sitzungsvariable ist, stellen Sie dem Namen `SESSION` oder `@@session.` voran.

- `LOCAL` und `@@local.` sind Synonyme von `SESSION` bzw. `@@session.`.

- Ist kein Modifizierer vorhanden, dann stellt `SET` die Sitzungsvariable ein.

Ein paar Beispiele:

    SET sort_buffer_size=10000;
    SET @@local.sort_buffer_size=10000;
    SET GLOBAL sort_buffer_size=1000000, SESSION sort_buffer_size=1000000;
    SET @@sort_buffer_size=1000000;
    SET @@global.sort_buffer_size=1000000, @@local.sort_buffer_size=1000000;

Die Syntax `@@`var_name`` für Systemvariablen wird unterstützt, damit die MySQL-Syntax mit einigen anderen Datenbanksystemen kompatibel ist.

Wenn Sie mehrere Systemvariablen in derselben Anweisung einstellen, wird die zuletzt angegebene `GLOBAL`- oder `SESSION`-Option für Variablen verwendet, deren Modus nicht näher spezifiziert ist.

Wenn Sie eine sitzungsspezifische Systemvariable einstellen, bleibt der Wert gültig, bis die aktuelle Sitzung endet oder Sie der Variablen einen anderen Wert zuweisen. Stellen Sie eine globale Systemvariable ein, dann wird der Wert gespeichert und bis zum nächsten Neustart des Servers für alle neuen Verbindungen verwendet. Wenn Sie den Wert einer globalen Systemvariablen permanent ändern wollen, sollten Sie diesen in eine Optionsdatei eintragen. Siehe auch Abschnitt 4.3.2, „my.cnf-Optionsdateien“.

Um eine falsche Verwendung zu verhindern, erzeugt MySQL einen Fehler, wenn Sie `SET GLOBAL` für eine Variable verwenden, für die nur `SET SESSION` zulässig ist, oder `GLOBAL` (bzw. `@@global.`) beim Einstellen einer globalen Variablen nicht angeben.

Um eine `SESSION`-Variable auf den `GLOBAL`-Wert oder eine `GLOBAL`-Variable auf den in MySQL einkompilierten Standardwert zu setzen, verwenden Sie das Schlüsselwort `DEFAULT`. So sind beispielsweise die beiden folgenden Anweisungen dahingehend identisch, dass sie den Sitzungswert von `max_join_size` auf den globalen Wert setzen:

    SET max_join_size=DEFAULT;
    SET @@session.max_join_size=@@global.max_join_size;

Es lassen sich nicht alle Systemvariablen auf `DEFAULT` setzen. In solchen Fällen tritt bei Verwendung von `DEFAULT` ein Fehler auf.

Eine Liste der Systemvariablen und ihrer Werte zeigen Sie mit der `SHOW VARIABLES`-Anweisung an. (Siehe auch Abschnitt 13.5.4.24, „`SHOW VARIABLES`“.) Um einen bestimmten Variablennamen oder eine Liste der Namen zu erhalten, die einem Muster entsprechen, verwenden Sie eine `LIKE`-Klausel wie folgt:

    SHOW VARIABLES LIKE 'max_join_size';
    SHOW GLOBAL VARIABLES LIKE 'max_join_size';

Zum Anzeigen einer Variablenliste, deren Namen einem Muster entsprechen, verwenden Sie das Jokerzeichen ‘`%`’:

    SHOW VARIABLES LIKE '%size%';
    SHOW GLOBAL VARIABLES LIKE '%size%';

Jokerzeichen können an beliebiger Position im Vergleichsmuster stehen.

Sie können den Wert einer bestimmten Systemvariablen auch mit `SELECT` ermitteln, indem Sie die Syntax `@@[global.|session.]`var_name`` benutzen:

    SELECT @@global.max_join_size, @@session.max_join_size;

Wenn Sie eine Variable mit `SELECT @@`var_name`` (ohne Modifizierer) abrufen, gibt MySQL den `SESSION`-Wert, sofern dieser vorhanden ist, und andernfalls den `GLOBAL`-Wert zurück. (Hier liegt ein Unterschied zu `SET @@`var_name` = `value`` vor, wo immer der Sitzungswert referenziert wird.)

Die folgende Liste beschreibt Variablen, die keine Standardsyntax aufweisen oder nicht in der in Abschnitt 5.2.2, „Server-Systemvariablen“, aufgeführten Liste der Systemvariablen beschrieben sind. Zwar werden die hier beschriebenen Variablen nicht von `SHOW VARIABLES` angezeigt, Sie können die Werte aber mit `SELECT` abrufen (Ausnahmen sind `CHARACTER SET` und `SET NAMES`). Zum Beispiel:

    mysql> SELECT @@AUTOCOMMIT;
    +--------------+
    | @@AUTOCOMMIT |
    +--------------+
    |            1 |
    +--------------+

Die Groß-/Kleinschreibung dieser Optionen ist irrelevant.

- `AUTOCOMMIT = {0 | 1}`

  Stellt den Autocommit-Modus ein. Mit der Einstellung 1 werden alle Änderungen direkt übernommen. Wenn Sie 0 wählen, müssen Sie eine Transaktion mit `COMMIT` übergeben oder sie mit `ROLLBACK` abbrechen. Standardmäßig starten Clientverbindungen mit dem `AUTOCOMMIT`-Wert 1. Wenn Sie `AUTOCOMMIT` von 0 auf 1 umstellen, führt MySQL automatisch eine `COMMIT`-Anweisung für alle offenen Transaktionen aus. Eine andere Möglichkeit, eine Transaktion zu starten, besteht in der Verwendung der Anweisungen `START TRANSACTION` oder `BEGIN`. Siehe auch Abschnitt 13.4.1, „`BEGIN/COMMIT/ROLLBACK`“.

- `BIG_TABLES = {0 | 1}`

  Beim Wert 1 werden alle Temporärtabellen auf der Festplatte statt im Arbeitsspeicher abgelegt. Dies ist ein wenig langsamer, aber der Fehler `The table `tbl_name` is full` tritt nicht bei `SELECT`-Operationen auf, die eine große Temporärtabelle erfordern. Der Standardwert bei einer neuen Verbindung ist 0 (d. h., es werden speicherresidente Temporärtabellen verwendet). Im Normalfall sollten Sie diese Variable niemals umstellen müssen, da speicherresidente Tabellen nach Bedarf automatisch in festplattenbasierte Tabellen konvertiert werden. (Hinweis: Diese Variable hieß früher `SQL_BIG_TABLES`.)

- `CHARACTER SET {`charset_name` | DEFAULT}`

  Hiermit werden alle Strings vom und an den Client den Angaben entsprechend konvertiert. Sie können neue Zuordnungen angeben, indem Sie die Datei `sql/convert.cc` in der MySQL-Quelldistribution bearbeiten. `SET CHARACTER SET` stellt drei sitzungsspezifische Systemvariablen ein: `character_set_client` und `character_set_results` werden auf den angegebenen Zeichensatz gesetzt, `character_set_connection` auf den Wert von `character_set_database`. Siehe auch Abschnitt 10.4, „Verbindungszeichensatz und -sortierfolge“.

  Die Standardzuordnung kann mit dem Wert `DEFAULT` wiederhergestellt werden.

  Beachten Sie, dass die Syntax sich bei `SET CHARACTER SET` von der zur Einstellung der meisten anderen Optionen unterscheidet.

- `FOREIGN_KEY_CHECKS = {0 | 1}`

  Bei der Einstellung 1 (Vorgabe) werden Fremdschlüssel-Constraints für `InnoDB`-Tabellen überprüft. Bei der Einstellung 0 werden sie ignoriert. Die Deaktivierung der Fremdschlüsselüberprüfung kann nützlich sein, um `InnoDB`-Tabellen in einer anderen als der Reihenfolge neu zu laden, die von den Parent/Child-Beziehungen erfordert wird. Siehe auch Abschnitt 14.2.6.4, „Fremdschlüssel-Beschränkungen“.

- `IDENTITY = `value``

  Diese Variable ist synonym zur Variablen `LAST_INSERT_ID`. Sie ist aus Gründen der Kompatibilität mit anderen Datenbanksystemen vorhanden. Sie können ihren Wert mit `SELECT @@IDENTITY` auslesen und mit `SET IDENTITY` einstellen.

- `INSERT_ID = `value``

  Stellt den von der folgenden `INSERT`- oder `ALTER TABLE`-Anweisung zu verwendenden Wert ein, wenn ein `AUTO_INCREMENT`-Wert eingefügt wird. Wird in erster Linie beim Binärlog benutzt.

- `LAST_INSERT_ID = `value``

  Stellt den von `LAST_INSERT_ID()` zurückzugebenden Wert ein. Dieser wird im Binärlog gespeichert, wenn Sie `LAST_INSERT_ID()` in einer Anweisung verwenden, die eine Tabelle aktualisiert. Durch Einstellen dieser Variablen wird der von der C-API-Funktion `mysql_insert_id()` zurückgegebene Wert nicht geändert.

- `NAMES {'`charset_name`' | DEFAULT}`

  `SET NAMES` setzt die drei Systemvariablen `character_set_client`, `character_set_connection` und `character_set_results` auf den angegebenen Zeichensatz. Das Einstellen von `character_set_connection` auf `charset_name` setzt `collation_connection` auf die Standardsortierfolge für `charset_name`. Siehe auch Abschnitt 10.4, „Verbindungszeichensatz und -sortierfolge“.

  Die Standardzuordnung kann mit dem Wert `DEFAULT` wiederhergestellt werden.

  Beachten Sie, dass die Syntax sich bei `SET NAMES` von der zur Einstellung der meisten anderen Optionen unterscheidet.

- `ONE_SHOT`

  Diese Option ist ein Modifizierer und keine Variable. Sie kann verwendet werden, um die Wirkung von Variablen zu beeinflussen, die den Zeichensatz, die Sortierfolge und die Zeitzone einstellen. `ONE_SHOT` wird in erster Linie zu Replikationszwecken eingesetzt. mysqlbinlog verwendet `SET ONE_SHOT` zur vorübergehenden Änderung der Werte von Zeichensatz-, Sortierfolgen- und Zeitzonenvariablen, um die ursprünglichen Werte für einen Rollforward zu speichern.

  Sie können `ONE_SHOT` nur mit den zulässigen Variablen verwenden, andernfalls erhalten Sie einen Fehler wie den folgenden:

      mysql> SET ONE_SHOT max_allowed_packet = 1;
      ERROR 1382 (HY000): The 'SET ONE_SHOT' syntax is reserved for purposes
      internal to the MySQL server

  Wenn `ONE_SHOT` mit zulässigen Variablen benutzt wird, ändert es die Variablen nach Bedarf – jedoch nur für die nächste Anweisung, die nicht `SET` ist. Nachfolgend setzt der Server alle zeichensatz-, sortierfolgen- und zeitzonenspezifischen Systemvariablen auf ihre vorherigen Werte. Beispiel:

      mysql> SET ONE_SHOT character_set_connection = latin5;

      mysql> SET ONE_SHOT collation_connection = latin5_turkish_ci;

      mysql> SHOW VARIABLES LIKE '%_connection';
      +--------------------------+-------------------+
      | Variable_name            | Value             |
      +--------------------------+-------------------+
      | character_set_connection | latin5            |
      | collation_connection     | latin5_turkish_ci |
      +--------------------------+-------------------+

      mysql> SHOW VARIABLES LIKE '%_connection';
      +--------------------------+-------------------+
      | Variable_name            | Value             |
      +--------------------------+-------------------+
      | character_set_connection | latin1            |
      | collation_connection     | latin1_swedish_ci |
      +--------------------------+-------------------+

- `SQL_AUTO_IS_NULL = {0 | 1}`

  Bei der Einstellung 1 (Vorgabe) ermitteln Sie den zuletzt eingefügten Datensatz für eine Tabelle, die eine `AUTO_INCREMENT`-Spalte umfasst, mithilfe des folgenden Konstrukts:

      WHERE auto_increment_column IS NULL

  Dieses Verhalten wird von einigen ODBC-Programmen wie etwa Access verwendet.

- `SQL_BIG_SELECTS = {0 | 1}`

  Bei der Einstellung 0 bricht MySQL `SELECT`-Anweisungen ab, deren Ausführung voraussichtlich sehr lange dauern wird (d. h., Anweisungen, bei denen der Optimierer eine Anzahl von untersuchten Datensätzen annimmt, deren Wert `max_join_size` überschreitet. Dies ist praktisch, wenn eine nicht empfehlenswerte `WHERE`-Anweisung abgesetzt wurde. Der Standardwert für eine neue Verbindung ist 1, d. h., alle `SELECT`-Anweisungen sind zulässig.

  Wenn Sie die Systemvariable `max_join_size` auf einen anderen Wert als `DEFAULT` setzen, wird `SQL_BIG_SELECTS` auf 0 gesetzt.

- `SQL_BUFFER_RESULT = {0 | 1}`

  `SQL_BUFFER_RESULT` bewirkt, dass Ergebnisse aus `SELECT`-Anweisungen in Temporärtabellen abgelegt werden. Auf diese Weise kann MySQL die Tabellensperren schnell wieder aufheben. Die Option ist zudem in Fällen hilfreich, in denen die Übermittlung der Ergebnisse an den Client sehr lange dauert.

- `SQL_LOG_BIN = {0 | 1}`

  Bei der Einstellung 0 erfolgt für den Client keine Aufzeichnung in das Binärlog. Der Client benötigt die Berechtigung `SUPER`, um diese Option einzustellen.

- `SQL_LOG_OFF = {0 | 1}`

  Bei der Einstellung 1 erfolgt für den Client keine Aufzeichnung in das Log für allgemeine Abfragen. Der Client benötigt die Berechtigung `SUPER`, um diese Option einzustellen.

- `SQL_LOG_UPDATE = {0 | 1}`

  Diese Variable ist veraltet und wird auf `SQL_LOG_BIN` umgesetzt.

- `SQL_NOTES = {0 | 1}`

  Bei der Einstellung 1 (Standard) werden Warnungen auf `Note`-Ebene aufgezeichnet. Wird hingegen 0 gewählt, dann werden `Note`-Warnungen unterdrückt. mysqldump enthält eine Ausgabe, die diese Variable auf 0 setzt, sodass ein Neuladen der Dumpdatei keine Warnungen für Ereignisse erzeugt, die die Integrität des Neuladevorgangs nicht beeinträchtigen.

- `SQL_QUOTE_SHOW_CREATE = {0 | 1}`

  Bei der Einstellung 1 setzt der Server Bezeichner für die Anweisungen `SHOW CREATE TABLE` und `SHOW CREATE DATABASE` in Anführungszeichen. Bei 0 werden keine Anführungszeichen gesetzt. Die Option ist standardmäßig aktiviert, damit die Replikation auch bei Bezeichnern funktioniert, die Anführungszeichen erfordern. Siehe auch Abschnitt 13.5.4.6, „`SHOW CREATE TABLE`“, und Abschnitt 13.5.4.4, „`SHOW CREATE DATABASE`“.

- `SQL_SAFE_UPDATES = {0 | 1}`

  Bei der Einstellung 1 bricht MySQL `UPDATE`- und `DELETE`-Anweisungen ab, die keinen Schlüssel in der `WHERE`-Klausel oder einer `LIMIT`-Klausel verwenden. Auf diese Weise lassen sich `UPDATE`- oder `DELETE`-Anweisungen abfangen, bei denen Schlüssel nicht korrekt eingesetzt werden und die unter Umständen eine große Zahl von Datensätzen ändern oder löschen würden.

- `SQL_SELECT_LIMIT = {`value` | DEFAULT}`

  Die maximale Anzahl von Datensätzen, die von `SELECT`-Anweisungen zurückgegeben werden können. Der Standardwert bei einer neuen Verbindung lautet „unbegrenzt“. Wenn Sie den Grenzwert geändert haben, kann der Standardwert mit dem Wert `DEFAULT` für `SQL_SELECT_LIMIT` wiederhergestellt werden.

  Wenn eine `SELECT`-Anweisung eine `LIMIT`-Klausel aufweist, hat diese `LIMIT`-Klausel Vorrang vor dem Wert von `SQL_SELECT_LIMIT`.

  `SQL_SELECT_LIMIT` gilt nicht für `SELECT`-Anweisungen, die in gespeicherten Routinen ausgeführt werden. Ebenso wenig gelten sie für `SELECT`-Anweisungen, die keine Ergebnismenge erzeugen, die an den Client zurückgegeben wird. Hierzu gehören `SELECT`-Anweisungen in Unterabfragen, `CREATE TABLE ... SELECT` und `INSERT INTO ... SELECT`.

- `SQL_WARNINGS = {0 | 1}`

  Diese Variable steuert, ob `INSERT`-Anweisungen für einen Datensatz einen Informations-String erzeugen, wenn Warnungen auftreten. Die Standardeinstellung ist 0. Setzen Sie den Wert auf 1, um einen Informations-String zu generieren.

- `TIMESTAMP = {`timestamp_value` | DEFAULT}`

  Stellt die Zeit für diesen Client ein. Auf deren Basis wird der ursprüngliche Zeitstempel ermittelt, wenn Sie Datensätze mit dem Binärlog wiederherstellen. `timestamp_value` sollte ein Unix-Epochenzeitstempel und kein MySQL-Zeitstempel sein.

- `UNIQUE_CHECKS = {0 | 1}`

  Bei der Einstellung 1 (Standard) werden Eindeutigkeitsprüfungen für Sekundärindizes in `InnoDB`-Tabellen durchgeführt. Wenn der Wert 0 eingestellt wurde, werden keine Eindeutigkeitsprüfungen für Indexeinträge durchgeführt, die in den `InnoDB`-Einfügepuffer eingefügt wurden. Wenn Sie ganz sicher wissen, dass Ihre Daten keine Verstöße gegen das Eindeutigkeitsgebot enthalten, können Sie hier 0 wählen, um den Import großer Tabellen in `InnoDB` zu beschleunigen.

### 13.5.4. `SHOW`

Es gibt viele Formen von `SHOW`, die Informationen zu Datenbanken, Tabellen oder Spalten sowie Statusangaben zum Server vermitteln. In diesem Abschnitt werden die folgenden `SHOW`-Anweisungen beschrieben:

    SHOW [FULL] COLUMNS FROM tbl_name [FROM db_name] [LIKE 'pattern']
    SHOW CREATE DATABASE db_name
    SHOW CREATE FUNCTION funcname
    SHOW CREATE PROCEDURE procname
    SHOW CREATE TABLE tbl_name
    SHOW DATABASES [LIKE 'pattern']
    SHOW ENGINE engine_name {LOGS | STATUS }
    SHOW [STORAGE] ENGINES
    SHOW ERRORS [LIMIT [offset,] row_count]
    SHOW FUNCTION STATUS [LIKE 'pattern']
    SHOW GRANTS FOR user
    SHOW INDEX FROM tbl_name [FROM db_name]
    SHOW INNODB STATUS
    SHOW PROCEDURE STATUS [LIKE 'pattern']
    SHOW [BDB] LOGS
    SHOW PLUGIN
    SHOW PRIVILEGES
    SHOW [FULL] PROCESSLIST
    SHOW [GLOBAL | SESSION] STATUS [LIKE 'pattern']
    SHOW TABLE STATUS [FROM db_name] [LIKE 'pattern']
    SHOW [OPEN] TABLES [FROM db_name] [LIKE 'pattern']
    SHOW TRIGGERS
    SHOW [GLOBAL | SESSION] VARIABLES [LIKE 'pattern']
    SHOW WARNINGS [LIMIT [offset,] row_count]

Es gibt zusätzliche Formen der `SHOW`-Anweisung, die Informationen zu Replikationsmaster- und -slave-Servern vermitteln (diese werden in Abschnitt 13.6, „SQL-Befehle in Bezug auf Replikation“, beschrieben):

    SHOW BINLOG EVENTS
    SHOW MASTER LOGS
    SHOW MASTER STATUS
    SHOW SLAVE HOSTS
    SHOW SLAVE STATUS

Wenn die Syntax für eine gegebene `SHOW`-Anweisung einen `LIKE '`pattern`'`-Teil enthält, ist `'`pattern`'` ein String, der die SQL-Jokerzeichen ‘`%`’ und ‘`_`’ enthalten kann. Dieses Muster ist praktisch, um die Ausgabe der Anweisung auf passende Werte zu beschränken.

Mehrere `SHOW`-Anweisungen akzeptieren zudem eine `WHERE`-Klausel, die mehr Flexibilität bei der Angabe der anzuzeigenden Datensätze bietet. Siehe auch Abschnitt 22.22, „Erweiterungen der `SHOW`-Anweisungen“.

#### 13.5.4.1. `SHOW CHARACTER SET`

    SHOW CHARACTER SET [LIKE 'pattern']

Die Anweisung `SHOW CHARACTER SET` zeigt alle verfügbaren Zeichensätze an. Sie nimmt eine optionale `LIKE`-Klausel entgegen, die angibt, auf welche Zeichensatznamen zu prüfen ist. Zum Beispiel:

    mysql> SHOW CHARACTER SET LIKE 'latin%';
    +---------+-----------------------------+-------------------+--------+
    | Charset | Description                 | Default collation | Maxlen |
    +---------+-----------------------------+-------------------+--------+
    | latin1  | cp1252 West European        | latin1_swedish_ci |      1 |
    | latin2  | ISO 8859-2 Central European | latin2_general_ci |      1 |
    | latin5  | ISO 8859-9 Turkish          | latin5_turkish_ci |      1 |
    | latin7  | ISO 8859-13 Baltic          | latin7_general_ci |      1 |
    +---------+-----------------------------+-------------------+--------+

Die Spalte `Maxlen` zeigt die maximale Anzahl von Bytes an, die zur Speicherung eines Zeichens erforderlich sind.

#### 13.5.4.2. `SHOW COLLATION`

    SHOW COLLATION [LIKE 'pattern']

Die Ausgabe von `SHOW COLLATION` enthält alle verfügbaren Zeichensätze. Sie nimmt eine optionale `LIKE`-Klausel entgegen, bei der `pattern` angibt, auf welche Sortierfolgennamen zu prüfen ist. Zum Beispiel:

    mysql> SHOW COLLATION LIKE 'latin1%';
    +-------------------+---------+----+---------+----------+---------+
    | Collation         | Charset | Id | Default | Compiled | Sortlen |
    +-------------------+---------+----+---------+----------+---------+
    | latin1_german1_ci | latin1  |  5 |         |          |       0 |
    | latin1_swedish_ci | latin1  |  8 | Yes     | Yes      |       0 |
    | latin1_danish_ci  | latin1  | 15 |         |          |       0 |
    | latin1_german2_ci | latin1  | 31 |         | Yes      |       2 |
    | latin1_bin        | latin1  | 47 |         | Yes      |       0 |
    | latin1_general_ci | latin1  | 48 |         |          |       0 |
    | latin1_general_cs | latin1  | 49 |         |          |       0 |
    | latin1_spanish_ci | latin1  | 94 |         |          |       0 |
    +-------------------+---------+----+---------+----------+---------+

Die Spalte `Default` gibt ab, ob eine Sortierfolge standardmäßig für den Zeichensatz verwendet wird. `Compiled` zeigt an, ob der Zeichensatz in den Server einkompiliert ist. `Sortlen` schließlich bezieht sich auf die Menge des Speichers, die zum Sortieren der im Zeichensatz ausgedrückten Strings erforderlich ist.

#### 13.5.4.3. `SHOW COLUMNS`

    SHOW [FULL] COLUMNS FROM tbl_name [FROM db_name] [LIKE 'pattern']

`SHOW COLUMNS` vermittelt Informationen zu Spalten in einer Tabelle. Die Anweisung funktioniert auch bei Views.

Das Schlüsselwort `FULL` bewirkt, dass die Ausgabe ihre Berechtigungen sowie alle spaltenspezifischen Kommentare für jede Spalte enthält.

Sie können `db_name.tbl_name` als Alternative zur Syntax ``tbl_name` FROM `db_name`` verwenden. Die beiden folgenden Anweisungen sind mithin äquivalent:

    mysql> SHOW COLUMNS FROM mytable FROM mydb;
    mysql> SHOW COLUMNS FROM mydb.mytable;

`SHOW FIELDS` ist ein Synonym für `SHOW COLUMNS`. Sie können die Spalten einer Tabelle auch mit dem Befehl mysqlshow `db_name` `tbl_name` auflisten.

Die Anweisung `DESCRIBE` ermittelt ähnliche Informationen wie `SHOW COLUMNS`. Siehe auch Abschnitt 13.3.1, „`DESCRIBE` (Informationen über Spalten abrufen)“.

#### 13.5.4.4. `SHOW CREATE DATABASE`

    SHOW CREATE {DATABASE | SCHEMA} db_name

Zeigt die `CREATE DATABASE`-Anweisung an, mit der die übergebene Datenbank erstellt wurde. `SHOW CREATE SCHEMA` ist ein Synonym zu `SHOW CREATE DATABASE`.

    mysql> SHOW CREATE DATABASE test\G
    *************************** 1. row ***************************
           Database: test
    Create Database: CREATE DATABASE `test`
                     /*!40100 DEFAULT CHARACTER SET latin1 */

    mysql> SHOW CREATE SCHEMA test\G
    *************************** 1. row ***************************
           Database: test
    Create Database: CREATE DATABASE `test`
                     /*!40100 DEFAULT CHARACTER SET latin1 */

`SHOW CREATE DATABASE` setzt Tabellen- und Spaltennamen entsprechend dem Wert von `SQL_QUOTE_SHOW_CREATE` in Anführungszeichen. Siehe auch Abschnitt 13.5.3, „`SET`“.

#### 13.5.4.5. `SHOW CREATE PROCEDURE` und `SHOW CREATE FUNCTION`

    SHOW CREATE {PROCEDURE | FUNCTION} sp_name

Diese Anweisung ist eine MySQL-Erweiterung. Analog zu `SHOW CREATE TABLE` gibt sie den exakten String zurück, mit dem die genannte Routine neu erstellt werden kann.

    mysql> SHOW CREATE FUNCTION test.hello\G
    *************************** 1. row ***************************
           Function: hello
           sql_mode:
    Create Function: CREATE FUNCTION `test`.`hello`(s CHAR(20)) RETURNS CHAR(50)
    RETURN CONCAT('Hello, ',s,'!')

#### 13.5.4.6. `SHOW CREATE TABLE`

    SHOW CREATE TABLE tbl_name

Zeigt die `CREATE TABLE`-Anweisung an, mit der die übergebene Tabelle erstellt wurde. Diese Anweisung funktioniert auch bei Views.

    mysql> SHOW CREATE TABLE t\G
    *************************** 1. row ***************************
           Table: t
    Create Table: CREATE TABLE t (
      id INT(11) default NULL auto_increment,
      s char(60) default NULL,
      PRIMARY KEY (id)
    ) ENGINE=MyISAM

`SHOW CREATE TABLE` setzt Tabellen- und Spaltennamen entsprechend dem Wert von `SQL_QUOTE_SHOW_CREATE` in Anführungszeichen. Siehe auch Abschnitt 13.5.3, „`SET`“.

#### 13.5.4.7. `SHOW DATABASES`

    SHOW {DATABASES | SCHEMAS} [LIKE 'pattern']

`SHOW DATABASES` listet die Datenbanken auf dem MySQL Server-Host auf. Sofern Sie nicht über die Berechtigung `SHOW DATABASES` verfügen, werden Ihnen nur diejenigen Datenbanken angezeigt, für die Sie Berechtigungen haben. Sie können diese Liste auch mit mysqlshow anzeigen.

Wurde der Server mit der Option `--skip-show-database` gestartet, dann können Sie diese Anweisung ohne die Berechtigung `SHOW DATABASES` überhaupt nicht verwenden.

`SHOW SCHEMAS` kann ebenfalls verwendet werden.

#### 13.5.4.8. `SHOW ENGINE`

    SHOW ENGINE engine_name {LOGS | STATUS }

`SHOW ENGINE` zeigt Log- und Statusinformationen zu Speicher-Engines an. Die folgenden Anweisungen werden derzeit unterstützt:

    SHOW ENGINE BDB LOGS
    SHOW ENGINE INNODB STATUS

`SHOW ENGINE BDB LOGS` zeigt Statusinformationen zu vorhandenen `BDB`-Logdateien an. Zurückgegeben werden die folgenden Felder:

- `File`

  Der vollständige Pfad zur Logdatei.

- `Type`

  Der Logdateityp (`BDB` bei Berkeley DB-Logdateien).

- `Status`

  Der Status der Logdatei (`FREE`, wenn die Datei entfernt werden kann, oder `IN USE`, wenn die Datei vom Transaktionssubsystem benötigt wird).

`SHOW ENGINE INNODB STATUS` zeigt umfassende Informationen zum Zustand der `InnoDB`-Speicher-Engine an.

Ältere (und mittlerweile nicht mehr verwendete) Synonyme für diese Anweisungen sind `SHOW [BDB] LOGS` und `SHOW INNODB STATUS`.

#### 13.5.4.9. `SHOW ENGINES`

    SHOW [STORAGE] ENGINES

`SHOW ENGINES` zeigt Statusinformationen zu den Speicher-Engines des Servers an. Dies ist besonders nützlich, um zu überprüfen, ob eine Speicher-Engine unterstützt wird, oder um festzustellen, welche Engine standardmäßig benutzt wird. `SHOW TABLE TYPES` ist ein veraltetes Synonym.

    mysql> SHOW ENGINES\G
    *************************** 1. row ***************************
          Engine: MEMORY
         Support: YES
         Comment: Hash based, stored in memory, useful for temporary tables
    Transactions: NO
              XA: NO
      Savepoints: NO
    *************************** 2. row ***************************
          Engine: MyISAM
         Support: DEFAULT
         Comment: Default engine as of MySQL 3.23 with great performance
    Transactions: NO
              XA: NO
      Savepoints: NO
    *************************** 3. row ***************************
          Engine: InnoDB
         Support: YES
         Comment: Supports transactions, row-level locking, and foreign keys
    Transactions: YES
              XA: YES
      Savepoints: YES
    *************************** 4. row ***************************
          Engine: BerkeleyDB
         Support: YES
         Comment: Supports transactions and page-level locking
    Transactions: YES
              XA: NO
      Savepoints: NO
    *************************** 5. row ***************************
          Engine: EXAMPLE
         Support: YES
         Comment: Example storage engine
    Transactions: NO
              XA: NO
      Savepoints: NO
    *************************** 6. row ***************************
          Engine: ARCHIVE
         Support: YES
         Comment: Archive storage engine
    Transactions: NO
              XA: NO
      Savepoints: NO
    *************************** 7. row ***************************
          Engine: CSV
         Support: YES
         Comment: CSV storage engine
    Transactions: NO
              XA: NO
      Savepoints: NO
    *************************** 8. row ***************************
          Engine: BLACKHOLE
         Support: YES
         Comment: /dev/null storage engine (anything you write to it disappears)
    Transactions: NO
              XA: NO
      Savepoints: NO
    *************************** 9. row ***************************
          Engine: FEDERATED
         Support: YES
         Comment: Federated MySQL storage engine
    Transactions: NO
              XA: NO
      Savepoints: NO
    *************************** 10. row ***************************
          Engine: MRG_MYISAM
         Support: YES
         Comment: Collection of identical MyISAM tables
    Transactions: NO
              XA: NO
      Savepoints: NO

Der Wert `Support` gibt an, ob die betreffende Speicher-Engine unterstützt wird und welches die standardmäßig verwendete Engine ist. Wird der Server beispielsweise mit der Option `--default-table-type=InnoDB` gestartet, dann hat der Wert `Support` für den Datensatz `InnoDB` den Wert `DEFAULT`. Siehe auch Kapitel 14, Speicher-Engines und Tabellentypen.

Die Spalten `Transactions`, `XA` und `Savepoints` wurden in MySQL 5.1.2 hinzugefügt. Sie geben jeweils an, ob die Speicher-Engine Transaktionen, XA-Transaktionen und/oder Speicherpunkte unterstützt.

#### 13.5.4.10. `SHOW ERRORS`

    SHOW ERRORS [LIMIT [offset,] row_count]
    SHOW COUNT(*) ERRORS

Diese Anweisung ähnelt `SHOW WARNINGS`; der Unterschied besteht darin, dass statt Fehlern, Warnungen und Hinweisen lediglich Fehler angezeigt werden.

Die `LIMIT`-Klausel hat dieselbe Syntax wie bei der `SELECT`-Anweisung. Siehe auch Abschnitt 13.2.7, „`SELECT`“.

Die `SHOW COUNT(*) ERRORS`-Anweisung zeigt die Anzahl der Fehler an. Sie können diese Anzahl auch der Variablen `error_count` entnehmen:

    SHOW COUNT(*) ERRORS;
    SELECT @@error_count;

Weitere Informationen finden Sie unter Abschnitt 13.5.4.25, „`SHOW WARNINGS`“.

#### 13.5.4.11. `SHOW GRANTS`

    SHOW GRANTS FOR user

Diese Anweisung listet die `GRANT`-Anweisung(en) auf, die abgesetzt werden muss bzw. müssen, um die Berechtigungen zu kopieren, die einem MySQL-Benutzerkonto zugewiesen sind. Das Konto wird im selben Format wie bei der `GRANT`-Anweisung angegeben (z. B. `'jeffrey'@'localhost'`). Die Benutzer- und Hostbestandteile des Kontonamens entsprechen den Werten der Spalten `User` und `Host` des kontenspezifischen Datensatzes in der Tabelle `user`.

    mysql> SHOW GRANTS FOR 'root'@'localhost';
    +---------------------------------------------------------------------+
    | Grants for root@localhost                                           |
    +---------------------------------------------------------------------+
    | GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' WITH GRANT OPTION |
    +---------------------------------------------------------------------+

Um die Berechtigungen des Kontos aufzulisten, über das Sie mit dem Server verbunden sind, können Sie eine der folgenden Anweisungen verwenden:

    SHOW GRANTS;
    SHOW GRANTS FOR CURRENT_USER;
    SHOW GRANTS FOR CURRENT_USER();

`SHOW GRANTS` zeigt nur die Berechtigungen an, die dem genannten Konto explizit zugewiesen sind. Das Konto kann also über weitere Berechtigungen verfügen, die nicht aufgelistet sind. Ist beispielsweise ein anonymes Konto vorhanden, dann kann das genannte Konto dessen Berechtigungen unter Umständen nutzen; dies wird aber von `SHOW GRANTS` nicht angezeigt.

#### 13.5.4.12. `SHOW INDEX`

    SHOW INDEX FROM tbl_name [FROM db_name]

`SHOW INDEX` gibt Informationen zum Tabellenindex zurück. Das Format erinnert an das des Aufrufs `SQLStatistics` in ODBC.

`SHOW INDEX` gibt die folgenden Felder zurück:

- `Table`

  Der Name der Tabelle.

- `Non_unique`

  0, wenn der Index keine Dubletten enthalten darf, andernfalls 1.

- `Key_name`

  Der Name des Indexes.

- `Seq_in_index`

  Die Sequenznummer der Spalte im Index, beginnend bei 1.

- `Column_name`

  Der Spaltenname.

- `Collation`

  Gibt an, wie die Spalte im Index sortiert ist. In MySQL können die Werte ‘`A`’ (aufsteigend) oder `NULL` (nicht sortiert) auftreten.

- `Cardinality`

  Schätzung der Anzahl eindeutiger Werte im Index. Aktualisiert wird der Wert durch Ausführung von `ANALYZE TABLE` oder myisamchk -a. `Cardinality` wird basierend auf Statistiken gezählt, die als Integers gespeichert werden, d. h., der Wert ist auch bei kleinen Tabellen unter Umständen nicht exakt. Je höher die Kardinalität, desto größer ist die Chance, dass MySQL den Index bei der Durchführung von Joins verwendet.

- `Sub_part`

  Die Anzahl der indizierten Zeichen, wenn die Spalte nur teilweise indiziert ist, oder `NULL`, wenn die gesamte Spalte indiziert ist.

- `Packed`

  Gibt an, wie der Schlüssel gepackt ist. `NULL` zeigt an, dass der Schlüssel nicht gepackt ist.

- `Null`

  Enthält `YES`, wenn die Spalte `NULL` sein kann. Andernfalls enthält die Spalte `NO`.

- `Index_type`

  Der verwendete Indextyp (`BTREE`, `FULLTEXT`, `HASH`, `RTREE`).

- `Comment`

  Verschiedene Anmerkungen.

Sie können `db_name`.`tbl_name` als Alternative zur Syntax ``tbl_name` FROM `db_name`` verwenden. Die folgenden beiden Anweisungen sind äquivalent:

    SHOW INDEX FROM mytable FROM mydb;
    SHOW INDEX FROM mydb.mytable;

`SHOW KEYS` ist ein Synonym für `SHOW INDEX`. Sie können die Indizes einer Tabelle auch mit dem Befehl mysqlshow -k `db_name` `tbl_name` auflisten.

#### 13.5.4.13. `SHOW INNODB STATUS`

    SHOW INNODB STATUS

In MySQL 5.1 ist dies ein veraltetes Synonym für `SHOW ENGINE INNODB STATUS`. Siehe auch Abschnitt 13.5.4.8, „`SHOW ENGINE`“.

#### 13.5.4.14. `SHOW LOGS`

    SHOW [BDB] LOGS

In MySQL 5.1 ist dies ein veraltetes Synonym für `SHOW ENGINE BDB LOGS`. Siehe auch Abschnitt 13.5.4.8, „`SHOW ENGINE`“.

#### 13.5.4.15. `SHOW OPEN TABLES`

    SHOW OPEN TABLES [FROM db_name] [LIKE 'pattern']

`SHOW OPEN TABLES` listet die nichttemporären Tabellen auf, die derzeit im Tabellen-Cache geöffnet sind. Siehe auch Abschnitt 7.4.8, „Nachteile der Erzeugung großer Mengen von Tabellen in derselben Datenbank“.

`SHOW OPEN TABLES` gibt die folgenden Felder zurück:

- `Database`

  Die Datenbank, die die Tabelle enthält.

- `Table`

  Der Tabellenname.

- `In_use`

  Häufigkeit, mit der die Tabelle zurzeit von Abfragen verwendet wird. Wenn der Wert null ist, dann ist die Tabelle geöffnet, wird aber derzeit nicht verwendet.

- `Name_locked`

  Gibt an, ob der Tabellenname gesperrt ist. Die Namenssperrung wird bei Operationen wie dem Löschen oder Umbenennen von Tabellen verwendet.

#### 13.5.4.16. `SHOW PLUGIN`

    SHOW PLUGIN

`SHOW PLUGIN` zeigt Informationen zu bekannten Plug-Ins an.

    mysql> SHOW PLUGIN;
    +------------+--------+----------------+---------+
    | Name       | Status | Type           | Library |
    +------------+--------+----------------+---------+
    | MEMORY     | ACTIVE | STORAGE ENGINE | NULL    |
    | MyISAM     | ACTIVE | STORAGE ENGINE | NULL    |
    | InnoDB     | ACTIVE | STORAGE ENGINE | NULL    |
    | ARCHIVE    | ACTIVE | STORAGE ENGINE | NULL    |
    | CSV        | ACTIVE | STORAGE ENGINE | NULL    |
    | BLACKHOLE  | ACTIVE | STORAGE ENGINE | NULL    |
    | FEDERATED  | ACTIVE | STORAGE ENGINE | NULL    |
    | MRG_MYISAM | ACTIVE | STORAGE ENGINE | NULL    |
    +------------+--------+----------------+---------+

`SHOW PLUGIN` wurde in MySQL 5.1.5 hinzugefügt.

#### 13.5.4.17. `SHOW PRIVILEGES`

    SHOW PRIVILEGES

`SHOW PRIVILEGES` zeigt eine Liste mit Systemberechtigungen an, die der MySQL Server unterstützt. Wie diese Liste genau aussieht, hängt von der Version Ihres Servers ab.

    mysql> SHOW PRIVILEGES\G
    *************************** 1. row ***************************
    Privilege: Alter
    Context: Tables
    Comment: To alter the table
    *************************** 2. row ***************************
    Privilege: Alter routine
    Context: Functions,Procedures
    Comment: To alter or drop stored functions/procedures
    *************************** 3. row ***************************
    Privilege: Create
    Context: Databases,Tables,Indexes
    Comment: To create new databases and tables
    *************************** 4. row ***************************
    Privilege: Create routine
    Context: Functions,Procedures
    Comment: To use CREATE FUNCTION/PROCEDURE
    *************************** 5. row ***************************
    Privilege: Create temporary tables
    Context: Databases
    Comment: To use CREATE TEMPORARY TABLE
    ...

#### 13.5.4.18. `SHOW PROCEDURE STATUS` und `SHOW FUNCTION STATUS`

    SHOW {PROCEDURE | FUNCTION} STATUS [LIKE 'pattern']

Diese Anweisung ist eine MySQL-Erweiterung. Sie gibt Eigenschaften von Routinen zurück, z. B. Datenbank, Name, Typ und Ersteller sowie Erstellungs- und Änderungsdatum. Wird kein Muster angegeben, dann werden abhängig von der verwendeten Anweisung Informationen zu allen gespeicherten Prozeduren oder allen gespeicherten Funktionen aufgelistet.

    mysql> SHOW FUNCTION STATUS LIKE 'hello'\G
    *************************** 1. row ***************************
               Db: test
             Name: hello
             Type: FUNCTION
          Definer: testuser@localhost
         Modified: 2004-08-03 15:29:37
          Created: 2004-08-03 15:29:37
    Security_type: DEFINER
          Comment:

Sie können Informationen zu gespeicherten Routinen auch der Tabelle `ROUTINES` in `INFORMATION_SCHEMA` entnehmen. Siehe auch Abschnitt 22.14, „Die Tabelle `INFORMATION_SCHEMA ROUTINES`“.

#### 13.5.4.19. `SHOW PROCESSLIST`

    SHOW [FULL] PROCESSLIST

`SHOW PROCESSLIST` zeigt Ihnen, welche Threads gerade ausgeführt werden. Sie können diese Information auch mit mysqladmin processlist anzeigen. Wenn Sie die Berechtigung `SUPER` haben, werden alle Threads angezeigt. Andernfalls werden nur Ihre eigenen Threads (d. h. Threads, die mit dem MySQL-Benutzerkonto verknüpft sind, das Sie verwenden) angezeigt. Siehe auch Abschnitt 13.5.5.3, „`KILL`“. Wenn Sie das Schlüsselwort `FULL` nicht angeben, werden nur die ersten hundert Zeichen jeder Anweisung im Feld `Info` angezeigt.

Diese Anweisung ist recht praktisch, wenn Sie die Fehlermeldung „Too many connections“ erhalten und herausfinden wollen, was gerade passiert. MySQL reserviert eine zusätzliche Verbindung für Konten, die die Berechtigung `SUPER` haben, damit gewährleistet ist, dass Administratoren jederzeit Verbindungen herstellen können, um das System zu überprüfen. (Dies setzt natürlich voraus, dass Sie diese Berechtigung nicht allen Benutzern gewähren.)

Die Ausgabe von `SHOW PROCESSLIST` kann etwa so aussehen:

    mysql> SHOW FULL PROCESSLIST\G
    *************************** 1. row ***************************
    Id: 1
    User: system user
    Host:
    db: NULL
    Command: Connect
    Time: 1030455
    State: Waiting for master to send event
    Info: NULL
    *************************** 2. row ***************************
    Id: 2
    User: system user
    Host:
    db: NULL
    Command: Connect
    Time: 1004
    State: Has read all relay log; waiting for the slave I/O thread to update it
    Info: NULL
    *************************** 3. row ***************************
    Id: 3112
    User: replikator
    Host: artemis:2204
    db: NULL
    Command: Binlog Dump
    Time: 2144
    State: Has sent all binlog to slave; waiting for binlog to be updated
    Info: NULL
    *************************** 4. row ***************************
    Id: 3113
    User: replikator
    Host: iconnect2:45781
    db: NULL
    Command: Binlog Dump
    Time: 2086
    State: Has sent all binlog to slave; waiting for binlog to be updated
    Info: NULL
    *************************** 5. row ***************************
    Id: 3123
    User: stefan
    Host: localhost
    db: apollon
    Command: Query
    Time: 0
    State: NULL
    Info: SHOW FULL PROCESSLIST
    5 rows in set (0.00 sec)

Die Spalten haben die nachfolgend beschriebenen Bedeutungen:

- `Id`

  Der Verbindungsbezeichner.

- `User`

  Der MySQL-Benutzer, der die Anweisung abgesetzt hat. Die Anzeige `system user` bezeichnet einen clientlosen Thread, den der Server erzeugt hat, um Tasks intern zu verwalten. Es kann sich dabei um den I/O- oder den SQL-Thread, der auf dem Replikationsserver verwendet wird, oder einen Handler für verzögerte Datensätze handeln. Für den `system user` ist in der Spalte `Host` kein Host angegeben.

- `Host`

  Der Hostname des Clients, der die Anweisung absetzt (außer bei `system user`, wo kein Host angegeben wird).

  `SHOW PROCESSLIST` meldet den Hostnamen für TCP/IP-Verbindungen im Format ``host_name`:`client_port``, damit Sie schneller feststellen können, welcher Client was tut.

- `db`

  Die Standarddatenbank, sofern eine solche ausgewählt wurde; andernfalls `NULL`.

- `Command`

  Der Wert dieser Spalte entspricht den `COM_`xxx``-Befehlen des Client/Server-Protokolls. Siehe auch Abschnitt 5.2.4, „Server-Statusvariablen“.

  Der Wert `Command` kann einen der folgenden Werte haben: `Binlog Dump`, `Change user`, `Close stmt`, `Connect`, `Connect Out`, `Create DB`, `Debug`, `Delayed insert`, `Drop DB`, `Error`, `Execute`, `Fetch`, `Field List`, `Init DB`, `Kill`, `Long Data`, `Ping`, `Prepare`, `Processlist`, `Query`, `Quit`, `Refresh`, `Register Slave`, `Reset stmt`, `Set option`, `Shutdown`, `Sleep`, `Statistics`, `Table Dump`, `Time`

- `Time`

  Die Zeit (in Sekunden), die seit dem Start der Anweisung oder des Befehls bis jetzt vergangen ist.

- `State`

  Eine Aktion, ein Ereignis oder ein Zustand. Folgende Werte sind möglich: `After create`, `Analyzing`, `Changing master`, `Checking master version`, `Checking table`, `Connecting to master`, `Copying to group table`, `Copying to tmp table`, `Creating delayed handler`, `Creating index`, `Creating sort index`, `Creating table from master dump`, `Creating tmp table`, `Execution of init_command`, `FULLTEXT initialization`, `Finished reading one binlog; switching to next binlog`, `Flushing tables`, `Killed`, `Killing slave`, `Locked`, `Making temp file` , `Opening master dump table`, `Opening table`, `Opening tables`, `Processing request`, `Purging old relay logs`, `Queueing master event to the relay log`, `Reading event from the relay log`, `Reading from net`, `Reading master dump table data`, `Rebuilding the index on master dump table`, `Reconnecting after a failed binlog dump request`, `Reconnecting after a failed master event read`, `Registering slave on master`, `Removing duplicates`, `Reopen tables`, `Repair by sorting`, `Repair done`, `Repair with keycache`, `Requesting binlog dump`, `Rolling back`, `Saving state`, `Searching rows for update`, `Sending binlog event to slave`, `Sending data`, `Sorting for group`, `Sorting for order`, `Sorting index`, `Sorting result`, `System lock`, `Table lock`, `Thread initialized`, `Updating`, `User lock`, `Waiting for INSERT`, `Waiting for master to send event`, `Waiting for master update`, `Waiting for slave mutex on exit`, `Waiting for table`, `Waiting for tables`, `Waiting for the next event in relay log`, `Waiting on cond`, `Waiting to finalize termination`, `Waiting to reconnect after a failed binlog dump request`, `Waiting to reconnect after a failed master event read`, `Writing to net`, `allocating local table`, `cleaning up`, `closing tables`, `converting HEAP to MyISAM`, `copy to tmp table`, `creating table`, `deleting from main table`, `deleting from reference tables`, `discard_or_import_tablespace`, `end`, `freeing items`, `got handler lock`, `got old table`, `info`, `init`, `insert`, `logging slow query`, `login`, `preparing`, `purging old relay logs`, `query end`, `removing tmp table`, `rename`, `rename result table`, `reschedule`, `setup`, `starting slave`, `statistics`, `storing row into queue`, `update`, `updating`, `updating main table`, `updating reference tables`, `upgrading lock`, `waiting for delay_list`, `waiting for handler insert`, `waiting for handler lock`, `waiting for handler open`

  Die gängigsten `State`-Werte werden im Folgenden beschrieben. Die Mehrzahl der anderen `State`-Werte sind in erster Linie praktisch, um Bugs im Server zu finden. Weitere Informationen zu Prozesszuständen bei Replikationsservern finden Sie in Abschnitt 6.4, „Replikation: Implementationsdetails“.

  Für die `SHOW PROCESSLIST`-Anweisung ist der `State`-Wert `NULL`.

- `Info`

  Die Anweisung, die der Thread ausführt, oder `NULL`, sofern er keine Anweisung ausführt.

Einige `State`-Werte finden Sie in der Ausgabe von `SHOW PROCESSLIST` recht häufig:

- `Checking table`

  Der Thread führt eine Tabellenprüfung durch.

- `Closing tables`

  Der Thread synchronisiert die geänderten Tabellendaten auf die Festplatte und schließt die verwendeten Tabellen. Dies sollte ein sehr schneller Vorgang sein. Andernfalls sollten Sie überprüfen, ob Ihre Festplatte nicht voll ist oder stark frequentiert wird.

- `Connect Out`

  Ein Replikationsslave stellt eine Verbindung zum Master her.

- `Copying to tmp table`

  Der Server kopiert Daten in eine Temporärtabelle im Speicher.

- `Copying to tmp table on disk`

  Der Server kopiert Daten in eine Temporärtabelle auf die Festplatte. Die temporäre Ergebnismenge war größer als `tmp_table_size`, und der Thread stellt die Temporärtabelle deswegen vom speicherresidenten in das festplattenbasierte Format um, um Speicher zu sparen.

- `Creating tmp table`

  Der Thread erstellt eine Temporärtabelle, die einen Teil des Abfrageergebnisses aufnehmen soll.

- `deleting from main table`

  Der Server führt den ersten Teil eines Löschvorgangs über mehrere Tabellen aus. Der Löschvorgang erfolgt nur in der ersten Tabelle und speichert Felder und Offsets, die zum Löschen aus anderen (Referenz-)Tabellen benutzt werden.

- `deleting from reference tables`

  Der Server führt den zweiten Teil eines Löschvorgangs über mehrere Tabellen aus und löscht die entsprechenden Datensätze aus anderen Tabellen.

- `Flushing tables`

  Der Thread führt `FLUSH TABLES` aus und wartet, bis alle Threads ihre Tabellen geschlossen haben.

- `FULLTEXT initialization`

  Der Server bereitet die Ausführung einer natursprachlichen Volltextsuche vor.

- `Killed`

  Jemand hat eine `KILL`-Anweisung an den Thread abgesetzt. Der Thread wird abgebrochen, wenn beim nächsten Mal das Terminierungs-Flag gesetzt wird. Dieses Flag wird in jeder größeren Schleife in MySQL gesetzt. Trotzdem kann es unter Umständen einen Moment dauern, bis der Thread terminiert ist. Ist der Thread durch einen anderen Thread gesperrt, dann erfolgt die Terminierung erst, wenn der andere Thread die Sperre aufgehoben hat.

- `Locked`

  Die Abfrage wird durch eine andere Abfrage gesperrt.

- `Sending data`

  Der Thread verarbeitet Datensätze für eine `SELECT`-Anweisung und sendet zudem Daten an den Client.

- `Sorting for group`

  Der Thread führt eine Sortierung infolge einer `GROUP BY`-Klausel durch.

- `Sorting for order`

  Der Thread führt eine Sortierung infolge einer `ORDER BY`-Klausel durch.

- `Opening tables`

  Der Thread versucht, eine Tabelle zu öffnen. Dies sollte ein sehr schneller Vorgang sein, sofern das Öffnen nicht durch irgendeinen Umstand verhindert wird. So kann beispielsweise eine `ALTER TABLE`- oder eine `LOCK TABLE`-Anweisung das Öffnen einer Tabelle bis zum Abschluss der Anweisung unterbinden.

- `Reading from net`

  Der Server liest ein Paket aus dem Netzwerk.

- `Removing duplicates`

  Die Abfrage verwendete `SELECT DISTINCT` so, dass MySQL die `DISTINCT`-Operation nicht zu einem frühen Zeitpunkt wegoptimieren konnte. Aus diesem Grund erfordert MySQL eine zusätzliche Phase, um alle duplizierten Datensätze zu entfernen, bevor das Ergebnis an den Client gesendet wird.

- `Reopen table`

  Der Thread hat eine Sperre für die Tabelle erwirkt, danach aber festgestellt, dass die zugrunde liegende Tabellenstruktur sich geändert hat. Der Thread hat die Sperre dann aufgehoben und die Tabelle geschlossen und versucht nun, sie wieder zu öffnen.

- `Repair by sorting`

  Der Reparaturcode verwendet einen Sortiervorgang zur Erstellung der Indizes.

- `Repair with keycache`

  Der Reparaturcode erstellt einen Schlüssel nach dem anderen über den Schlüssel-Cache. Dies ist wesentlich langsamer als `Repair by sorting`.

- `Searching rows for update`

  Der Thread durchläuft die erste Phase zur Suche nach passenden Datensätzen, bevor er sie aktualisiert. Dies muss getan werden, wenn `UPDATE` den Index ändert, der für die Suche nach den betreffenden Datensätzen verwendet wird.

- `Sleeping`

  Der Thread wartet darauf, dass der Client eine neue Anweisung an ihn sendet.

- `statistics`

  Der Server berechnet Statistiken zur Entwicklung eines Abfrageausführungsplans.

- `System lock`

  Der Thread wartet darauf, eine externe Systemsperre für die Tabelle zu erhalten. Wenn Sie nicht mehrere mysqld-Server verwenden, die auf die gleichen Tabellen zugreifen, können Sie Systemsperren mit der Option `--skip-external-locking` deaktivieren.

- `Upgrading lock`

  Der Handler `INSERT DELAYED` versucht, eine Sperre für die Tabelle zu erwirken, um Datensätze einzufügen.

- `Updating`

  Der Thread sucht nach zu aktualisierenden Datensätzen und aktualisiert diese dann.

- `updating main table`

  Der Server führt den ersten Teil eines Änderungsvorgangs über mehrere Tabellen aus. Er führt Änderungen nur in der ersten Tabelle aus und speichert Felder und Offsets, die zur Aktualisierung anderer (Referenz-)Tabellen benutzt werden.

- `updating reference tables`

  Der Server führt den zweiten Teil eines Änderungsvorgangs über mehrere Tabellen aus und aktualisiert die entsprechenden Datensätze in den anderen Tabellen.

- `User Lock`

  Der Thread wartet auf ein `GET_LOCK()`.

- `Waiting for tables`

  Der Thread hat eine Mitteilung erhalten, dass die einer Tabelle zugrunde liegende Struktur sich geändert hat und er die Tabelle neu öffnen muss, um die neue Struktur zu erhalten. Um die Tabelle allerdings neu öffnen zu können, muss er warten, bis alle anderen Threads die fragliche Tabelle geschlossen haben.

  Diese Benachrichtigung erfolgt, wenn ein anderer Thread `FLUSH TABLES` oder eine der folgenden Anweisungen für die betreffende Tabelle verwendet hat: `FLUSH TABLES `tbl_name``, `ALTER TABLE`, `RENAME TABLE`, `REPAIR TABLE`, `ANALYZE TABLE` oder `OPTIMIZE TABLE`.

- `waiting for handler insert`

  Der `INSERT DELAYED`-Handler hat alle anhängigen Einfügeoperationen verarbeitet und wartet auf neue.

- `Writing to net`

  Der Server schreibt ein Paket in das Netzwerk.

Die meisten Zustände entsprechen sehr schnellen Operationen. Wenn ein Thread für mehrere Sekunden in einem dieser Zustände verbleibt, dann weist dies auf ein Problem hin, das untersucht werden muss.

#### 13.5.4.20. `SHOW STATUS`

    SHOW [GLOBAL | SESSION] STATUS [LIKE 'pattern']

`SHOW STATUS` zeigt Serverstatusinformationen an. Diese Informationen können auch mit dem Befehl mysqladmin extended-status ermittelt werden.

Nachfolgend ist auszugsweise eine Ausgabe aufgelistet. Die Liste der Variablen und ihrer Werte kann auf Ihrem Server anders aussehen. Die Bedeutung der Variablen ist in Abschnitt 5.2.4, „Server-Statusvariablen“, beschrieben.

    mysql> SHOW STATUS;
    +--------------------------+------------+
    | Variable_name            | Value      |
    +--------------------------+------------+
    | Aborted_clients          | 0          |
    | Aborted_connects         | 0          |
    | Bytes_received           | 155372598  |
    | Bytes_sent               | 1176560426 |
    | Connections              | 30023      |
    | Created_tmp_disk_tables  | 0          |
    | Created_tmp_tables       | 8340       |
    | Created_tmp_files        | 60         |
    ...
    | Open_tables              | 1          |
    | Open_files               | 2          |
    | Open_streams             | 0          |
    | Opened_tables            | 44600      |
    | Questions                | 2026873    |
    ...
    | Table_locks_immediate    | 1920382    |
    | Table_locks_waited       | 0          |
    | Threads_cached           | 0          |
    | Threads_created          | 30022      |
    | Threads_connected        | 1          |
    | Threads_running          | 1          |
    | Uptime                   | 80380      |
    +--------------------------+------------+

Mit einer `LIKE`-Klausel zeigt die Anweisung nur die Variablen an, die dem Muster entsprechen:

    mysql> SHOW STATUS LIKE 'Key%';
    +--------------------+----------+
    | Variable_name      | Value    |
    +--------------------+----------+
    | Key_blocks_used    | 14955    |
    | Key_read_requests  | 96854827 |
    | Key_reads          | 162040   |
    | Key_write_requests | 7589728  |
    | Key_writes         | 3813196  |
    +--------------------+----------+

Wenn die Option `GLOBAL` angegeben wird, erhalten Sie die Statuswerte für alle Verbindungen zu MySQL. Bei `SESSION` erhalten Sie hingegen die Statuswerte der aktuellen Verbindung. Geben Sie überhaupt keine Option an, dann wird `SESSION` als Vorgabe verwendet. `LOCAL` ist ein Synonym für `SESSION`.

Einige Statusvariablen haben nur einen globalen Wert. Bei diesen erhalten Sie denselben Wert sowohl für `GLOBAL` als auch für `SESSION`.

#### 13.5.4.21. `SHOW TABLE STATUS`

    SHOW TABLE STATUS [FROM db_name] [LIKE 'pattern']

`SHOW TABLE STATUS` funktioniert wie `SHOW TABLE`, vermittelt aber zahlreiche Informationen zu den einzelnen Tabellen. Sie können diese Liste auch mit mysqlshow --status `db_name` anzeigen.

Diese Anweisung erlaubt auch die Anzeige von Informationen zu Views.

`SHOW TABLE STATUS` gibt die folgenden Felder zurück:

- `Name`

  Den Namen der Tabelle.

- `Engine`

  Die Speicher-Engine der Tabelle. Siehe auch Kapitel 14, Speicher-Engines und Tabellentypen. Vor MySQL 4.1.2 hieß dieser Wert `Type`.

- `Version`

  Die Versionsnummer der `.frm`-Datei der Tabelle.

- `Row_format`

  Das Format für die Datensatzspeicherung (`Fixed`, `Dynamic`, `Compressed`, `Redundant`, `Compact`). Das Format von `InnoDB`-Tabellen wird als `Redundant` oder `Compact` gemeldet.

- `Rows`

  Anzahl der Datensätze. Einige Speicher-Engines wie etwa `MyISAM` speichern die exakte Anzahl.

  Bei anderen Engines wie `InnoDB` hingegen ist dies ein Schätzwert, der vom tatsächlichen Wert um bis zu 40 oder 50 Prozent abweichen kann. In solchen Fällen sollten Sie mit `SELECT COUNT(*)` eine exakte Anzahl ermitteln.

  Der `Rows`-Wert ist `NULL` bei Tabellen in der Datenbank `INFORMATION_SCHEMA`.

- `Avg_row_length`

  Durchschnittliche Länge eines Datensatzes.

- `Data_length`

  Die Länge der Datendatei.

- `Max_data_length`

  Die maximale Länge der Datendatei. Dies ist die Gesamtzahl der Bytes, die in der Tabelle gespeichert werden können. Sie wird auf der Basis der verwendeten Zeigergröße berechnet.

- `Index_length`

  Die Länge der Indexdatei.

- `Data_free`

  Anzahl der reservierten, aber nicht verwendeten Bytes.

- `Auto_increment`

  Der nächste `AUTO_INCREMENT`-Wert.

- `Create_time`

  Zeitpunkt der Tabellenerstellung.

- `Update_time`

  Zeitpunkt der letzten Aktualisierung der Datendatei.

- `Check_time`

  Zeitpunkt der letzten Tabellenüberprüfung. Nicht alle Speicher-Engines aktualisieren diese Zeitangabe (in solchen Fällen ist der Wert stets `NULL`).

- `Collation`

  Zeichensatz und Sortierung der Tabelle.

- `Checksum`

  Wert der mitlaufenden Prüfsumme (sofern vorhanden).

- `Create_options`

  Zusätzliche Optionen, die bei `CREATE TABLE` angegeben wurden.

- `Comment`

  Bei der Erstellung der Tabelle angegebener Kommentar (oder Angaben dazu, warum MySQL nicht auf die Tabellendaten zugreifen konnte).

Im Tabellenkommentar meldet `InnoDB` den freien Speicher des Tablespaces, zu dem die Tabelle gehört. Bei einer Tabelle, die sich in einem gemeinsamen Tablespace befindet, ist dies der freie Speicher des gemeinsamen Tablespaces. Verwenden Sie mehrere Tablespaces und hat die Tabelle einen eigenen Tablespace, dann bezieht sich die Angabe des freien Speichers nur auf diese Tabelle.

Bei `MEMORY`-Tabellen geben die Werte `Data_length`, `Max_data_length` und `Index_length` näherungsweise die tatsächliche Menge des reservierten Speichers an. Der Reservierungsalgorithmus reserviert in großem Umfang Speicher, um die Anzahl der Reservierungsoperationen zu verringern.

Bei `NDB Cluster`-Tabellen zeigt die Ausgabe dieser Anweisung annähernde Werte für die Spalten `Avg_row_length` und `Data_length`. Ausgenommen sind lediglich `BLOB`-Spalten, die nicht berücksichtigt werden. Außerdem wird die Anzahl der Repliken in der `Comment`-Spalte (als `number_of_replicas`) angegeben.

Bei Views sind alle von `SHOW TABLE STATUS` angezeigten Felder `NULL`; lediglich `Name` zeigt den Namen des Views an, und `Comment` enthält `view`.

#### 13.5.4.22. `SHOW TABLES`

    SHOW [FULL] TABLES [FROM db_name] [LIKE 'pattern']

`SHOW TABLES` listet alle nichttemporären Tabellen in einer gegebenen Datenbank auf. Sie können diese Liste auch mit mysqlshow `db_name` anzeigen.

Die Anweisung listet außerdem alle Views in der Datenbank auf. Der Modifizierer `FULL` wird dahingehend unterstützt, dass `SHOW FULL TABLES` eine zweite Ausgabespalte anzeigt. Werte der zweiten Spalte sind `BASE TABLE` bei einer Tabelle und `VIEW` bei einem View.

Hinweis: Wenn Sie keine Berechtigungen für eine Tabelle haben, dann erscheint diese nicht in der Ausgabe von `SHOW TABLES` oder mysqlshow db_name.

#### 13.5.4.23. `SHOW TRIGGERS`

    SHOW TRIGGERS [FROM db_name] [LIKE expr]

`SHOW TRIGGERS` listet die derzeit auf dem MySQL Server definierten Trigger auf. Diese Anweisung erfordert die Berechtigung `SUPER`.

Für den Trigger `ins_sum`, wie er in Abschnitt 20.3, „Verwendung von Triggern“, definiert ist, sieht die Ausgabe der Anweisung wie folgt aus:

    mysql> SHOW TRIGGERS LIKE 'acc%'\G
    *************************** 1. row ***************************
      Trigger: ins_sum
        Event: INSERT
        Table: account
    Statement: SET @sum = @sum + NEW.amount
       Timing: BEFORE
      Created: NULL
     sql_mode:
      Definer: myname@localhost

Hinweis: Wenn Sie eine `LIKE`-Klausel mit `SHOW TRIGGERS` verwenden, wird der zu prüfende Ausdruck `expr` mit dem Namen der Tabelle verglichen, für die der Trigger deklariert wurde, und nicht mit dem Namen des Triggers:

    mysql> SHOW TRIGGERS LIKE 'ins%';
    Empty set (0.01 sec)

Es folgt eine kurze Erläuterung der Spalten in der Ausgabe der Anweisung:

- `Trigger`

  Der Name des Triggers.

- `Event`

  Das Ereignis, welches die Trigger-Aktivierung ausgelöst hat: `'INSERT'`, `'UPDATE'` oder `'DELETE'`.

- `Table`

  Die Tabelle, für die der Trigger definiert ist.

- `Statement`

  Die bei Aktivierung des Triggers auszuführende Anweisung. Diese entspricht dem Text in der Spalte `ACTION_STATEMENT` von `INFORMATION_SCHEMA.TRIGGERS`.

- `Timing`

  Einer der beiden Werte `'BEFORE'` oder `'AFTER'`.

- `Created`

  Der Wert dieser Spalte ist zurzeit immer `NULL`.

- `sql_mode`

  Der bei der Ausführung des Triggers gültige SQL-Modus.

- `Definer`

  Das Konto, welches den Trigger erstellt hat.

Siehe auch Abschnitt 22.16, „Die Tabelle `INFORMATION_SCHEMA TRIGGERS`“.

#### 13.5.4.24. `SHOW VARIABLES`

    SHOW [GLOBAL | SESSION] VARIABLES [LIKE 'pattern']

`SHOW VARIABLES` zeigt den Wert einiger MySQL-Systemvariablen. Diese Informationen können auch mit dem Befehl mysqladmin variables ermittelt werden.

Mit der Option `GLOBAL` erhalten Sie die Werte, die für neue Verbindungen mit MySQL verwendet werden. Mit `SESSION` erhalten Sie hingegen die für die aktuelle Verbindung gültigen Werte. Geben Sie überhaupt keine Option an, dann wird `SESSION` als Vorgabe verwendet. `LOCAL` ist ein Synonym für `SESSION`.

Sind die Standardwerte ungeeignet, dann können Sie die meisten dieser Variablen beim Start von mysqld mit Befehlsoptionen oder zur Laufzeit mit der `SET`-Anweisung einstellen. Siehe auch Abschnitt 5.2.1, „Befehlsoptionen für mysqld“, und Abschnitt 13.5.3, „`SET`“.

Nachfolgend ist auszugsweise eine Ausgabe aufgelistet. Die Liste der Variablen und ihrer Werte kann auf Ihrem Server anders aussehen. Abschnitt 5.2.2, „Server-Systemvariablen“, beschreibt die Bedeutung der einzelnen Variablen. Informationen zu ihrer Optimierung finden Sie in Abschnitt 7.5.2, „Serverparameter feineinstellen“.

    mysql> SHOW VARIABLES;
    +---------------------------------+---------------------------+
    | Variable_name                   | Value                     |
    +---------------------------------+---------------------------+
    | auto_increment_increment        | 1                         |
    | auto_increment_offset           | 1                         |
    | automatic_sp_privileges         | ON                        |
    | back_log                        | 50                        |
    | basedir                         | /home/jon/bin/mysql-5.1/  |
    | binlog_cache_size               | 32768                     |
    | bulk_insert_buffer_size         | 8388608                   |
    | character_set_client            | latin1                    |
    | character_set_connection        | latin1                    |
    ...
    | max_user_connections            | 0                         |
    | max_write_lock_count            | 4294967295                |
    | multi_range_count               | 256                       |
    | myisam_data_pointer_size        | 6                         |
    | myisam_max_sort_file_size       | 2147483647                |
    | myisam_recover_options          | OFF                       |
    | myisam_repair_threads           | 1                         |
    | myisam_sort_buffer_size         | 8388608                   |
    | ndb_autoincrement_prefetch_sz   | 32                        |
    | ndb_cache_check_time            | 0                         |
    | ndb_force_send                  | ON                        |
    ...
    | time_zone                       | SYSTEM                    |
    | timed_mutexes                   | OFF                       |
    | tmp_table_size                  | 33554432                  |
    | tmpdir                          |                           |
    | transaction_alloc_block_size    | 8192                      |
    | transaction_prealloc_size       | 4096                      |
    | tx_isolation                    | REPEATABLE-READ           |
    | updatable_views_with_limit      | YES                       |
    | version                         | 5.1.6-alpha-log           |
    | version_comment                 | Source distribution       |
    | version_compile_machine         | i686                      |
    | version_compile_os              | suse-linux                |
    | wait_timeout                    | 28800                     |
    +---------------------------------+---------------------------+

Mit einer `LIKE`-Klausel zeigt die Anweisung nur die Variablen an, die dem Muster entsprechen:

    mysql> SHOW VARIABLES LIKE 'have%';
    +-----------------------+----------+
    | Variable_name         | Value    |
    +-----------------------+----------+
    | have_archive          | YES      |
    | have_bdb              | NO       |
    | have_blackhole_engine | YES      |
    | have_compress         | YES      |
    | have_crypt            | YES      |
    | have_csv              | YES      |
    | have_example_engine   | NO       |
    | have_federated_engine | NO       |
    | have_geometry         | YES      |
    | have_innodb           | YES      |
    | have_isam             | NO       |
    | have_ndbcluster       | DISABLED |
    | have_openssl          | NO       |
    | have_partitioning     | YES      |
    | have_query_cache      | YES      |
    | have_raid             | NO       |
    | have_rtree_keys       | YES      |
    | have_symlink          | YES      |
    +-----------------------+----------+

#### 13.5.4.25. `SHOW WARNINGS`

    SHOW WARNINGS [LIMIT [offset,] row_count]
    SHOW COUNT(*) WARNINGS

`SHOW WARNINGS` zeigt die Fehler-, Warnungs- und Hinweismeldungen, die durch die zuletzt abgesetzte Anweisung ausgegeben wurden. Hat diese Anweisung keine Meldungen erzeugt, so ist die Ausgabe leer. Die verwandte Anweisung `SHOW ERRORS` zeigt nur die Fehler an. Siehe auch Abschnitt 13.5.4.10, „`SHOW ERRORS`“.

Die Liste der Meldungen wird bei jeder neuen Anweisung, die eine Tabelle verwendet, zurückgesetzt.

Die `SHOW COUNT(*) WARNINGS`-Anweisung zeigt die Gesamtanzahl der Fehler, Warnungen und Hinweise an. Sie können diese Anzahl auch der Variablen `warning_count` entnehmen:

    SHOW COUNT(*) WARNINGS;
    SELECT @@warning_count;

Der Wert von `warning_count` kann größer sein als die Anzahl der von `SHOW WARNINGS` angezeigten Meldungen. Dies liegt dann daran, dass die Systemvariable `max_error_count` so niedrig angesetzt ist, dass nicht alle Meldungen gespeichert werden. Ein weiter unten in diesem Anschnitt gezeigtes Beispiel veranschaulicht, wie dies geschehen kann.

Die `LIMIT`-Klausel hat dieselbe Syntax wie bei der `SELECT`-Anweisung. Siehe auch Abschnitt 13.2.7, „`SELECT`“.

Der MySQL Server sendet die Gesamtanzahl der Fehler, Warnungen und Hinweise zurück, die aufgrund der letzten Anweisung erzeugt wurden. Wenn Sie die C-API verwenden, lässt sich dieser Wert durch einen Aufruf von `mysql_warning_count()` ermitteln. Siehe auch Abschnitt 24.2.3.69, „`mysql_warning_count()`“.

Warnungen werden für Anweisungen wie `LOAD DATA INFILE` und DML-Anweisungen wie `INSERT`, `UPDATE`, `CREATE TABLE` und `ALTER TABLE` erzeugt.

Die folgende `DROP TABLE`-Anweisung erzeugt einen Hinweis:

    mysql> DROP TABLE IF EXISTS no_such_table;
    mysql> SHOW WARNINGS;
    +-------+------+-------------------------------+
    | Level | Code | Message                       |
    +-------+------+-------------------------------+
    | Note  | 1051 | Unknown table 'no_such_table' |
    +-------+------+-------------------------------+

Es folgt ein einfaches Beispiel, das eine Syntaxwarnung für `CREATE TABLE` und Konvertierungswarnungen für `INSERT` enthält:

    mysql> CREATE TABLE t1 (a TINYINT NOT NULL, b CHAR(4)) TYPE=MyISAM;
    Query OK, 0 rows affected, 1 warning (0.00 sec)
    mysql> SHOW WARNINGS\G
    *************************** 1. row ***************************
      Level: Warning
       Code: 1287
    Message: 'TYPE=storage_engine' is deprecated, use
             'ENGINE=storage_engine' instead
    1 row in set (0.00 sec)

    mysql> INSERT INTO t1 VALUES(10,'mysql'),(NULL,'test'),
        -> (300,'Open Source');
    Query OK, 3 rows affected, 4 warnings (0.01 sec)
    Records: 3  Duplicates: 0  Warnings: 4

    mysql> SHOW WARNINGS\G
    *************************** 1. row ***************************
      Level: Warning
       Code: 1265
    Message: Data truncated for column 'b' at row 1
    *************************** 2. row ***************************
      Level: Warning
       Code: 1263
    Message: Data truncated, NULL supplied to NOT NULL column 'a' at row 2
    *************************** 3. row ***************************
      Level: Warning
       Code: 1264
    Message: Data truncated, out of range for column 'a' at row 3
    *************************** 4. row ***************************
      Level: Warning
       Code: 1265
    Message: Data truncated for column 'b' at row 3
    4 rows in set (0.00 sec)

Die maximale Anzahl zu speichernder Fehler-, Warn- und Hinweismeldungen wird von der Systemvariablen `max_error_count` gesteuert. Der Standardwert ist 64. Um die Anzahl der Meldungen, die Sie speichern wollen, zu ändern, modifizieren Sie den Wert von `max_error_count`. Im folgenden Beispiel erzeugt die `ALTER TABLE`-Anweisung drei Warnmeldungen, von denen aber nur eine gespeichert wird, weil `max_error_count` zuvor auf 1 gesetzt worden war:

    mysql> SHOW VARIABLES LIKE 'max_error_count';
    +-----------------+-------+
    | Variable_name   | Value |
    +-----------------+-------+
    | max_error_count | 64    |
    +-----------------+-------+
    1 row in set (0.00 sec)

    mysql> SET max_error_count=1;
    Query OK, 0 rows affected (0.00 sec)

    mysql> ALTER TABLE t1 MODIFY b CHAR;
    Query OK, 3 rows affected, 3 warnings (0.00 sec)
    Records: 3  Duplicates: 0  Warnings: 3

    mysql> SELECT @@warning_count;
    +-----------------+
    | @@warning_count |
    +-----------------+
    |               3 |
    +-----------------+
    1 row in set (0.01 sec)

    mysql> SHOW WARNINGS;
    +---------+------+----------------------------------------+
    | Level   | Code | Message                                |
    +---------+------+----------------------------------------+
    | Warning | 1263 | Data truncated for column 'b' at row 1 |
    +---------+------+----------------------------------------+
    1 row in set (0.00 sec)

Um Warnungen zu deaktivieren, setzen Sie `max_error_count` auf 0. In diesem Fall zeigt `warning_count` zwar noch an, wie viele Warnungen aufgetreten sind, aber keine dieser Meldungen wird gespeichert.

Sie können die Sitzungsvariable `SQL_NOTES` auf 0 setzen, damit Warnungen auf der `Note`-Ebene nicht aufgezeichnet werden.

### 13.5.5. Weitere Verwaltungsanweisungen

#### 13.5.5.1. `CACHE INDEX`

    CACHE INDEX
      tbl_index_list [, tbl_index_list] ...
      IN key_cache_name

    tbl_index_list:
      tbl_name [[INDEX|KEY] (index_name[, index_name] ...)]

Die Anweisung `CACHE INDEX` weist Tabellenindizes einem bestimmten Schlüssel-Cache zu. Sie wird nur bei `MyISAM`-Tabellen eingesetzt.

Die folgende Anweisung weist Indizes der Tabellen `t1`, `t2` und `t3` dem Schlüssel-Cache namens `hot_cache` zu:

    mysql> CACHE INDEX t1, t2, t3 IN hot_cache;
    +---------+--------------------+----------+----------+
    | Table   | Op                 | Msg_type | Msg_text |
    +---------+--------------------+----------+----------+
    | test.t1 | assign_to_keycache | status   | OK       |
    | test.t2 | assign_to_keycache | status   | OK       |
    | test.t3 | assign_to_keycache | status   | OK       |
    +---------+--------------------+----------+----------+

Die Syntax von `CACHE INDEX` gestattet Ihnen, anzugeben, dass nur bestimmte Indizes aus einer Tabelle dem Cache zuzuweisen sind. Die aktuelle Implementierung weist alle Indizes der Tabelle dem Cache zu, weswegen es keinen Grund gibt, einen anderen Parameter als den Tabellennamen zu übergeben.

Der in der `CACHE INDEX`-Anweisung referenzierte Schlüssel-Cache kann erstellt werden, indem seine Größe mit einer Anweisung zur Parametereinstellung oder in den Parametereinstellungen des Servers angegeben wird. Zum Beispiel:

    mysql> SET GLOBAL keycache1.key_buffer_size=128*1024;

Parameter eines Schlüssel-Caches lassen sich als Mitglieder einer strukturierten Systemvariablen einstellen. Siehe auch Abschnitt 5.2.3.1, „Strukturierte Systemvariablen“.

Ein Schlüssel-Cache muss bereits vorhanden sein, bevor Sie ihm Indizes zuweisen:

    mysql> CACHE INDEX t1 IN non_existent_cache;
    ERROR 1284 (HY000): Unknown key cache 'non_existent_cache'

Standardmäßig werden Tabellenindizes dem (vorgabeseitigen) Hauptschlüssel-Cache zugewiesen, der beim Serverstart erstellt wird. Wird ein Schlüssel-Cache zerstört, dann werden alle ihm zugewiesenen Indizes wieder dem Standardschlüssel-Cache zugewiesen.

Die Indexzuweisung wirkt sich global auf den Server aus: Wenn ein Client einem gegebenen Cache einen Index zuweist, wird der Cache für alle Abfragen verwendet, die diesen Index einbeziehen – unabhängig davon, welcher Client die Abfragen absetzt.

#### 13.5.5.2. `FLUSH`

    FLUSH [LOCAL | NO_WRITE_TO_BINLOG] flush_option [, flush_option] ...

Die `FLUSH`-Anweisung leert verschiedene interne Caches, die von MySQL verwendet werden, bzw. lädt diese neu. Für die Ausführung von `FLUSH` benötigen Sie die Berechtigung `RELOAD`.

Die Anweisung `RESET` ähnelt `FLUSH`. Siehe auch Abschnitt 13.5.5.5, „`RESET`“.

`flush_option` kann die folgenden Werte annehmen:

- `HOSTS`

  Leert die Cache-Tabellen auf dem Host. Sie sollten die Hosttabellen leeren, wenn einer Ihrer Hosts die IP-Nummer wechselt oder Sie die Fehlermeldung `Host '`host_name`' is blocked` erhalten. Wenn aufeinander folgend mehr als `max_connect_errors` Fehler für einen gegebenen Host auftreten, während dieser eine Verbindung mit dem MySQL Server herstellt, dann geht MySQL davon aus, dass etwas nicht stimmt, und sperrt weitere Verbindungsanfragen dieses Hosts. Das Synchronisieren der Hosttabellen gestattet dem Host einen neuen Versuch der Verbindungsherstellung. Siehe auch Abschnitt A.2.5, „`Host '...' is blocked`-Fehler“. Sie können mysqld mit `--max_connect_errors=999999999` starten, um diese Fehlermeldung zu verhindern.

- `DES_KEY_FILE`

  Lädt die DES-Schlüssel aus der mit der Option `--des-key-file` beim Serverstart angegebenen Datei neu.

- `LOGS`

  Schließt alle Logdateien und öffnet sie neu. Wenn das binäre Loggen aktiviert ist, wird die Sequenznummer der Binärlogdatei relativ zur vorherigen Datei um den Wert 1 erhöht. Unter Unix ist dies das Gleiche wie das Senden eines `SIGHUP`-Signals an den mysqld-Server. (Ausnahme sind einige Versionen von Mac OS X 10.3, wo mysqld `SIGHUP` und `SIGQUIT` ignoriert.)

  Wenn der Server mit der Option `--log-error` gestartet wurde, bewirkt `FLUSH LOGS`, dass das Fehlerlog mit dem Suffix `-old` umbenannt wird und mysqld eine neue leere Logdatei erstellt. Wenn die Option `--log-error` nicht angegeben wird, erfolgt keine Umbenennung.

- `PRIVILEGES`

  Lädt die Berechtigungen aus der Gesamtstruktur in der `mysql`-Datenbank neu.

- `QUERY CACHE`

  Defragmentiert den Abfrage-Cache, um seinen Speicher besser zu nutzen. `FLUSH QUERY CACHE` entfernt anders als `RESET QUERY CACHE` keine Abfragen aus dem Cache.

- `STATUS`

  Setzt die meisten Statusvariablen auf null. Dies ist etwas, das Sie nur beim Debuggen einer Abfrage tun sollten. Siehe auch Abschnitt 1.8, „Wie man Bugs oder Probleme meldet“.

- `{TABLE | TABLES} [`tbl_name` [, `tbl_name`] ...]`

  Wenn keine Tabellen benannt sind, werden alle Tabellen geschlossen. Das Schließen aller gerade verwendeten Tabellen wird ebenfalls erzwungen. Ferner wird der Schlüssel-Cache synchronisiert. Werden ein oder mehrere Tabellennamen angegeben, dann werden nur die angegebenen Tabellen synchronisiert. `FLUSH TABLES` entfernt ebenso wie `RESET QUERY CACHE` zudem alle Abfrageergebnisse aus dem Abfrage-Cache.

- `TABLES WITH READ LOCK`

  Schließt alle offenen Tabellen und versieht alle Tabellen für alle Datenbanken mit einer Lesesperre, bis Sie `UNLOCK TABLES` ausführen. Dies ist eine recht praktische Möglichkeit der Datensicherung, wenn Sie ein Dateisystem wie Veritas einsetzen, das rechtzeitig Schnappschüsse erstellt.

- `USER_RESOURCES`

  Setzt alle Benutzerbeschränkungen auf Stundenbasis auf null. Hierdurch können Clients, bei denen der Grenzwert für Verbindungen, Abfragen oder Änderungen pro Stunde erreicht wurde, ihre Aktivitäten direkt wiederaufnehmen. `FLUSH USER_RESOURCES` wirkt sich allerdings nicht auf die Begrenzung gleichzeitiger Verbindungen aus. Siehe auch Abschnitt 13.5.1.3, „`GRANT` und `REVOKE`“.

`FLUSH`-Anweisungen werden in das Binärlog geschrieben, sofern das optionale Schlüsselwort `NO_WRITE_TO_BINLOG` (oder sein Alias `LOCAL`) nicht verwendet wird. Dies wird gemacht, damit `FLUSH`-Anweisungen, die auf einem MySQL Server verwendet werden, der als Replikationsmaster agiert, standardmäßig auf den Replikationsslave repliziert werden.

Hinweis: `FLUSH LOGS`, `FLUSH MASTER`, `FLUSH SLAVE` und `FLUSH TABLES WITH READ LOCK` werden keinesfalls geloggt, weil dies bei der Replikation auf einen Slave Probleme verursachen würde.

Sie können auf einige dieser Anweisungen auch mit dem Hilfsprogramm mysqladmin zugreifen, indem Sie die Befehle `flush-hosts`, `flush-logs`, `flush-privileges`, `flush-status` oder `flush-tables` verwenden.

Hinweis: Es ist in MySQL 5.1 nicht möglich, `FLUSH`-Anweisungen in gespeicherten Funktionen oder Triggern abzusetzen. Allerdings können Sie `FLUSH` in gespeicherten Prozeduren benutzen, solange diese nicht aus gespeicherten Funktionen heraus oder von Triggern aufgerufen werden. Siehe auch Abschnitt I.1, „Beschränkungen bei gespeicherten Routinen und Triggern“.

Informationen dazu, wie die `RESET`-Anweisung bei der Replikation verwendet wird, finden Sie in Abschnitt 13.5.5.5, „`RESET`“.

#### 13.5.5.3. `KILL`

    KILL [CONNECTION | QUERY] thread_id

Jede Verbindung mit mysqld wird in einem separaten Thread ausgeführt. Mit der Anweisung `SHOW PROCESSLIST` können Sie die gerade ausgeführten Threads auflisten. Die Terminierung eines Threads ist mit der Anweisung `KILL `thread_id`` möglich.

`KILL` unterstützt die optionalen Modifizierer `CONNECTION` oder `QUERY`:

- `KILL CONNECTION` entspricht `KILL` ohne Modifizierer: Es terminiert die Verbindung zur angegebenen Kennung `thread_id`.

- `KILL QUERY` terminiert die über die Verbindung aktuell ausgeführte Anweisung, lässt die Verbindung selbst aber bestehen.

Wenn Sie die Berechtigung `PROCESS` haben, werden alle Threads angezeigt. Wenn Sie die Berechtigung `SUPER` haben, können Sie alle Threads und Anweisungen terminieren. Andernfalls werden nur Ihre eigenen Threads und Anweisungen angezeigt und zur Terminierung freigegeben.

Zur Überprüfung und Terminierung von Threads können Sie auch die Befehle mysqladmin processlist und mysqladmin kill verwenden.

Hinweis: Sie können `KILL` nicht mit der Embedded MySQL Server-Bibliothek verwenden, da der eingebettete Server nur in den Threads der Hostanwendung ausgeführt wird – er selbst erstellt also keine Verbindungs-Threads.

Wenn Sie `KILL` verwenden, wird ein Thread-spezifisches Terminierungs-Flag für den Thread gesetzt. In den meisten Fällen kann es etwas dauern, bis die Terminierung des Threads abgeschlossen ist, weil das Flag nur in bestimmten Abständen überprüft wird:

- Bei `SELECT`-, `ORDER BY`- und `GROUP BY`-Schleifen wird das Flag nach dem Lesen eines Datensatzblocks überprüft. Ist das Terminierungs-Flag gesetzt, dann wird die Anweisung abgebrochen.

- Bei `ALTER TABLE` wird das Terminierungs-Flag vor jedem Lesen eines Datensatzblocks aus der Ursprungstabelle geprüft. Wurde das Flag gesetzt, dann wird die Anweisung abgebrochen und die Temporärtabelle gelöscht.

- Bei `UPDATE`- oder `DELETE`-Operationen wird das Flag nach jedem gelesenen Block und nach jedem geänderten oder gelöschten Datensatz überprüft. Ist das Terminierungs-Flag gesetzt, dann wird die Anweisung abgebrochen. Beachten Sie, dass, wenn Sie keine Transaktionen verwenden, bereits erfolgte Änderungen nicht rückgängig gemacht werden.

- `GET_LOCK()` führt einen Abbruch aus und gibt `NULL` zurück.

- Ein `INSERT DELAYED`-Thread synchronisiert schnell alle Datensätze in seinem Speicher (d. h., er schreibt sie) und wird dann terminiert.

- Wenn der Thread sich im Tabellensperr-Handler befindet (Zustand `Locked`), dann wird die Tabellensperre umgehend aufgehoben.

- Wartet der Thread bei einem Schreibaufruf auf freien Festplattenspeicher, dann wird die Schreiboperation mit der Fehlermeldung „Disk Full“ abgebrochen.

- Warnung: Die Terminierung einer `REPAIR TABLE`- oder `OPTIMIZE TABLE`-Operation führt bei einer `MyISAM`-Tabelle zu Beschädigungen, die die Tabelle unbrauchbar machen. Lese- oder Schreiboperationen in eine solche Tabelle schlagen fehl, bis Sie sie – ohne Unterbrechung – wieder optimieren oder reparieren.

#### 13.5.5.4. `LOAD INDEX INTO CACHE`

    LOAD INDEX INTO CACHE
      tbl_index_list [, tbl_index_list] ...

    tbl_index_list:
      tbl_name
        [[INDEX|KEY] (index_name[, index_name] ...)]
        [IGNORE LEAVES]

Die Anweisung `LOAD INDEX INTO CACHE` lädt einen Tabellenindex vorab in den Schlüssel-Cache, dem er durch eine explizite `CACHE INDEX`-Anweisung zugewiesen wurde, oder aber in den vorgabeseitigen Schlüssel-Cache. `LOAD INDEX INTO CACHE` wird nur bei `MyISAM`-Tabellen verwendet.

Der Modifizierer `IGNORE LEAVES` bewirkt, dass nur Blöcke für Indexknoten, die nicht Endknoten (Blätter) sind, geladen werden.

Die folgende Anweisung lädt Knoten (Indexblöcke) mit Indizes der Tabellen `t1` und `t2`:

    mysql> LOAD INDEX INTO CACHE t1, t2 IGNORE LEAVES;
    +---------+--------------+----------+----------+
    | Table   | Op           | Msg_type | Msg_text |
    +---------+--------------+----------+----------+
    | test.t1 | preload_keys | status   | OK       |
    | test.t2 | preload_keys | status   | OK       |
    +---------+--------------+----------+----------+

Die Anweisung lädt alle Indexblöcke aus `t1`. Bei `t2` werden nur Blöcke für Nichtendknoten geladen.

Die Syntax von `LOAD INDEX INTO CACHE` gestattet Ihnen, anzugeben, dass nur bestimmte Indizes aus einer Tabelle geladen werden sollen. Die aktuelle Implementierung lädt alle Indizes der Tabelle in den Cache, weswegen es keinen Grund gibt, einen anderen Parameter als den Tabellennamen zu übergeben.

#### 13.5.5.5. `RESET`

    RESET reset_option [, reset_option] ...

Die `RESET`-Anweisung wird benutzt, um den Status verschiedener Serveroperationen zu löschen. Sie benötigen die Berechtigung `RELOAD`, um `RESET` ausführen zu können.

`RESET` agiert als stärkere Version der `FLUSH`-Anweisung. Siehe auch Abschnitt 13.5.5.2, „`FLUSH`“.

`reset_option` kann die folgenden Werte annehmen:

- `MASTER`

  Löscht alle in der Indexdatei aufgeführten Binärlogs, leert den Binärlogindex und setzt ihn zurück und erstellt eine neue Binärlogdatei. (Ist als `FLUSH MASTER` in MySQL-Versionen vor 3.23.26 bekannt.) Siehe auch Abschnitt 13.6.1, „SQL-Anweisungen für die Steuerung von Master-Servern“.

- `QUERY CACHE`

  Entfernt alle Abfrageergebnisse aus dem Abfrage-Cache.

- `SLAVE`

  Löscht auf dem Slave die Angabe zur Replikationsposition in den Binärlogs des Masters (d. h., der Slave „vergisst“ die Position). Setzt außerdem das Relay-Log zurück, indem alle vorhandenen Relay-Logdateien gelöscht werden und eine neue Logdatei begonnen wird. (Ist als `FLUSH SLAVE` in MySQL-Versionen vor 3.23.26 bekannt.) Siehe auch Abschnitt 13.6.2, „SQL-Anweisungen für die Steuerung von Slave-Servern“.

## 13.6. SQL-Befehle in Bezug auf Replikation

Dieser Abschnitt beschreibt SQL-Anweisungen, die im Zusammenhang mit der Replikation von Bedeutung sind. Eine Gruppe von Anweisungen wird zur Steuerung der Master-Server verwendet, die andere zur Steuerung der Slave-Server.

### 13.6.1. SQL-Anweisungen für die Steuerung von Master-Servern

Die Replikation kann über die SQL-Schnittstelle gesteuert werden. Dieser Bereich beschreibt die Anweisungen zur Verwaltung der Replikationsmaster-Server. Abschnitt 13.6.2, „SQL-Anweisungen für die Steuerung von Slave-Servern“, beschreibt Anweisungen zur Verwaltung der Slave-Server.

#### 13.6.1.1. `PURGE MASTER LOGS`

    PURGE {MASTER | BINARY} LOGS TO 'log_name'
    PURGE {MASTER | BINARY} LOGS BEFORE 'date'

Löscht alle Binärlogs, die im Logindex vor dem angegebenen Log oder Datum aufgelistet sind. Die Logs werden auch von der Liste entfernt, die in der Logindexdatei aufgezeichnet ist, d. h., das übergebene Log wird zum ersten Log auf der Liste.

Beispiel:

    PURGE MASTER LOGS TO 'mysql-bin.010';
    PURGE MASTER LOGS BEFORE '2003-04-02 22:46:26';

Das Argument `date` der Variante `BEFORE` kann im Format `'YYYY-MM-DD hh:mm:ss'` angegeben werden. `MASTER` und `BINARY` sind Synonyme.

Diese Anweisung kann auch bei laufender Slave-Replikation sicher ausgeführt werden. Sie müssen die Replikation also nicht anhalten. Wenn ein aktiver Slave gerade eines der Logs ausliest, das Sie löschen wollen, dann hat die Anweisung keine Auswirkungen, sondern schlägt mit einem Fehler fehl. Wenn allerdings ein Slave schläft und Sie eines der Logs löschen, die dieser Slave noch lesen muss, dann wird er nach dem Erwachen nicht mehr zur Replikation in der Lage sein.

Um Logs sicher zu löschen, gehen Sie wie folgt vor:

1. Sie setzen auf allen Slave-Servern `SHOW SLAVE STATUS` ab, um zu prüfen, welches Log gerade gelesen wird.

2. Sie zeigen mit `SHOW MASTER LOGS` eine Liste der Logdateien auf dem Master-Server an.

3. Ermitteln Sie das zeitlich früheste Log unter allen Slaves. Dies ist das Ziellog. Wenn alle Slaves aktuell sind, muss es das letzte Log auf der Liste sein.

4. Erstellen Sie eine Kopie aller Logs, die Sie zu löschen beabsichtigen. (Dieser Schritt ist optional, aber stets empfehlenswert.)

5. Löschen Sie alle Logs bis zum Ziellog (aber nicht das Ziellog selbst).

#### 13.6.1.2. `RESET MASTER`

    RESET MASTER

Löscht alle in der Indexdatei aufgeführten Binärlogs, leert den Binärlogindex und setzt ihn zurück und erstellt eine neue Binärlogdatei.

#### 13.6.1.3. `SET SQL_LOG_BIN`

    SET SQL_LOG_BIN = {0|1}

Aktiviert oder deaktiviert das binäre Loggen für die aktuelle Verbindung (`SQL_LOG_BIN` ist eine Sitzungsvariable), sofern der Client die Berechtigung `SUPER` hat. Die Anweisung wird mit einem Fehler abgewiesen, wenn der Client die Berechtigung nicht hat.

#### 13.6.1.4. `SHOW BINLOG EVENTS`

    SHOW BINLOG EVENTS
       [IN 'log_name'] [FROM pos] [LIMIT [offset,] row_count]

Zeigt die Ereignisse im Binärlog an. Wenn Sie `'`log_name`'` nicht angeben, wird das erste Binärlog angezeigt.

Die `LIMIT`-Klausel hat dieselbe Syntax wie bei der `SELECT`-Anweisung. Siehe auch Abschnitt 13.2.7, „`SELECT`“.

Hinweis: Das Absetzen einer `SHOW BINLOG EVENTS`-Anweisung ohne `LIMIT`-Klausel kann einen sehr zeit- und ressourcenaufwändigen Prozess starten, weil der Server den vollständigen Inhalt des Binärlogs an den Client zurückgibt (dieses Log enthält alle datenändernden Anweisungen, die vom Server ausgeführt wurden). Als Alternative zu `SHOW BINLOG EVENTS` können Sie das Hilfsprogramm mysqlbinlog verwenden. Sie können damit das Binärlog in eine Textdatei speichern und später untersuchen. Siehe auch Abschnitt 8.8, „mysqlbinlog — Hilfsprogramm für die Verarbeitung binärer Logdateien“.

#### 13.6.1.5. `SHOW MASTER LOGS`

    SHOW MASTER LOGS
    SHOW BINARY LOGS

Listet die Binärlogdateien auf dem Server auf. Diese Anweisung wird im Zuge eines Vorgangs benutzt, der in Abschnitt 13.6.1.1, „`PURGE MASTER LOGS`“, beschrieben ist. Dort wird gezeigt, wie man ermittelt, welche Logdateien gelöscht werden können.

    mysql> SHOW BINARY LOGS;
    +---------------+-----------+
    | Log_name      | File_size |
    +---------------+-----------+
    | binlog.000015 |    724935 |
    | binlog.000016 |    733481 |
    +---------------+-----------+

`SHOW BINARY LOGS` ist äquivalent mit `SHOW MASTER LOGS`.

#### 13.6.1.6. `SHOW MASTER STATUS`

    SHOW MASTER STATUS

Vermittelt Statusinformationen zu den Binärlogdateien des Masters. Beispiel:

    mysql > SHOW MASTER STATUS;
    +---------------+----------+--------------+------------------+
    | File          | Position | Binlog_Do_DB | Binlog_Ignore_DB |
    +---------------+----------+--------------+------------------+
    | mysql-bin.003 | 73       | test         | manual,mysql     |
    +---------------+----------+--------------+------------------+

#### 13.6.1.7. `SHOW SLAVE HOSTS`

    SHOW SLAVE HOSTS

Zeigt eine Liste der Replikationsslaves an, die derzeit beim Master registriert wird. Slaves, die nicht mit der Option `--report-host=`slave_name`` gestartet wurden, werden in der Liste nicht angezeigt.

### 13.6.2. SQL-Anweisungen für die Steuerung von Slave-Servern

Die Replikation kann über die SQL-Schnittstelle gesteuert werden. Dieser Abschnitt beschreibt die Anweisungen zur Verwaltung der Replikationsslave-Server. Abschnitt 13.6.1, „SQL-Anweisungen für die Steuerung von Master-Servern“, beschreibt Anweisungen zur Verwaltung der Master-Server.

#### 13.6.2.1. `CHANGE MASTER TO`

    CHANGE MASTER TO master_def [, master_def] ...

    master_def:
        MASTER_HOST = 'host_name'
      | MASTER_USER = 'user_name'
      | MASTER_PASSWORD = 'password'
      | MASTER_PORT = port_num
      | MASTER_CONNECT_RETRY = count
      | MASTER_LOG_FILE = 'master_log_name'
      | MASTER_LOG_POS = master_log_pos
      | RELAY_LOG_FILE = 'relay_log_name'
      | RELAY_LOG_POS = relay_log_pos
      | MASTER_SSL = {0|1}
      | MASTER_SSL_CA = 'ca_file_name'
      | MASTER_SSL_CAPATH = 'ca_directory_name'
      | MASTER_SSL_CERT = 'cert_file_name'
      | MASTER_SSL_KEY = 'key_file_name'
      | MASTER_SSL_CIPHER = 'cipher_list'

`CHANGE MASTER TO` ändert die Parameter, die der Slave-Server zur Verbindungsherstellung und Kommunikation mit dem Master-Server verwendet. Die Anweisung aktualisiert auch den Inhalt der Dateien `master.info` und `relay-log.info`.

`MASTER_USER`, `MASTER_PASSWORD`, `MASTER_SSL`, `MASTER_SSL_CA`, `MASTER_SSL_CAPATH`, `MASTER_SSL_CERT`, `MASTER_SSL_KEY` und `MASTER_SSL_CIPHER` vermitteln dem Slave Informationen dazu, wie er Verbindungen mit dem Master herstellen kann.

Die SSL-Optionen (`MASTER_SSL`, `MASTER_SSL_CA`, `MASTER_SSL_CAPATH`, `MASTER_SSL_CERT`, `MASTER_SSL_KEY` und `MASTER_SSL_CIPHER`) können auch auf Slaves geändert werden, die ohne SSL-Unterstützung kompiliert wurden. Sie werden in der Datei `master.info` gespeichert, aber ignoriert, bis Sie einen Server verwenden, auf dem die SSL-Unterstützung aktiviert ist.

Wenn Sie einen der Parameter nicht angeben, dann behält er in der Regel seinen alten Wert (Ausnahmen entnehmen Sie der nachfolgenden Erläuterung). Wenn sich beispielsweise das Passwort, mit dem die Verbindung zu Ihrem MySQL-Master hergestellt wird, geändert hat, müssen Sie nur die folgenden Anweisungen absetzen, um dem Slave das neue Passwort mitzuteilen:

    STOP SLAVE; -- if replication was running
    CHANGE MASTER TO MASTER_PASSWORD='new3cret';
    START SLAVE; -- if you want to restart replication

Es ist nicht notwendig, Parameter anzugeben, die sich nicht ändern (Host, Port, Benutzer usw.).

`MASTER_HOST` und `MASTER_PORT` sind der Hostname (oder die IP-Adresse) des Master-Hosts bzw. sein TCP/IP-Port. Beachten Sie, dass, wenn `MASTER_HOST` gleich `localhost` ist, die Portnummer – wie unter MySQL bei anderen Gelegenheiten auch – unter Umständen ignoriert werden kann (dies ist etwa der Fall, wenn Unix-Socketdateien benutzt werden).

Geben Sie `MASTER_HOST` oder `MASTER_PORT` an, dann setzt der Slave voraus, dass der Master-Server sich vom vorherigen unterscheidet (und zwar auch dann, wenn Sie einen Host- oder Portwert angeben, der mit dem aktuellen Wert identisch ist). In diesem Fall werden die alten Namens- und Positionswerte der Binärlogdatei auf dem Master-Server als nun ungültig betrachtet, d. h., wenn Sie `MASTER_LOG_FILE` und `MASTER_LOG_POS` in der Anweisung nicht angeben, werden stillschweigend `MASTER_LOG_FILE=''` und `MASTER_LOG_POS=4` angehängt.

`MASTER_LOG_FILE` und `MASTER_LOG_POS` sind die Koordinaten, bei denen der Slave-I/O-Thread mit dem Lesen vom Master beginnen soll, wenn der Thread beim nächsten Mal startet. Wenn Sie einen dieser Werte angeben, dürfen Sie `RELAY_LOG_FILE` oder `RELAY_LOG_POS` nicht angeben. Wenn weder `MASTER_LOG_FILE` noch `MASTER_LOG_POS` angegeben werden, verwendet der Slave die letzten Koordinaten des Slave-SQL-Threads, bevor `CHANGE MASTER` abgesetzt wurde. Hierdurch ist gewährleistet, dass es bei der Replikation auch dann nicht zu Unstetigkeiten kommt, wenn der Slave-SQL-Thread sehr spät mit dem Slave-I/O-Thread verglichen wurde – etwa dann, wenn Sie beispielsweise nur das zu verwendende Passwort ändern wollen.

`CHANGE MASTER` löscht alle Relay-Logdateien und beginnt eine neue Relay-Logdatei, sofern Sie nicht `RELAY_LOG_FILE` oder `RELAY_LOG_POS` angeben. In diesem Fall werden die Relay-Logs behalten, und die globale Variable `relay_log_purge` wird stillschweigend auf 0 gesetzt.

`CHANGE MASTER` ist praktisch, wenn es darum geht, einen Slave zu konfigurieren, und Sie hierfür die Momentaufnahme des Masters benötigen und Logdatei und Offset entsprechend aufgezeichnet haben. Nachdem Sie die Momentaufnahme in den Slave geladen haben, können Sie `CHANGE MASTER TO MASTER_LOG_FILE='`log_name_on_master`', MASTER_LOG_POS=`log_offset_on_master`` auf dem Slave ausführen.

Das folgende Beispiel ändert die Koordinaten des Masters und dessen Binärlogdatei. Dies tut man, wenn man den Slave so konfiguriert, dass er den Master repliziert:

    CHANGE MASTER TO
      MASTER_HOST='master2.mycompany.com',
      MASTER_USER='replication',
      MASTER_PASSWORD='bigs3cret',
      MASTER_PORT=3306,
      MASTER_LOG_FILE='master2-bin.001',
      MASTER_LOG_POS=4,
      MASTER_CONNECT_RETRY=10;

Das nächste Beispiel zeigt eine Operation, die weniger häufig benötigt wird. Sie wird verwendet, wenn auf dem Slave Relay-Logs vorhanden sind, die Sie aus irgendeinem Grund erneut ausführen wollen. Zu diesem Zweck muss der Master nicht erreichbar sein. Sie müssen lediglich `CHANGE MASTER TO` benutzen und den SQL-Thread mit `START SLAVE SQL_THREAD` starten:

    CHANGE MASTER TO
      RELAY_LOG_FILE='slave-relay-bin.006',
      RELAY_LOG_POS=4025;

Sie können die zweite Operation sogar in einer Nicht-Replikations-Konfiguration mit einem eigenständigen Nicht-Slave-Server benutzen, um nach einem Absturz eine Wiederherstellung durchzuführen. Angenommen, Ihr Server ist abgestürzt, und Sie haben eine Sicherung wiederhergestellt. Nun wollen Sie die eigenen Binärlogs des Servers – nicht die Relay-Logs, sondern die regulären Binärlogs – namens (beispielsweise) `myhost-bin.*` wieder auf den Server aufspielen. Zunächst erstellen Sie ein Backup dieser Binärlogs an einer sicheren Position für den Fall, dass Sie der nachfolgenden Anleitung nicht exakt folgen und der Server deswegen die Binärlogs unbeabsichtigt löscht. Verwenden Sie `SET GLOBAL relay_log_purge=0`, um die Sicherheit zu erhöhen. Danach starten Sie den Server ohne die Option `--log-bin`. Stattdessen geben Sie die Optionen `--replicate-same-server-id`, `--relay-log=myhost-bin` (damit der Server glaubt, dass es sich bei diesen regulären Logs um Relay-Logs handelt) und `--skip-slave-start` an. Nach dem Serverstart setzen Sie die folgenden Anweisungen ab:

    CHANGE MASTER TO
      RELAY_LOG_FILE='myhost-bin.153',
      RELAY_LOG_POS=410,
      MASTER_HOST='some_dummy_string';
    START SLAVE SQL_THREAD;

Der Server liest nun seine eigenen Binärlogs und führt diese aus. Auf diese Weise erfolgt eine Wiederherstellung der Daten. Nach deren Abschluss führen Sie `STOP SLAVE` aus, fahren den Server herunter, löschen die Dateien `master.info` und `relay-log.info` und starten den Server mit den ursprünglichen Optionen neu.

Die Angabe der Option `MASTER_HOST` (auch mit einem Pseudowert) ist erforderlich, damit der Server annimmt, er sei ein Slave.

#### 13.6.2.2. `LOAD DATA FROM MASTER`

    LOAD DATA FROM MASTER

Diese Anweisung erstellt eine Momentaufnahme des Masters und kopiert diese auf den Slave. Sie aktualisiert die Werte von `MASTER_LOG_FILE` und `MASTER_LOG_POS`, sodass der Slave die Replikation an der korrekten Position startet. Ausschlussregeln für Tabellen und Datenbanken, die mit den Optionen `--replicate-*-do-*` und `--replicate-*-ignore-*` angegeben werden, werden beachtet. `--replicate-rewrite-db` wird hingegen nicht berücksichtigt, weil ein Benutzer mit dieser Option eine nichteindeutige Zuordnung wie `--replicate-rewrite-db="db1->db3"` oder `--replicate-rewrite-db="db2->db3"` vornehmen könnte, was den Slave beim Laden der Tabellen vom Master verwirren würde.

Die Verwendung dieser Anweisung hängt von den folgenden Bedingungen ab:

- Sie funktioniert nur bei `MyISAM`-Tabellen. Der Versuch, eine Tabelle anderen Typs zu laden, führt zu folgendem Fehler:

      ERROR 1189 (08S01): Net error reading from master

- Sie erwirkt während der Aufzeichnung der Momentaufnahme eine globale Lesesperre auf dem Master, wodurch während des Ladevorgangs Updates auf dem Master unterbunden werden.

Wenn Sie große Tabellen laden, müssen Sie die Werte von `net_read_timeout` und `net_write_timeout` unter Umständen sowohl auf dem Master- als auch auf den Slave-Servern erhöhen. Siehe auch Abschnitt 5.2.2, „Server-Systemvariablen“.

Beachten Sie, dass `LOAD DATA FROM MASTER` keine Tabellen aus der `mysql`-Datenbank kopiert. Dies erleichtert die Einrichtung verschiedener Benutzer und Berechtigungen auf dem Master und dem Slave.

Um `LOAD DATA FROM MASTER` verwenden zu können, benötigt das Replikationskonto, welches zur Verbindung mit dem Master-Server verwendet wird, die Berechtigungen `RELOAD` und `SUPER` auf dem Master und die Berechtigung `SELECT` für alle Master-Tabellen, die Sie laden wollen. Alle Master-Tabellen, für die der Benutzer die Berechtigung `SELECT` nicht hat, werden von `LOAD DATA FROM MASTER` ignoriert. Dies liegt daran, dass der Master sie vor dem Benutzer verbirgt: `LOAD DATA FROM MASTER` ruft `SHOW DATABASES` auf, um die zu ladenden Master-Datenbanken in Erfahrung zu bringen; `SHOW DATABASES` aber gibt nur Datenbanken zurück, für die der Benutzer Berechtigungen hat. Siehe auch Abschnitt 13.5.4.7, „`SHOW DATABASES`“. Auf der Slave-Seite benötigt der Benutzer, der `LOAD DATA FROM MASTER` absetzt, Berechtigungen zum Löschen und Erstellen der Datenbanken und Tabellen, die kopiert werden.

#### 13.6.2.3. `LOAD TABLE `tbl_name` FROM MASTER`

    LOAD TABLE tbl_name FROM MASTER

Überträgt eine Kopie der Tabelle vom Master auf den Slave. Diese Anweisung wurde in erster Linie zum Debuggen von `LOAD DATA FROM MASTER`-Operationen implementiert. Um `LOAD TABLE` verwenden zu können, benötigt das Konto, welches zur Verbindung mit dem Master-Server verwendet wird, die Berechtigungen `RELOAD` und `SUPER` auf dem Master und die Berechtigung `SELECT` für die zu ladende Master-Tabelle. Auf der Slave-Seite benötigt der Benutzer, der `LOAD TABLE FROM MASTER` absetzt, Berechtigungen zum Löschen und Erstellen der Tabelle.

Die Bedingungen für `LOAD DATA FROM MASTER` gelten auch hier. So funktioniert `LOAD TABLE FROM MASTER` beispielsweise nur bei `MyISAM`-Tabellen. Auch die Hinweise zu Zeitüberschreitungen für `LOAD DATA FROM MASTER` sind anzuwenden.

#### 13.6.2.4. `MASTER_POS_WAIT()`

    SELECT MASTER_POS_WAIT('master_log_file', master_log_pos)

Dies ist eigentlich eine Funktion und keine Anweisung. Mit ihr kann gewährleistet werden, dass der Slave Ereignisse bis zu einer gegebenen Position im Binärlog des Masters gelesen und ausgeführt hat. Eine vollständige Beschreibung finden Sie in Abschnitt 12.10.4, „Verschiedene Funktionen“.

#### 13.6.2.5. `RESET SLAVE`

    RESET SLAVE

`RESET SLAVE` löscht auf dem Slave die Angabe zur Replikationsposition in den Binärlogs des Masters (d. h., der Slave „vergisst“ die Position). Diese Anweisung ist zur Verwendung für einen sauberen Start vorgesehen: Sie löscht die Dateien `master.info` und `relay-log.info` und alle Relay-Logs und beginnt ein neues Relay-Log.

Hinweis: Alle Relay-Logs werden gelöscht – auch dann, wenn sie nicht vollständig vom Slave-SQL-Thread ausgeführt wurden. (Dieser Umstand ist wahrscheinlich auf einem Replikationsslave gegeben, wenn Sie eine `STOP SLAVE`-Anweisung abgesetzt haben oder der Slave stark belastet ist.)

Verbindungsdaten, die in der Datei `master.info` gespeichert sind, werden direkt unter Berücksichtigung von Werten zurückgesetzt, die ggf. mit den entsprechenden Startoptionen angegeben werden. Zu diesen Daten gehören Werte wie Master-Host, Master-Port, Master-Benutzer und Master-Passwort. Wenn der Slave-SQL-Thread gerade mit der Replikation von Temporärtabellen beschäftigt war, als er angehalten wurde, und `RESET SLAVE` abgesetzt wird, dann werden diese replizierten Temporärtabellen auf dem Slave gelöscht.

#### 13.6.2.6. `SET GLOBAL SQL_SLAVE_SKIP_COUNTER`

    SET GLOBAL SQL_SLAVE_SKIP_COUNTER = N

Diese Anweisung überspringt die nächsten `N` Ereignisse auf dem Master. Dies ist nützlich, wenn Replikationen wiederhergestellt werden sollen, die durch eine Anweisung angehalten wurden.

Die Anweisung ist nur gültig, wenn der Slave-Thread nicht ausgeführt wird. Andernfalls erzeugt er einen Fehler.

#### 13.6.2.7. `SHOW SLAVE STATUS`

    SHOW SLAVE STATUS

Diese Anweisung vermittelt Statusinformationen zu wesentlichen Parametern der Slave-Threads. Wenn Sie diese Anweisung mit dem mysql-Client absetzen, können Sie `\G` statt des Semikolons als Abschlusszeichen für die Anweisung verwenden, um eine vertikale Ausgabe zu erhalten, die besser zu lesen ist:

    mysql> SHOW SLAVE STATUS\G
    *************************** 1. row ***************************
           Slave_IO_State: Waiting for master to send event
              Master_Host: localhost
              Master_User: root
              Master_Port: 3306
            Connect_Retry: 3
          Master_Log_File: gbichot-bin.005
      Read_Master_Log_Pos: 79
           Relay_Log_File: gbichot-relay-bin.005
            Relay_Log_Pos: 548
    Relay_Master_Log_File: gbichot-bin.005
         Slave_IO_Running: Yes
        Slave_SQL_Running: Yes
          Replicate_Do_DB:
      Replicate_Ignore_DB:
               Last_Errno: 0
               Last_Error:
             Skip_Counter: 0
      Exec_Master_Log_Pos: 79
          Relay_Log_Space: 552
          Until_Condition: None
           Until_Log_File:
            Until_Log_Pos: 0
       Master_SSL_Allowed: No
       Master_SSL_CA_File:
       Master_SSL_CA_Path:
          Master_SSL_Cert:
        Master_SSL_Cipher:
           Master_SSL_Key:
    Seconds_Behind_Master: 8

`SHOW SLAVE STATUS` gibt die folgenden Felder zurück:

- `Slave_IO_State`

  Eine Kopie des `State`-Felds in der Ausgabe von `SHOW PROCESSLIST` für den Slave-I/O-Thread. Sie zeigt an, was der Thread gerade tut: Verbindungsherstellung zum Master, Warten auf vom Master kommende Ereignisse, Wiederverbindung mit dem Master usw. Mögliche Zustände sind in Abschnitt 6.4, „Replikation: Implementationsdetails“, beschrieben. Bei älteren MySQL-Versionen ist eine Überprüfung dieses Felds notwendig, denn diese erlaubten eine fortlaufende Ausführung des Threads auch für den Fall, dass eine Verbindungsherstellung mit dem Master nicht möglich war. Wird er ausgeführt, so liegt kein Problem vor; andernfalls finden Sie den Fehler im Feld `Last_Error` (siehe unten).

- `Master_Host`

  Der aktuelle Master-Host.

- `Master_User`

  Der aktuelle Benutzer, der mit dem Master verbunden ist.

- `Master_Port`

  Der aktuelle Master-Port.

- `Connect_Retry`

  Der aktuelle Wert der Option `--master-connect-retry`.

- `Master_Log_File`

  Der Name der Master-Binärlogdatei, aus der der I/O-Thread derzeit liest.

- `Read_Master_Log_Pos`

  Die Position, bis zu der der I/O-Thread im aktuellen Master-Binärlog gelesen hat.

- `Relay_Log_File`

  Der Name der Relay-Logdatei, deren Angaben der SQL-Thread derzeit liest und ausführt.

- `Relay_Log_Pos`

  Die Position, bis zu der der SQL-Thread Angaben in der aktuellen Relay-Logdatei gelesen und ausgeführt hat.

- `Relay_Master_Log_File`

  Der Name der Master-Binärlogdatei, die das aktuelle Ereignis enthält, welches gerade vom SQL-Thread ausgeführt wird.

- `Slave_IO_Running`

  Gibt an, ob der I/O-Thread gestartet wurde und erfolgreich eine Verbindung mit dem Master herstellen konnte. Bei älteren MySQL-Versionen (vor 4.1.14 und 5.0.12) hat `Slave_IO_Running` den Wert `YES`, wenn der I/O-Thread gestartet wurde (und zwar auch dann, wenn noch keine Verbindung zum Master hergestellt wurde).

- `Slave_SQL_Running`

  Gibt an, ob der SQL-Thread gestartet wurde.

- `Replicate_Do_DB`, `Replicate_Ignore_DB`

  Liste der Datenbanken, die ggf. mit den Optionen `--replicate-do-db` und `--replicate-ignore-db` angegeben wurden.

- `Replicate_Do_Table`, `Replicate_Ignore_Table`, `Replicate_Wild_Do_Table`, `Replicate_Wild_Ignore_Table`

  Liste der Tabellen, die ggf. mit den Optionen `--replicate-do-table`, `--replicate-ignore-table`, `--replicate-wild-do-table` und `--replicate-wild-ignore_table` angegeben wurden.

- `Last_Errno`, `Last_Error`

  Nummer und Meldung des Fehlers, der von der zuletzt ausgeführten Abfrage zurückgegeben wurde. Die Fehlernummer 0 und der Leer-String als Meldung haben die Bedeutung „kein Fehler“. Wenn der Wert `Last_Error` nicht leer ist, erscheint er auch als Meldung im Fehlerlog des Slaves. Zum Beispiel:

      Last_Errno: 1051
      Last_Error: error 'Unknown table 'z'' on query 'drop table z'

  Die Meldung zeigt an, dass die Tabelle `z` auf dem Master vorhanden war und dort gelöscht wurde, dass sie aber auf dem Slave nicht existierte, weswegen die Anweisung `DROP TABLE` dort fehlschlug. (Dies kann beispielsweise passieren, wenn Sie vergessen, die Tabelle beim Einrichten der Replikation auf den Slave zu kopieren.)

- `Skip_Counter`

  Der zuletzt verwendete Wert von `SQL_SLAVE_SKIP_COUNTER`.

- `Exec_Master_Log_Pos`

  Die Position des letzten vom SQL-Thread ausgeführten Ereignisses aus dem Binärlog des Masters (`Relay_Master_Log_File`). (`Relay_Master_Log_File`, `Exec_Master_Log_Pos`) im Binärlog des Masters entspricht (`Relay_Log_File`, `Relay_Log_Pos`) im Relay-Log.

- `Relay_Log_Space`

  Die Gesamtgröße aller vorhandenen Relay-Logs.

- `Until_Condition`, `Until_Log_File`, `Until_Log_Pos`

  Der in der `UNTIL`-Klausel der `START SLAVE`-Anweisung angegebene Wert.

  `Until_Condition` kann folgende Werte haben:

  - `None`, sofern keine `UNTIL`-Klausel angegeben wurde.

  - `Master`, wenn der Slave bis zu einer angegebenen Position in den Binärlogs des Masters liest.

  - `Relay`, wenn der Slave bis zu einer angegebenen Position in seinen Binärlogs liest.

  `Until_Log_File` und `Until_Log_Pos` geben den Namen der Logdatei und die Position an. Diese Werte definieren den Punkt, an dem die Ausführung des SQL-Threads endet.

- `Master_SSL_Allowed`, `Master_SSL_CA_File`, `Master_SSL_CA_Path`, `Master_SSL_Cert`, `Master_SSL_Cipher`, `Master_SSL_Key`

  Diese Felder geben (sofern vorhanden) die SSL-Parameter an, die vom Slave zur Verbindung mit dem Master verwendet werden.

  `Master_SSL_Allowed` kann folgende Werte haben:

  - `Yes`, wenn eine SSL-Verbindung zum Master zulässig ist.

  - `No`, wenn keine SSL-Verbindung zum Master zulässig ist.

  - `Ignored`, wenn eine SSL-Verbindung zwar zulässig ist, aber am Slave-Server die SSL-Unterstützung nicht aktiviert ist.

  Die Werte der übrigen SSL-spezifischen Felder entsprechen den Werten der Optionen `--master-ca`, `--master-capath`, `--master-cert`, `--master-cipher` und `--master-key`.

- `Seconds_Behind_Master`

  Dieses Feld gibt an, wie „verspätet“ der Slave ist:

  - Wenn der Slave-SQL-Thread aktiv läuft (d. h. Änderungen verarbeitet), dann gibt dieses Feld die Anzahl der Sekunden an, die seit dem Zeitstempel des Ereignisses vergangen sind, das von diesem Thread zuletzt auf dem Master ausgeführt wurde.

  - Wenn der SQL-Thread den Slave-I/O-Thread eingeholt hat und untätig auf weitere Ereignisse vom I/O-Thread wartet, ist das Feld null.

  Im Endeffekt misst das Feld also den zeitlichen Unterschied zwischen dem Slave-SQL-Thread und dem Slave-I/O-Thread.

  Ist die Netzwerkverbindung zwischen Master und Slave sehr schnell, dann liegt der Slave-I/O-Thread recht nah am Master, d. h., das Feld erlaubt eine recht genaue Schätzung des zeitlichen Verarbeitungsabstandes zwischen Slave-SQL-Thread und dem Master. Ist das Netzwerk hingegen langsam, dann ist der Wert nicht sehr aussagekräftig: Der Slave-SQL-Thread kann recht häufig zum langsam lesenden Slave-I/O-Thread aufschließen, weswegen `Seconds_Behind_Master` oft den Wert 0 anzeigt – und zwar auch dann, wenn der I/O-Thread im Vergleich zum Master relativ stark verspätet ist. Anders gesagt, diese Spalte ist nur bei schnellen Netzwerken aussagekräftig.

  Diese Berechnung des zeitlichen Unterschieds funktioniert, obwohl Master und Slave keine identisch laufenden Uhren haben (der Unterschied wird ermittelt, wenn der Slave-I/O-Thread startet; danach wird davon ausgegangen, dass der Abstand konstant bleibt). `Seconds_Behind_Master` ist `NULL` (d. h. „unbekannt“), wenn der Slave-SQL-Thread nicht ausgeführt wird oder wenn der Slave-I/O-Thread nicht läuft oder nicht mit dem Master verbunden ist. Schläft beispielsweise der Slave-I/O-Thread für die mit der Option `--master-connect-retry` angegebene Anzahl von Sekunden, bevor er eine Wiederverbindung versucht, dann wird `NULL` angezeigt, weil der Slave nicht wissen kann, was der Master tut, und deswegen auch nicht zuverlässig weiß, wie spät es ist.

  Dieses Feld hat eine Einschränkung: Der Zeitstempel wird bei der Replikation beibehalten, d. h., wenn ein Master M1 seinerseits ein Slave von M0 ist, dann hat jedes Ereignis im Binärlog von M1, das der Replikation eines Ereignisses aus dem Binärlog von M0 entstammt, auch den Zeitstempel dieses Ereignisses. Dies erlaubt MySQL die erfolgreiche Replikation von `TIMESTAMP`. Der Nachteil für `Seconds_Behind_Master` besteht allerdings darin, dass, wenn M1 auch direkte Updates von Clients erhält, der Wert wahllos abweicht, weil das letzte Ereignis auf M1 mal von M0 stammt, mal aber auch der letzte Zeitstempel eines direkten Updates ist.

#### 13.6.2.8. `START SLAVE`

    START SLAVE [thread_type [, thread_type] ... ]
    START SLAVE [SQL_THREAD] UNTIL
        MASTER_LOG_FILE = 'log_name', MASTER_LOG_POS = log_pos
    START SLAVE [SQL_THREAD] UNTIL
        RELAY_LOG_FILE = 'log_name', RELAY_LOG_POS = log_pos

    thread_type: IO_THREAD | SQL_THREAD

`START SLAVE` startet beide Slave-Threads. Der I/O-Thread liest Abfragen vom Master-Server und speichert sie im Relay-Log. Der SQL-Thread liest das Relay-Log und führt die Abfragen aus. `START SLAVE` erfordert die Berechtigung `SUPER`.

Wenn `START SLAVE` die Slave-Threads erfolgreich startet, wird kein Fehler zurückgegeben. Allerdings kann es auch in diesem Fall vorkommen, dass die Slave-Threads starten und kurz darauf wieder beendet werden (etwa weil sie keine Verbindung zum Master herstellen oder die Binärlogs nicht lesen konnten oder aus einem anderen Grund). `START SLAVE` warnt Sie davor nicht. Sie müssen das Fehlerlog des Slaves auf Fehlermeldungen prüfen, die von den Slave-Threads erzeugt wurden, oder sich mit `SHOW SLAVE STATUS` vergewissern, dass sie einwandfrei ausgeführt werden.

Sie können die Optionen `IO_THREAD` oder `SQL_THREAD` zur Anweisung hinzufügen, wenn Sie angeben wollen, welcher der Threads gestartet werden soll.

Eine `UNTIL`-Klausel kann hinzugefügt werden, um anzugeben, dass der Slave starten und laufen soll, bis der SQL-Thread einen gegebenen Punkt im Master-Binärlog oder den Slave-Relay-Logs erreicht. Wenn der SQL-Thread diesen Punkt erreicht, wird er beendet. Wird die Option `SQL_THREAD` in der Anweisung angegeben, dann startet nur der SQL-Thread. Andernfalls werden beide Slave-Threads gestartet. Läuft der SQL-Thread bereits, dann wird die Klausel `UNTIL` ignoriert, und eine Warnung wird ausgegeben.

Für eine `UNTIL`-Klausel müssen Sie sowohl einen Logdateinamen als auch eine Position angeben. Vermischen Sie die Optionen für Master- und Relay-Logs nicht.

Eine `UNTIL`-Bedingung wird von einer nachfolgenden `STOP SLAVE`-Anweisung, einer `START SLAVE`-Anweisung ohne `UNTIL`-Klausel oder einem Serverneustart zurückgesetzt.

Die `UNTIL`-Klausel kann nützlich sein, um die Replikation zu debuggen oder festzulegen, dass die Replikation bis genau zu dem Punkt fortfahren soll, an dem ein Slave eine Anweisung nicht mehr replizieren soll. Wurde beispielsweise versehentlich eine `DROP TABLE`-Anweisung auf dem Master ausgeführt, dann können Sie den Slave mit `UNTIL` anweisen, das Log nur bis unmittelbar vor diesem Punkt, aber nicht mehr weiter auszuführen. Um herauszufinden, was das Ereignis ist, verwenden Sie mysqlbinlog mit den Master-Logs oder den Slave-Relay-Logs oder setzen eine `SHOW BINLOG EVENTS`-Anweisung ab.

Wenn Sie `UNTIL` verwenden, damit der Slave-Prozess die Abfragen in Abschnitten repliziert, empfehlen wir den Start des Slaves mit der Option `--skip-slave-start`, damit der SQL-Thread nicht ausgeführt wird, wenn der Slave-Server startet. Es ist wahrscheinlich am besten, diese Option in einer Optionsdatei statt auf der Befehlszeile zu benutzen, damit die Klausel bei einem unerwarteten Serverneustart nicht vergessen wird.

Die `SHOW SLAVE STATUS`-Anweisung enthält Ausgabefelder, die die aktuellen Werte der `UNTIL`-Bedingung anzeigen.

In älteren Versionen von MySQL (vor 4.0.5) hieß diese Anweisung `SLAVE START`. Ihre Verwendung in dieser Form ist zwar in MySQL 5.1 aus Kompatibilitätsgründen noch akzeptabel, aber veraltet.

#### 13.6.2.9. `STOP SLAVE`

    STOP SLAVE [thread_type [, thread_type] ... ]

    thread_type: IO_THREAD | SQL_THREAD

Beendet die Slave-Threads. `STOP SLAVE` erfordert die Berechtigung `SUPER`.

Wie `START SLAVE` kann diese Anweisung mit den Optionen `IO_THREAD` und `SQL_THREAD` verwendet werden, um den oder die zu beendenden Threads anzugeben.

In älteren Versionen von MySQL (vor 4.0.5) hieß diese Anweisung `SLAVE STOP`. Ihre Verwendung in dieser Form ist zwar in MySQL 5.1 aus Kompatibilitätsgründen noch akzeptabel, aber veraltet.

## 13.7. SQL-Syntax für vorbereitete Anweisungen

MySQL 5.1 unterstützt serverseitige vorbereitete Anweisungen. Diese Unterstützung nutzt das effiziente binäre Client/Server-Protokoll, welches in MySQL 4.1 implementiert wurde. Voraussetzung hierfür ist, dass Sie eine geeignete Client-Programmierschnittstelle verwenden. Geeignete Schnittstellen sind die C-API-Clientbibliothek von MySQL (für C-Programme), MySQL Connector/J (für Java-Programme) und MySQL Connector/NET. So bietet etwa die C-API eine Anzahl von Funktionsaufrufen, die eine API für vorbereitete Anweisungen darstellen. Siehe auch Abschnitt 24.2.4, „C-API: Prepared Statements“. Andere Sprachschnittstellen bieten Unterstützung für vorbereitete Anweisungen, die das binäre Protokoll verwenden, indem Sie eine Verbindung in die C-Clientbibliothek herstellen (z. B. die `mysqli`-Erweiterung in PHP 5.0).

Es gibt auch eine alternative SQL-Schnittstelle für vorbereitete Anweisungen. Diese ist zwar nicht so effizient wie die Verwendung eines binären Protokolls über eine API für vorbereitete Anweisungen, sie erfordert aber auch keine Programmierung, weil sie direkt auf SQL-Ebene verfügbar ist:

- Sie können sie verwenden, wenn Ihnen keine Programmierschnittstelle zur Verfügung steht.

- Sie können sie aus jedem Programm heraus verwenden, das Ihnen die Übermittlung von SQL-Anweisungen an den Server zur dortigen Ausführung gestattet (dies gilt beispielsweise für das mysql-Clientprogramm).

- Sie können es auch dann verwenden, wenn der Client eine alte Version der Clientbibliothek einsetzt. Die einzige Voraussetzung besteht darin, dass Sie eine Verbindung mit einem Server herstellen können müssen, der aktuell genug ist, um die SQL-Syntax für vorbereitete Anweisungen zu unterstützen.

Die SQL-Syntax für vorbereitete Anweisungen ist zur Verwendung in Fällen wie den folgenden vorgesehen:

- Sie wollen die Funktion vorbereiteter Anweisungen in Ihrer Anwendung testen, bevor Sie sie einkodieren.

- Eine Anwendung hat Probleme mit der Ausführung vorbereiteter Anweisungen, und Sie wollen dem Problem interaktiv auf den Grund gehen.

- Sie wollen einen Testfall erstellen, der ein Problem im Zusammenhang mit vorbereiteten Anweisungen beschreibt. Dieser soll als Grundlage eines Fehlerberichts dienen.

- Sie müssen vorbereitete Anweisungen verwenden, haben aber keinen Zugang zu einer Programmierschnittstelle, die diese unterstützt.

Die SQL-Syntax für vorbereitete Anweisungen basiert auf drei SQL-Anweisungen:

- `PREPARE `stmt_name` FROM `preparable_stmt``

  Die Anweisung `PREPARE` bereitet eine Anweisung vor und weist ihr den Namen `stmt_name` zu, unter dem sie später referenziert werden kann. Die Groß-/Kleinschreibung wird bei Anweisungsnamen nicht unterschieden. `preparable_stmt` ist entweder ein String-Literal oder eine Benutzervariable, die den Text der Anweisung enthält. Der Text muss eine einzelne SQL-Anweisung (nicht mehrere Anweisungen) darstellen. In dieser Anweisung können Fragezeichen (‘`?`’) als Parameterkennzeichen verwendet werden: Sie geben an, wo bei der späteren Ausführung der Anweisung Datenwerte eingebunden werden. Fragezeichen sollten auch dann nicht in Anführungszeichen gesetzt werden, wenn Sie beabsichtigen, sie an String-Werte anzubinden. Parameterkennzeichen dürfen nur an Stellen verwendet werden, an denen Datenwerte eingefügt werden sollen, nicht jedoch für SQL-Schlüsselwörter, Bezeichner usw.

  Wenn eine vorbereitete Anweisung des angegebenen Namens bereits vorhanden ist, wird diese Namenszuweisung implizit aufgehoben, bevor die neue Anweisung vorbereitet wird. Das bedeutet, dass, wenn die neue Anweisung einen Fehler enthält und nicht vorbereitet werden kann, ein Fehler zurückgegeben wird; in diesem Fall gibt es keine Anweisung des betreffenden Namens mehr.

  Der Gültigkeitsbereich einer vorbereiteten Anweisung ist die Clientsitzung, innerhalb derer sie erstellt wird. Andere Clients sehen sie nicht.

- `EXECUTE `stmt_name` [USING @`var_name` [, @`var_name`] ...]`

  Nach der Vorbereitung einer Anweisung können Sie sie mit einer `EXECUTE`-Anweisung ausführen, die den Namen der vorbereiteten Anweisung referenziert. Wenn die vorbereitete Anweisung Parameterkennzeichen enthält, müssen Sie eine `USING`-Klausel angeben, die die Benutzervariablen mit den Werten auflistet, welche für die Parameter eingesetzt werden sollen. Parameterwerte können nur über Benutzervariablen übergeben werden. Die `USING`-Klausel muss so viele Variablen übergeben, wie Parameterkennzeichen in der Anweisung vorhanden sind, und alle Variablennamen müssen korrekt sein.

  Sie können eine vorbereitete Anweisung mehrfach ausführen und dabei unterschiedliche Variablen übergeben oder die Variablen vor jeder Ausführung auf andere Werte setzen.

- `{DEALLOCATE | DROP} PREPARE `stmt_name``

  Um eine vorbereitete Anweisung aufzuheben, verwenden Sie die Anweisung `DEALLOCATE PREPARE`. Wenn Sie eine vorbereitete Anweisung auszuführen versuchen, nachdem Sie sie aufgehoben haben, wird ein Fehler erzeugt.

  Wenn Sie eine Clientsitzung beenden, ohne eine zuvor vorbereitete Anweisung aufzuheben, dann hebt der Server sie automatisch auf.

In vorbereiteten Anweisungen können die folgenden SQL-Anweisungen verwendet werden: `CREATE TABLE`, `DELETE`, `DO`, `INSERT`, `REPLACE`, `SELECT`, `SET`, `UPDATE` und die meisten `SHOW`-Anweisungen. Andere Anweisungen werden noch nicht unterstützt.

Die folgenden Beispiele zeigen zwei gleichwertige Arten der Vorbereitung einer Anweisung, die die Hypotenuse eines Dreiecks berechnet, bei dem zwei Seitenlängen gegeben sind.

Das erste Beispiel zeigt, wie man eine vorbereitete Anweisung unter Verwendung eines String-Literals erstellt, um den Text der Anweisung zu übergeben:

    mysql> PREPARE stmt1 FROM 'SELECT SQRT(POW(?,2) + POW(?,2)) AS hypotenuse';
    mysql> SET @a = 3;
    mysql> SET @b = 4;
    mysql> EXECUTE stmt1 USING @a, @b;
    +------------+
    | hypotenuse |
    +------------+
    |          5 |
    +------------+
    mysql> DEALLOCATE PREPARE stmt1;

Das zweite Beispiel ist ähnlich, übergibt den Text der Anweisung aber als Benutzervariable:

    mysql> SET @s = 'SELECT SQRT(POW(?,2) + POW(?,2)) AS hypotenuse';
    mysql> PREPARE stmt2 FROM @s;
    mysql> SET @a = 6;
    mysql> SET @b = 8;
    mysql> EXECUTE stmt2 USING @a, @b;
    +------------+
    | hypotenuse |
    +------------+
    |         10 |
    +------------+
    mysql> DEALLOCATE PREPARE stmt2;

Die SQL-Syntax für vorbereitete Anweisungen erlaubt keine Verschachtelungen: Eine an `PREPARE` übergebene Anweisung darf selbst keine `PREPARE`-, `EXECUTE`- oder `DEALLOCATE PREPARE`-Anweisung sein.

Die SQL-Syntax für vorbereitete Anweisungen unterscheidet sich von der Verwendung von API-Aufrufen für vorbereitete Anweisungen. So können Sie beispielsweise mit der C-API-Funktion `mysql_stmt_prepare()` keine `PREPARE`-, `EXECUTE`- oder `DEALLOCATE PREPARE`-Anweisung vorbereiten.

Die SQL-Syntax für vorbereitete Anweisungen kann in gespeicherten Prozeduren, nicht aber in gespeicherten Funktionen oder Triggern verwendet werden.

Bei der Verwendung vorbereiteter Anweisungen können für die Argumente der `LIMIT`-Klausel Platzhalter eingesetzt werden. Siehe auch Abschnitt 13.2.7, „`SELECT`“.

Dies ist eine Übersetzung des MySQL-Referenzhandbuchs, das sich auf dev.mysql.com befindet. Das ursprüngliche Referenzhandbuch ist auf Englisch, und diese Übersetzung ist nicht notwendigerweise so aktuell wie die englische Ausgabe. Das vorliegende deutschsprachige Handbuch behandelt MySQL bis zur Version 5.1.

Zurück |  | Weiter
Kapitel 12. Funktionen für die Benutzung in `SELECT`- und `WHERE`-Klauseln | Zum Anfang | Kapitel 14. Speicher-Engines und Tabellentypen