第 13 章 SQL ステートメントの構文

目次

13.1 データ定義ステートメント
13.1.1 ALTER DATABASE 構文
13.1.2 ALTER EVENT 構文
13.1.3 ALTER LOGFILE GROUP 構文
13.1.4 ALTER FUNCTION 構文
13.1.5 ALTER PROCEDURE 構文
13.1.6 ALTER SERVER 構文
13.1.7 ALTER TABLE 構文
13.1.8 ALTER TABLESPACE 構文
13.1.9 ALTER VIEW 構文
13.1.10 CREATE DATABASE 構文
13.1.11 CREATE EVENT 構文
13.1.12 CREATE FUNCTION 構文
13.1.13 CREATE INDEX 構文
13.1.14 CREATE LOGFILE GROUP 構文
13.1.15 CREATE PROCEDURE および CREATE FUNCTION 構文
13.1.16 CREATE SERVER 構文
13.1.17 CREATE TABLE 構文
13.1.18 CREATE TABLESPACE 構文
13.1.19 CREATE TRIGGER 構文
13.1.20 CREATE VIEW 構文
13.1.21 DROP DATABASE 構文
13.1.22 DROP EVENT 構文
13.1.23 DROP FUNCTION 構文
13.1.24 DROP INDEX 構文
13.1.25 DROP LOGFILE GROUP 構文
13.1.26 DROP PROCEDURE および DROP FUNCTION 構文
13.1.27 DROP SERVER 構文
13.1.28 DROP TABLE 構文
13.1.29 DROP TABLESPACE 構文
13.1.30 DROP TRIGGER 構文
13.1.31 DROP VIEW 構文
13.1.32 RENAME TABLE 構文
13.1.33 TRUNCATE TABLE 構文
13.2 データ操作ステートメント
13.2.1 CALL 構文
13.2.2 DELETE 構文
13.2.3 DO 構文
13.2.4 HANDLER 構文
13.2.5 INSERT 構文
13.2.6 LOAD DATA INFILE 構文
13.2.7 LOAD XML 構文
13.2.8 REPLACE 構文
13.2.9 SELECT 構文
13.2.10 サブクエリー構文
13.2.11 UPDATE 構文
13.3 MySQL トランザクションおよびロックステートメント
13.3.1 START TRANSACTION、COMMIT、および ROLLBACK 構文
13.3.2 ロールバックできないステートメント
13.3.3 暗黙的なコミットを発生させるステートメント
13.3.4 SAVEPOINT、ROLLBACK TO SAVEPOINT、および RELEASE SAVEPOINT 構文
13.3.5 LOCK TABLES および UNLOCK TABLES 構文
13.3.6 SET TRANSACTION 構文
13.3.7 XA トランザクション
13.4 レプリケーションステートメント
13.4.1 マスターサーバーを制御するための SQL ステートメント
13.4.2 スレーブサーバーを制御するための SQL ステートメント
13.5 準備済みステートメントのための SQL 構文
13.5.1 PREPARE 構文
13.5.2 EXECUTE 構文
13.5.3 DEALLOCATE PREPARE 構文
13.6 MySQL 複合ステートメント構文
13.6.1 BEGIN ... END 複合ステートメント構文
13.6.2 ステートメントラベルの構文
13.6.3 DECLARE 構文
13.6.4 ストアドプログラム内の変数
13.6.5 フロー制御ステートメント
13.6.6 カーソル
13.6.7 条件の処理
13.7 データベース管理ステートメント
13.7.1 アカウント管理ステートメント
13.7.2 テーブル保守ステートメント
13.7.3 プラグインおよびユーザー定義関数ステートメント
13.7.4 SET 構文
13.7.5 SHOW 構文
13.7.6 その他の管理ステートメント
13.8 MySQL ユーティリティーステートメント
13.8.1 DESCRIBE 構文
13.8.2 EXPLAIN 構文
13.8.3 HELP 構文
13.8.4 USE 構文

この章では、MySQL によってサポートされる SQL ステートメントの構文について説明します。

13.1 データ定義ステートメント

13.1.1 ALTER DATABASE 構文

ALTER {DATABASE | SCHEMA} [db_name] alter_specification ...
ALTER {DATABASE | SCHEMA} db_name UPGRADE DATA DIRECTORY NAMEalter_specification: [DEFAULT] CHARACTER SET [=] charset_name | [DEFAULT] COLLATE [=] collation_name

ALTER DATABASE を使用すると、データベースの全体的な特性を変更できます。これらの特性は、データベースディレクトリ内の db.opt ファイルに格納されます。ALTER DATABASE を使用するには、そのデータベースに対する ALTER 権限が必要です。ALTER SCHEMAALTER DATABASE のシノニムです。

最初の構文からはデータベース名を省略できます。その場合、このステートメントはデフォルトデータベースに適用されます。

各国語に関する特性

CHARACTER SET 句は、デフォルトのデータベース文字セットを変更します。COLLATE 句は、デフォルトのデータベース照合順序を変更します。セクション10.1「文字セットのサポート」では、文字セットと照合順序名について説明しています。

どのような文字セットと照合順序を使用できるかは、それぞれ SHOW CHARACTER SET および SHOW COLLATION ステートメントを使用して確認できます。詳細は、セクション13.7.5.4「SHOW CHARACTER SET 構文」およびセクション13.7.5.5「SHOW COLLATION 構文」を参照してください。

データベースのデフォルトの文字セットまたは照合順序を変更する場合、データベースのデフォルトを使用するストアドルーチンを削除して、新しいデフォルトを使用するように再作成する必要があります。(ストアドルーチンでは、文字セットまたは照合順序が明示的に指定されていない場合、文字データ型を伴う変数は、データベースのデフォルトを使用します。セクション13.1.15「CREATE PROCEDURE および CREATE FUNCTION 構文」を参照してください。)

MySQL 5.1 より古いバージョンからのアップグレード

UPGRADE DATA DIRECTORY NAME 句を含む構文は、データベースに関連付けられたディレクトリの名前を、データベース名をデータベースディレクトリ名にマップするための MySQL 5.1 で実装されたエンコーディングを使用するように更新します (セクション9.2.3「識別子とファイル名のマッピング」を参照してください)。この句は、次の条件の下で使用されることを目的にしています。

  • MySQL を古いバージョンから 5.1 以降にアップグレードすることを目的にしている。

  • データベースディレクトリ名にエンコーディングが必要な特殊文字が含まれている場合は、その名前を現在のエンコーディング形式に更新することを目的にしている。

  • このステートメントが (mysql_upgrade から呼び出された) mysqlcheck によって使用されている。

たとえば、MySQL 5.0 でのデータベース名が a-b-c である場合、その名前には - (ダッシュ) 文字のインスタンスが含まれています。MySQL 5.0 では、データベースディレクトリの名前も、必ずしもすべてのファイルシステムで安全ではない a-b-c になります。MySQL 5.1 以降では、ファイルシステムに依存しないディレクトリ名を生成するために、同じデータベース名が a@002db@002dc としてエンコードされます。

MySQL インストールが古いバージョンから MySQL 5.1 以降にアップグレードされると、サーバーでは a-b-c などの (古い形式の) 名前が #mysql50#a-b-c として表示されるため、#mysql50# プリフィクスを使用して名前を参照する必要があります。この場合は、UPGRADE DATA DIRECTORY NAME を使用して、データベースディレクトリ名を現在のエンコーディング形式に再エンコーディングするようサーバーに明示的に指示します。

ALTER DATABASE `#mysql50#a-b-c` UPGRADE DATA DIRECTORY NAME;

このステートメントを実行したあとは、特殊な #mysql50# プリフィクスなしで、そのデータベースを a-b-c として参照できます。

13.1.2 ALTER EVENT 構文

ALTER [DEFINER = { user | CURRENT_USER }] EVENT event_name [ON SCHEDULE schedule] [ON COMPLETION [NOT] PRESERVE] [RENAME TO new_event_name] [ENABLE | DISABLE | DISABLE ON SLAVE] [COMMENT 'comment'] [DO event_body]

ALTER EVENT ステートメントは、既存のイベントの 1 つ以上の特性を、そのイベントを削除して再作成することなく変更します。DEFINERON SCHEDULEON COMPLETIONCOMMENTENABLE/DISABLEDO の各句の構文は、CREATE EVENT で使用される場合とまったく同じです。(セクション13.1.11「CREATE EVENT 構文」を参照してください。)

どのユーザーも、そのユーザーが EVENT 権限を持っているデータベースで定義されたイベントを変更できます。ユーザーが正常な ALTER EVENT ステートメントを実行すると、そのユーザーは、影響を受けるイベントの定義者になります。

ALTER EVENT は、既存のイベントでのみ機能します。

mysql> ALTER EVENT no_such_event  > ON SCHEDULE  > EVERY '2:3' DAY_HOUR;ERROR 1517 (HY000): Unknown event 'no_such_event'

次の各例では、myevent という名前のイベントが次に示すように定義されていることを前提にしています。

CREATE EVENT myevent ON SCHEDULE EVERY 6 HOUR COMMENT 'A sample comment.' DO UPDATE myschema.mytable SET mycol = mycol + 1;

次のステートメントは、myevent のスケジュールを、ただちに開始して 6 時間ごとに 1 回から、ステートメントが実行された 4 時間後から開始して 12 時間ごとに 1 回に変更します。

ALTER EVENT myevent ON SCHEDULE EVERY 12 HOUR STARTS CURRENT_TIMESTAMP + INTERVAL 4 HOUR;

イベントの複数の特性を 1 つのステートメントで変更できます。この例では、myevent によって実行される SQL ステートメントを、mytable のすべてのレコードを削除する SQL ステートメントに変更します。また、イベントのスケジュールも、この ALTER EVENT ステートメントが実行された 1 日あとに 1 回実行されるように変更します。

ALTER EVENT myevent ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 DAY DO TRUNCATE TABLE myschema.mytable;

ALTER EVENT ステートメントでは、変更したい特性のオプションのみを指定します。省略されたオプションでは、その既存の値が保持されます。これには、ENABLE などの、CREATE EVENT のデフォルト値もすべて含まれます。

myevent を無効にするには、この ALTER EVENT ステートメントを使用します。

ALTER EVENT myevent DISABLE;

ON SCHEDULE 句では、組み込みの MySQL 関数やユーザー変数を含む式を使用して、そこに含まれているすべての timestamp または interval 値を取得できます。このような式でストアドルーチンやユーザー定義関数を使用したり、テーブル参照を使用したりすることはできません。ただし、SELECT FROM DUAL は使用できます。これは、ALTER EVENT ステートメントと CREATE EVENT ステートメントの両方に当てはまります。このような場合のストアドルーチン、ユーザー定義関数、およびテーブルへの参照は明確に禁止されており、エラーで失敗します (Bug #22830 を参照してください)。

DO 句に別の ALTER EVENT ステートメントを含む ALTER EVENT ステートメントは成功したように見えますが、結果として得られるスケジュールされたイベントをサーバーが実行しようとすると、その実行はエラーで失敗します。

イベントの名前を変更するには、ALTER EVENT ステートメントの RENAME TO 句を使用します。このステートメントは、イベント myevent の名前を yourevent に変更します。

ALTER EVENT myevent RENAME TO yourevent;

次に示すように、ALTER EVENT ... RENAME TO ...db_name.event_name 表記を使用して、イベントを別のデータベースに移動することもできます。

ALTER EVENT olddb.myevent RENAME TO newdb.myevent;

前のステートメントを実行するには、それを実行するユーザーが、olddb および newdb データベースの両方に対する EVENT 権限を持っている必要があります。

注記

RENAME EVENT ステートメントはありません。

DISABLE ON SLAVE は、マスター上で作成されてスレーブにレプリケートされたが、まだスレーブ上で実行されていないイベントを示すために、ENABLE または DISABLE の代わりにレプリケーションスレーブに対して使用されます。通常、DISABLE ON SLAVE は必要に応じて自動的に設定されます。ただし、手動で変更することが必要になる場合もあります。詳細は、セクション17.4.1.11「呼び出される機能のレプリケーション」を参照してください。

13.1.3 ALTER LOGFILE GROUP 構文

ALTER LOGFILE GROUP logfile_group ADD UNDOFILE 'file_name' [INITIAL_SIZE [=] size] [WAIT] ENGINE [=] engine_name

このステートメントは、'file_name' という名前の UNDO ファイルを既存のログファイルグループ logfile_group に追加します。ALTER LOGFILE GROUP ステートメントには、ADD UNDOFILE 句が 1 つだけ存在します。DROP UNDOFILE 句は、現在サポートされていません。

注記

すべての MySQL Cluster ディスクデータオブジェクトが同じ名前空間を共有します。つまり、各ディスクデータオブジェクトは (単に、特定の型の各ディスクデータオブジェクトというだけでなく)、一意の名前が付けられている必要があります。たとえば、テーブルスペースと Undo ログファイルを同じ名前にしたり、Undo ログファイルとデータファイルを同じ名前にしたりすることはできません。

オプションの INITIAL_SIZE パラメータは、UNDO ファイルの初期サイズをバイト単位で設定します。指定されていない場合、初期サイズはデフォルトで 134217728 (128M バイト) になります。MySQL Cluster NDB 7.3.2 より前は、この値は数字で指定する必要がありました。MySQL Cluster NDB 7.3.2 以降では、size のあとにオプションで、my.cnf で使用されるのと同様の、オーダーを示す 1 文字の略語を指定できます。一般に、これは M (M バイト) または G (G バイト) のどちらかの文字です。(Bug #13116514、Bug #16104705、Bug #62858)

32 ビットシステム上では、INITIAL_SIZE のサポートされる最大値は 4294967296 (4G バイト) です。(Bug #29186)

INITIAL_SIZE の許可される最小値は 1048576 (1M バイト) です。(Bug #29574)

注記

WAIT は解析されますが、それ以外は無視されます。このキーワードは現在何の効果もなく、将来の拡張のために用意されています。

ENGINE パラメータ (必須) は、このログファイルグループによって使用されるストレージエンジンを決定します。ここで、engine_name はそのストレージエンジンの名前です。現在、engine_name として受け入れられる値はNDBCLUSTERNDBだけです。この 2 つの値は同等です。

次の例では、ログファイルグループ lg_3 がすでに CREATE LOGFILE GROUP を使用して作成されていることを前提にしています (セクション13.1.14「CREATE LOGFILE GROUP 構文」を参照してください)。

ALTER LOGFILE GROUP lg_3 ADD UNDOFILE 'undo_10.dat' INITIAL_SIZE=32M ENGINE=NDBCLUSTER;

ALTER LOGFILE GROUPENGINE = NDBCLUSTER (または、ENGINE = NDB) とともに使用された場合は、UNDO ログファイルが各 MySQL Cluster データノード上に作成されます。INFORMATION_SCHEMA.FILES テーブルをクエリーすることによって、UNDO ファイルが作成されたことを確認したり、それらに関する情報を取得したりできます。例:

mysql> SELECT FILE_NAME, LOGFILE_GROUP_NUMBER, EXTRA -> FROM INFORMATION_SCHEMA.FILES -> WHERE LOGFILE_GROUP_NAME = 'lg_3';+-------------+----------------------+----------------+
| FILE_NAME | LOGFILE_GROUP_NUMBER | EXTRA |
+-------------+----------------------+----------------+
| newdata.dat | 0 | CLUSTER_NODE=3 |
| newdata.dat | 0 | CLUSTER_NODE=4 |
| undo_10.dat | 11 | CLUSTER_NODE=3 |
| undo_10.dat | 11 | CLUSTER_NODE=4 |
+-------------+----------------------+----------------+
4 rows in set (0.01 sec)

(セクション21.30.1「INFORMATION_SCHEMA FILES テーブル」を参照してください。)

UNDO_BUFFER_SIZE に使用されるメモリーは、サイズが SharedGlobalMemory データノード構成パラメータの値によって決定されるグローバルプールから取得されます。これには、InitialLogFileGroup データノード構成パラメータの設定により、このオプションに暗黙的に指定されるデフォルト値もすべて含まれます。

ALTER LOGFILE GROUP は、MySQL Cluster のディスクデータストレージでのみ有効です。詳細は、セクション18.5.12「MySQL Cluster ディスクデータテーブル」を参照してください。

13.1.4 ALTER FUNCTION 構文

ALTER FUNCTION func_name [characteristic ...]characteristic: COMMENT 'string' | LANGUAGE SQL | { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA } | SQL SECURITY { DEFINER | INVOKER }

このステートメントを使用すると、ストアドファンクションの特性を変更できます。ALTER FUNCTION ステートメントでは、複数の変更を指定できます。ただし、このステートメントを使用して、ストアドファンクションのパラメータまたは本体を変更することはできません。このような変更を行うには、DROP FUNCTIONCREATE FUNCTION を使用して、この関数を削除および再作成する必要があります。

この関数に対する ALTER ROUTINE 権限が必要です。(その権限は、関数作成者に自動的に付与されます。)バイナリロギングが有効になっている場合は、セクション20.7「ストアドプログラムのバイナリロギング」で説明されているように、ALTER FUNCTION ステートメントに SUPER 権限も必要になる可能性があります。

13.1.5 ALTER PROCEDURE 構文

ALTER PROCEDURE proc_name [characteristic ...]characteristic: COMMENT 'string' | LANGUAGE SQL | { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA } | SQL SECURITY { DEFINER | INVOKER }

このステートメントを使用すると、ストアドプロシージャーの特性を変更できます。ALTER PROCEDURE ステートメントでは、複数の変更を指定できます。ただし、このステートメントを使用して、ストアドプロシージャーのパラメータまたは本体を変更することはできません。このような変更を行うには、DROP PROCEDURECREATE PROCEDURE を使用して、このプロシージャーを削除および再作成する必要があります。

このプロシージャーに対する ALTER ROUTINE 権限が必要です。デフォルトでは、その権限は、プロシージャー作成者に自動的に付与されます。この動作は、automatic_sp_privileges システム変数を無効にすることによって変更できます。セクション20.2.2「ストアドルーチンと MySQL 権限」を参照してください。

13.1.6 ALTER SERVER 構文

ALTER SERVER server_name OPTIONS (option [, option] ...)

server_name のサーバー情報を変更して、CREATE SERVER ステートメント内で許可されているオプションのいずれかを調整します。それに応じて、mysql.servers テーブル内の対応するフィールドが更新されます。このステートメントには、SUPER 権限が必要です。

たとえば、USER オプションを更新するには、次のようにします。

ALTER SERVER s OPTIONS (USER 'sally');

ALTER SERVER では、自動コミットは実行されません。

MySQL 5.6 では、使用されているロギング形式には関係なく、ALTER SERVER はバイナリログに書き込まれません。

MySQL 5.6.11 でのみ、このステートメントを発行する前に、gtid_nextAUTOMATIC に設定する必要があります。(Bug #16062608、Bug #16715809、Bug #69045)

13.1.7 ALTER TABLE 構文

ALTER [ONLINE|OFFLINE] [IGNORE] TABLE tbl_name [alter_specification [, alter_specification] ...] [partition_options]alter_specification: table_options | ADD [COLUMN] col_namecolumn_definition [FIRST | AFTER col_name ] | ADD [COLUMN] (col_namecolumn_definition,...) | ADD {INDEX|KEY} [index_name] [index_type] (index_col_name,...) [index_option] ... | ADD [CONSTRAINT [symbol]] PRIMARY KEY [index_type] (index_col_name,...) [index_option] ... | ADD [CONSTRAINT [symbol]] UNIQUE [INDEX|KEY] [index_name] [index_type] (index_col_name,...) [index_option] ... | ADD FULLTEXT [INDEX|KEY] [index_name] (index_col_name,...) [index_option] ... | ADD SPATIAL [INDEX|KEY] [index_name] (index_col_name,...) [index_option] ... | ADD [CONSTRAINT [symbol]] FOREIGN KEY [index_name] (index_col_name,...) reference_definition | ALGORITHM [=] {DEFAULT|INPLACE|COPY} | ALTER [COLUMN] col_name {SET DEFAULT literal | DROP DEFAULT} | CHANGE [COLUMN] old_col_namenew_col_namecolumn_definition [FIRST|AFTER col_name] | LOCK [=] {DEFAULT|NONE|SHARED|EXCLUSIVE} | MODIFY [COLUMN] col_namecolumn_definition [FIRST | AFTER col_name] | DROP [COLUMN] col_name | DROP PRIMARY KEY | DROP {INDEX|KEY} index_name | DROP FOREIGN KEY fk_symbol | DISABLE KEYS | ENABLE KEYS | RENAME [TO|AS] new_tbl_name | ORDER BY col_name [, col_name] ... | CONVERT TO CHARACTER SET charset_name [COLLATE collation_name] | [DEFAULT] CHARACTER SET [=] charset_name [COLLATE [=] collation_name] | DISCARD TABLESPACE | IMPORT TABLESPACE | FORCE | ADD PARTITION (partition_definition) | DROP PARTITION partition_names | TRUNCATE PARTITION {partition_names | ALL} | COALESCE PARTITION number | REORGANIZE PARTITION partition_names INTO (partition_definitions) | EXCHANGE PARTITION partition_name WITH TABLE tbl_name | ANALYZE PARTITION {partition_names | ALL} | CHECK PARTITION {partition_names | ALL} | OPTIMIZE PARTITION {partition_names | ALL} | REBUILD PARTITION {partition_names | ALL} | REPAIR PARTITION {partition_names | ALL} | REMOVE PARTITIONINGindex_col_name: col_name [(length)] [ASC | DESC]index_type: USING {BTREE | HASH}index_option: KEY_BLOCK_SIZE [=] value | index_type | WITH PARSER parser_name | COMMENT 'string'table_options: table_option [[,] table_option] ... (see CREATE TABLE options)partition_options: (see CREATE TABLE options)

ALTER TABLE は、テーブルの構造を変更します。たとえば、カラムを追加または削除したり、インデックスを作成または破棄したり、既存のカラムの型を変更したり、カラムまたはテーブル自体の名前を変更したりできます。また、テーブルに使用されているストレージエンジンやテーブルのコメントなどの特性を変更することもできます。

テーブル名のあとに、行う変更を指定します。何も指定されていない場合、ALTER TABLE は何もしません。

許可される多くの変更の構文は、CREATE TABLE ステートメントの各句に似ています。詳細は、セクション13.1.17「CREATE TABLE 構文」を参照してください。

table_options は、ENGINEAUTO_INCREMENTAVG_ROW_LENGTHMAX_ROWSROW_FORMAT などの、CREATE TABLE ステートメントで使用できる種類のテーブルオプションを示します。すべてのテーブルオプションのリストと各オプションの説明については、セクション13.1.17「CREATE TABLE 構文」を参照してください。ただし、ALTER TABLE は、DATA DIRECTORY および INDEX DIRECTORY テーブルオプションを無視します。

partition_options は、再パーティション化、パーティションの追加、削除、マージ、および分割、パーティション化の保守の実行などのために、パーティション化されたテーブルで使用できるオプションを示します。ALTER TABLE ステートメントには、ほかの変更指定に加えて、PARTITION BY または REMOVE PARTITIONING 句を含めることができますが、PARTITION BY または REMOVE PARTITIONING 句は、ほかのどの指定よりもあとの最後に指定する必要があります。ADD PARTITIONDROP PARTITIONCOALESCE PARTITIONREORGANIZE PARTITIONEXCHANGE PARTITIONANALYZE PARTITIONCHECK PARTITION、および REPAIR PARTITION オプションは、個々のパーティションに対して機能するため、1 つの ALTER TABLE 内でほかの変更指定と組み合わせることはできません。パーティションのオプションの詳細は、セクション13.1.17「CREATE TABLE 構文」およびセクション13.1.7.1「ALTER TABLE パーティション操作」を参照してください。ALTER TABLE ... EXCHANGE PARTITION ステートメントの詳細および例については、セクション19.3.1「RANGE および LIST パーティションの管理」を参照してください。

操作によっては、ストレージエンジンがその操作をサポートしていないテーブルに対して試行されると、警告が生成される場合があります。これらの警告は、SHOW WARNINGS で表示できます。セクション13.7.5.41「SHOW WARNINGS 構文」を参照してください。

ALTER TABLE のトラブルシューティングについては、セクションB.5.7.1「ALTER TABLE での問題」を参照してください。

ストレージ、パフォーマンス、および並列性に関する考慮事項

ほとんどの場合、ALTER TABLE は元のテーブルの一時的なコピーを作成します。MySQL は、そのテーブルを変更しているほかの操作を待ってから、処理を続行します。そのコピーに変更を組み込み、元のテーブルを削除したあと、新しいテーブルの名前を変更します。ALTER TABLE の実行中、ほかのセッションは元のテーブルを読み取ることができます (例外については、すぐあとに説明します)。ALTER TABLE 操作の開始後に開始されたテーブルへの更新や書き込みは、新しいテーブルの準備ができるまで停止されてから、どの更新も失敗することなく、新しいテーブルに自動的にリダイレクトされます。元のテーブルの一時的なコピーは、新しいテーブルのデータベースディレクトリ内に作成されます。これは、テーブルの名前を別のデータベースに変更した ALTER TABLE 操作のための元のテーブルのデータベースディレクトリとは異なる場合があります。

前に触れた例外とは、ALTER TABLE が、テーブルの .frm ファイルの新しいバージョンをインストールし、古いファイルを破棄して、テーブルおよびテーブル定義キャッシュから古くなったテーブル構造をクリアする準備ができた時点で (書き込みだけでなく) 読み取りをブロックすることです。この時点で、このステートメントは排他的ロックを取得する必要があります。それを行うために、現在の読み取り側が完了するのを待って、新しい読み取り (および書き込み) をブロックします。

MyISAM テーブルの場合は、myisam_sort_buffer_size システム変数を大きな値に設定することによって、インデックスの再作成 (変更プロセスのもっとも遅い部分) を高速化できます。

一部の操作では、一時テーブルを必要としないインプレース ALTER TABLE が可能です。

  • ALTER TABLE tbl_name RENAME TO new_tbl_name をほかのオプションなしで実行すると、MySQL は単純に、コピーを作成することなく、テーブル tbl_name に対応するすべてのファイルの名前を変更します。(RENAME TABLE ステートメントを使用してテーブルの名前を変更することもできます。セクション13.1.32「RENAME TABLE 構文」を参照してください。)名前変更されたテーブル専用に付与された権限は、どれも新しい名前には移行されません。それらは、手動で変更する必要があります。

  • サーバーが変更する必要があるのはテーブルの内容ではなく、テーブルの .frm ファイルだけであるため、テーブルデータを変更せず、テーブルメタデータだけを変更する変更はただちに実行されます。次の変更は、この方法で実行できる迅速な変更です。

    • カラムの名前変更。ただし、MySQL 5.6.6 より前の InnoDB ストレージエンジンを除きます。

    • カラムのデフォルト値の変更 (NDB テーブルを除きます。「MySQL Cluster オンライン操作の制限」を参照してください)。

    • 有効なメンバー値のリストの最後に新しい列挙またはセットメンバーを追加することによる、ENUM または SET カラムの定義の変更。ただし、データ型のストレージサイズが変更される場合を除きます。たとえば、メンバー数が 8 の SET カラムにメンバーを追加すると、値ごとに必要なストレージが 1 バイトから 2 バイトに変更されます。これには、テーブルコピーが必要になります。リストの途中にメンバーを追加すると、既存のメンバーの番号が変更されます。これには、テーブルコピーが必要になります。

  • ADD PARTITIONDROP PARTITIONCOALESCE PARTITIONREBUILD PARTITION、または REORGANIZE PARTITION を含む ALTER TABLE は、一時テーブルを作成しません (NDB テーブルで使用される場合を除きます)。ただし、これらの操作では、一時的なパーティションファイルが作成されます。

    RANGE または LIST パーティションに対する ADD または DROP 操作は即座の操作か、ほぼ即座の操作です。HASH または KEY パーティションに対する ADD または COALESCE 操作では、LINEAR HASH または LINEAR KEY が使用されていないかぎり、すべてのパーティション間でデータがコピーされます。ADD または COALESCE 操作はパーティションごとに実行されますが、これは実質的に、新しいテーブルの作成と同じです。REORGANIZE 操作では変更されたパーティションのみがコピーされ、変更されていないものはそのままです。

  • インデックスの名前変更。InnoDB を除きます。

  • InnoDBNDB に対するインデックスの追加または削除。

old_alter_table システム変数を ON に設定するか、または alter_specification 句の 1 つとして ALGORITHM=COPY を指定することによって、通常であればテーブルコピーを必要としない ALTER TABLE 操作で強制的に (MySQL 5.0 でサポートされている) 一時テーブルの方法を使用するようにできます。old_alter_table 設定と、DEFAULT 以外の値を持つ ALGORITHM 句の間に矛盾がある場合は、ALGORITHM 句が優先されます。(ALGORITHM = DEFAULT は、ALGORITHM 句をまったく指定しないのと同じです。)

ALGORITHM=INPLACE を指定すると、それをサポートする句やストレージエンジンに対してインプレースの手法が使用されるようになり、サポートされていない場合はエラーで失敗します。そのため、予測していたものとは異なるストレージエンジンを使用するテーブルを変更しようとした場合の非常に長いテーブルコピーが回避されます。InnoDB テーブルに対するオンライン DDL については、セクション14.11「InnoDB とオンライン DDL」を参照してください。

MySQL 5.6.16 では、ALTER TABLE は、ADD COLUMNCHANGE COLUMNMODIFY COLUMNADD INDEX、および FORCE 操作に関して、古い時間カラムを 5.6 形式にアップグレードします。テーブルを再構築しなければならないため、この変換は INPLACE アルゴリズムを使用して実行することはできません。そのため、これらの場合に ALGORITHM=INPLACE を指定するとエラーになります。必要であれば、ALGORITHM=COPY を指定します。

MySQL 5.6.22 から、テーブルを KEY によってパーティション化するために使用されるマルチカラムインデックスに対する ALTER TABLE 操作は、この操作によってカラムの順序が変更される場合はオンラインで実行できません。このような場合は、代わりに、コピーする ALTER TABLE を使用する必要があります。(Bug #17896265)

MySQL Cluster はオンライン ALTER TABLE 操作もサポートしていますが、ALGORITHM=INPLACE 構文を受け入れないため、代わりに ONLINE キーワードが使用されます。ONLINE および OFFLINE キーワードは、MySQL Cluster でのみサポートされます。これらのキーワードは、MySQL Cluster NDB 7.3 から非推奨です。MySQL Cluster NDB 7.4 では引き続きサポートされますが、将来のバージョンの MySQL Cluster で削除される可能性があります。正確な構文およびその他の詳細については、セクション13.1.7.2「MySQL Cluster での ALTER TABLE オンライン操作」を参照してください。

LOCK 句を使用すると、変更中のテーブルの並列読み取りおよび書き込みのレベルを制御できます。この句にデフォルト以外の値を指定すると、変更操作中に特定の量の並列アクセスまたは排他性が要求されるようにすることが可能であり、要求されたレベルのロックを使用できない場合は操作が停止されます。LOCK 句のパラメータは次のとおりです。

  • LOCK = DEFAULT

    指定された ALGORITHM 句 (存在する場合) および ALTER TABLE 操作に対する最大レベルの並列性: サポートされている場合は、並列読み取りおよび書き込みを許可します。そうでない場合、サポートされている場合は、並列読み取りを許可します。そうでない場合は、排他的アクセスを適用します。

  • LOCK = NONE

    サポートされている場合は、並列読み取りおよび書き込みを許可します。そうでない場合は、エラーメッセージを返します。

  • LOCK = SHARED

    サポートされている場合は、並列読み取りを許可しますが、書き込みはブロックします。書き込みは、指定された ALGORITHM 句 (存在する場合) および ALTER TABLE 操作に対して、並列書き込みがストレージエンジンによってサポートされている場合でもブロックされます。並列読み取りがサポートされていない場合は、エラーメッセージを返します。

  • LOCK = EXCLUSIVE

    排他的アクセスを適用します。これは、指定された ALGORITHM 句 (存在する場合) および ALTER TABLE 操作に対して、並列読み取り/書き込みがストレージエンジンによってサポートされている場合でも実行されます。

MySQL 5.6.3 の時点では、ALTER TABLE tbl_name FORCE を使用して、テーブルを再構築するnull変更操作を実行することもできます。以前は、FORCE オプションは認識されましたが、無視されました。MySQL 5.6.17 の時点では、オンライン DDL のサポートは FORCE オプションに対して提供されます。詳細は、セクション14.11.1「オンライン DDL の概要」を参照してください。

NDB テーブルの場合、可変幅カラム上のインデックスを追加および削除する操作は、そのほとんどの期間、テーブルコピーを行なったり、並列 DML アクションをブロックしたりすることなくオンラインで実行されます。セクション13.1.7.2「MySQL Cluster での ALTER TABLE オンライン操作」を参照してください。

使用上の注意

  • ALTER TABLE を使用するには、このテーブルに対する ALTERCREATE、および INSERT 権限が必要です。テーブルを名前変更するには、古いテーブル側で ALTER および DROP と、新しいテーブル側で ALTERCREATE、および INSERT 権限が必要です。

  • IGNORE は、標準 SQL への MySQL 拡張です。これは、新しいテーブル内の一意のキーに関して重複が存在する場合や、厳密モードが有効になっているときに警告が発生した場合の ALTER TABLE の動作を制御します。IGNORE が指定されていない場合は、重複キーエラーが発生すると、コピーは中止され、ロールバックされます。IGNORE が指定されている場合は、一意のキーが重複している行のうちの 1 行だけが使用されます。その他の競合している行は削除されます。正しくない値は、もっとも近い一致する許容可能な値に切り捨てられます。

    MySQL 5.6.17 の時点では、IGNORE 句は非推奨であり、使用すると警告が生成されます。MySQL 5.7 では、IGNORE は削除されます。

  • テーブルが書き込みロックされているときに、そのテーブル構造を変更するために ALTER TABLE が使用されると、保留中の INSERT DELAYED ステートメントは失われます。

  • table_option は、ENGINEAUTO_INCREMENTAVG_ROW_LENGTHMAX_ROWSROW_FORMAT などの、CREATE TABLE ステートメントで使用できる種類のテーブルオプションを示します。すべてのテーブルオプションのリストと各オプションの説明については、セクション13.1.17「CREATE TABLE 構文」を参照してください。ただし、ALTER TABLE は、DATA DIRECTORY および INDEX DIRECTORY テーブルオプションを無視します。

    たとえば、テーブルを InnoDB テーブルになるように変換するには、次のステートメントを使用します。

    ALTER TABLE t1 ENGINE = InnoDB;

    テーブルを InnoDB ストレージエンジンに切り替えるときの考慮事項については、セクション14.6.4「MyISAM から InnoDB へのテーブルの変換」を参照してください。

    ENGINE 句を指定すると、ALTER TABLE はテーブルを再構築します。これは、そのテーブルに指定されたストレージエンジンがすでに存在する場合にも当てはまります。

    既存の InnoDB テーブルに対して ALTER TABLE tbl_name ENGINE=INNODB を実行すると、nullALTER TABLE 操作が実行されます。これは、セクション14.10.4「テーブルのデフラグ」で説明されているように、InnoDB テーブルのデフラグに使用できます。InnoDB テーブルに対して ALTER TABLE tbl_name FORCE を実行しても、同じ機能が実行されます。

    MySQL 5.6.17 の時点では、ALTER TABLE tbl_name ENGINE=INNODBALTER TABLE tbl_name FORCE の両方がオンライン DDL (ALGORITHM=COPY) を使用します。詳細は、セクション14.11.1「オンライン DDL の概要」を参照してください。

    テーブルのストレージエンジンを変更しようとすると、セクション5.1.7「サーバー SQL モード」で説明されているように、その結果は目的のストレージエンジンが使用可能かどうかや、NO_ENGINE_SUBSTITUTION SQL モードの設定によって影響を受けます。

    データが誤って失われることのないように、ALTER TABLE を使用して、テーブルのストレージエンジンを MERGE または BLACKHOLE に変更することはできません。

    新しい行に使用される AUTO_INCREMENT カウンタの値を変更するには、次のようにします。

    ALTER TABLE t2 AUTO_INCREMENT = value;

    このカウンタを、現在使用されている値以下の値にリセットすることはできません。InnoDBMyISAM のどちらの場合も、この値が現在 AUTO_INCREMENT カラム内にある最大値以下である場合、この値は現在の AUTO_INCREMENT カラムの最大値に 1 を加えた値にリセットされます。

  • 1 つの ALTER TABLE ステートメントで、カンマで区切られた複数の ADDALTERDROP、および CHANGE 句を発行できます。これは、ALTER TABLE ステートメントごとに各句が 1 つしか許可されない標準 SQL への MySQL 拡張です。たとえば、1 つのステートメントで複数のカラムを削除するには、次のようにします。

    ALTER TABLE t2 DROP COLUMN c, DROP COLUMN d;
  • CHANGE col_nameDROP col_name、および DROP INDEX は、標準 SQL への MySQL 拡張です。

  • ワード COLUMN はオプションであり、省略できます。

  • column_definition 句は、ADDCHANGE に対して、CREATE TABLE に対するのと同じ構文を使用します。セクション13.1.17「CREATE TABLE 構文」を参照してください。

  • CHANGE old_col_namenew_col_namecolumn_definition 句を使用して、カラムの名前を変更できます。それを行うには、古いカラム名と新しいカラム名、およびそのカラムの現在の定義を指定します。たとえば、INTEGER カラムの名前を a から b に変更するには、次のように行うことができます。

    ALTER TABLE t1 CHANGE a b INTEGER;

    カラムの名前を変更せずに、その型を変更するには、古いカラム名と新しいカラム名が同じ場合でも、CHANGE 構文にはそれらの名前が引き続き必要です。例:

    ALTER TABLE t1 CHANGE b b BIGINT NOT NULL;

    MODIFY を使用しても、カラムの名前を変更せずに、その型を変更できます。

    ALTER TABLE t1 MODIFY b BIGINT NOT NULL;

    MODIFY は、Oracle の互換性のための ALTER TABLE への拡張です。

    CHANGE または MODIFY を使用する場合は、column_definition に、データ型および PRIMARY KEYUNIQUE などのインデックス属性以外の、新しいカラムに適用されるすべての属性を含める必要があります。元の定義には存在するが、新しい定義として指定されていない属性は引き継がれません。カラム col1INT UNSIGNED DEFAULT 1 COMMENT 'my column' として定義されているときに、このカラムを次のように変更するとします。

    ALTER TABLE t1 MODIFY col1 BIGINT;

    結果として得られるカラムは BIGINT として定義されますが、属性 UNSIGNED DEFAULT 1 COMMENT 'my column' は含まれません。これらを保持するには、ステートメントを次のようにしてください。

    ALTER TABLE t1 MODIFY col1 BIGINT UNSIGNED DEFAULT 1 COMMENT 'my column';
  • CHANGE または MODIFY を使用してデータ型を変更すると、MySQL は、既存のカラム値を新しい型にできるだけ変換しようとします。

    警告

    この変換によって、データが変更される可能性があります。たとえば、文字列カラムを短くすると、値が切り捨てられる可能性があります。新しいデータ型への変換によってデータが失われる場合は操作が成功しないようにするには、ALTER TABLE を使用する前に厳密な SQL モードを有効にします (セクション5.1.7「サーバー SQL モード」を参照してください)。

  • テーブル行内の特定の位置にカラムを追加するには、FIRST または AFTER col_name を使用します。デフォルトでは、そのカラムを最後に追加します。また、CHANGE または MODIFY 操作で FIRSTAFTER を使用して、テーブル内のカラムを並べ替えることもできます。

  • ALTER ... SET DEFAULT または ALTER ... DROP DEFAULT は、それぞれ、カラムの新しいデフォルト値を指定するか、または古いデフォルト値を削除します。古いデフォルトが削除され、かつカラムを NULL にできる場合、新しいデフォルトは NULL です。カラムを NULL にできない場合、MySQL は、セクション11.6「データ型デフォルト値」で説明されているようにデフォルト値を割り当てます。

  • DROP INDEX は、インデックスを削除します。これは、標準 SQL への MySQL 拡張です。セクション13.1.24「DROP INDEX 構文」を参照してください。インデックス名に確信がない場合は、SHOW INDEX FROM tbl_name を使用します。

  • テーブルからカラムが削除された場合、そのカラムは、それが含まれているすべてのインデックスからも削除されます。インデックスを構成するすべてのカラムが削除された場合は、そのインデックスも削除されます。CHANGE または MODIFY を使用して、インデックスが存在するカラムを短くしたときに、結果として得られるカラムの長さがインデックスの長さより短くなった場合、MySQL は自動的にそのインデックスを短くします。

  • テーブルに 1 つのカラムしか含まれていない場合は、そのカラムを削除できません。テーブルを削除することが目的である場合は、代わりに DROP TABLE を使用します。

  • DROP PRIMARY KEY は、主キーを削除します。主キーが存在しない場合は、エラーが発生します。主キーのパフォーマンス特性 (特に InnoDB テーブルの場合) については、セクション8.3.2「主キーの使用」を参照してください。

    テーブルに UNIQUE INDEX または PRIMARY KEY を追加すると、重複キーをできるだけ早く検出できるようにするために、MySQL はそれを一意でないどのインデックスよりも前に格納します。

  • 一部のストレージエンジンでは、インデックスの作成時にインデックスタイプを指定できます。index_type 指定子の構文は、USING type_name です。USING の詳細は、セクション13.1.13「CREATE INDEX 構文」を参照してください。推奨される位置は、カラムリストのあとです。このオプションをカラムリストの前に使用するためのサポートは、将来の MySQL リリースで削除される予定です。

    index_option 値は、インデックスの追加オプションを指定します。USING はそのようなオプションの 1 つです。許可される index_option 値の詳細は、セクション13.1.13「CREATE INDEX 構文」を参照してください。

  • ALTER TABLE ステートメントのあとに、インデックスカーディナリティー情報を更新するために ANALYZE TABLE の実行が必要になることがあります。セクション13.7.5.23「SHOW INDEX 構文」を参照してください。

  • ORDER BY を使用すると、特定の順序で行が含まれる新しいテーブルを作成できます。このオプションは主に、ほとんどは特定の順序で行をクエリーすることがわかっている場合に役立ちます。このオプションをテーブルの大幅な変更のあとに使用すると、パフォーマンスの向上が得られる可能性があります。場合によっては、テーブルが、あとでその並べ替えに使用するカラムごとの順番になっていれば、MySQL でのソートが簡単になることがあります。

    注記

    挿入や削除を行うと、このテーブルは指定された順序のままではなくなります。

    ORDER BY 構文では、ソートのためのカラム名を 1 つ以上指定できます。その各カラム名に続けて、オプションで、それぞれ昇順または降順のソート順序を示す ASC または DESC を指定できます。デフォルトは昇順です。ソート条件として許可されるのはカラム名だけです。任意の式は許可されていません。この句は、ほかのどの句よりもあとの最後に指定するようにしてください。

    InnoDB は常に、クラスタ化されたインデックスに従ってテーブル行を並べ替えるため、ORDER BYInnoDB テーブルでは意味がありません。

    注記

    パーティション化されたテーブルに対して使用されている場合、ALTER TABLE ... ORDER BY は、各パーティション内でのみ行を並べ替えます。

  • MyISAM テーブルに対して ALTER TABLE を使用した場合、一意でないインデックスはすべて (REPAIR TABLE として) 別のバッチに作成されます。多くのインデックスがあるときは、この方法で ALTER TABLE がはるかに早くなります。

    MyISAM テーブルの場合は、キーの更新を明示的に制御できます。ALTER TABLE ... DISABLE KEYS を使用して、一意でないインデックスの更新を停止するよう MySQL に指示します。次に、ALTER TABLE ... ENABLE KEYS を使用して、不足しているインデックスを再作成します。MyISAM はこれを、キーを 1 つずつ挿入するのに比べてはるかに高速な特殊なアルゴリズムで実行するため、一括挿入操作を実行する前にキーを無効にすると大幅な高速化が得られます。ALTER TABLE ... DISABLE KEYS を使用するには、先に説明した権限に加えて INDEX 権限が必要です。

    一意でないインデックスは、無効になっている間、有効なときにはこのインデックスを使用する SELECTEXPLAIN などのステートメントで無視されます。

  • MySQL 5.6.7 より前は、ALTER TABLE を使用して外部キーカラムの定義を変更すると、参照整合性が失われる可能性がありました。たとえば、NULL 値を含む外部キーカラムを NOT NULL になるように変更すると、NULL 値が空の文字列になりました。同様に、親テーブル内の行を削除する ALTER TABLE IGNORE によって、参照整合性が破壊される可能性がありました。

    5.6.7 の時点では、参照整合性が失われる可能性のある外部キーカラムへの変更がサーバーによって禁止されます。また、安全でない可能性のある、このようなカラムのデータ型への変更も禁止されます。たとえば、VARCHAR(20)VARCHAR(30) への変更は許可されますが、それを VARCHAR(1024) に変更することは、それによって個々の値を格納するために必要なバイト長の数が変更されるため許可されません。回避方法として、カラム定義を変更する前に ALTER TABLE ... DROP FOREIGN KEY を使用し、あとで ALTER TABLE ... ADD FOREIGN KEY を使用します。

  • FOREIGN KEY および REFERENCES 句は、ADD [CONSTRAINT [symbol]] FOREIGN KEY [index_name] (...) REFERENCES ... (...) を実装している InnoDB および NDB ストレージエンジンによってサポートされます。セクション14.6.6「InnoDB と FOREIGN KEY 制約」を参照してください。その他のストレージエンジンでは、これらの句は解析されますが、無視されます。CHECK 句は、すべてのストレージエンジンによって解析されますが、無視されます。セクション13.1.17「CREATE TABLE 構文」を参照してください。構文の句を受け入れるが、無視する理由は互換性のためです。つまり、ほかの SQL サーバーからコードを移植し、参照によってテーブルを作成するアプリケーションを実行することを容易にするためです。セクション1.7.2「MySQL と標準 SQL との違い」を参照してください。

    ALTER TABLE では、CREATE TABLE とは異なり、ADD FOREIGN KEYindex_name (指定されている場合) を無視し、自動的に生成された外部キー名を使用します。回避方法として、外部キー名を指定する CONSTRAINT 句を含めます。

    ADD CONSTRAINT name FOREIGN KEY (....) ...
    重要

    参照がカラム指定の一部として定義されているインラインの REFERENCES 指定は、暗黙のうちに無視されます。MySQL は、個別の FOREIGN KEY 指定の一部として定義されている REFERENCES 句のみを受け入れます。

    注記

    パーティション化された InnoDB テーブルは、外部キーをサポートしていません。この制限は、NDB テーブル ([LINEAR] KEY によって明示的にパーティション化されたテーブルを含む) には適用されません。詳細は、セクション19.6.2「ストレージエンジンに関連するパーティショニング制限」を参照してください。

  • InnoDB および NDB ストレージエンジンは、外部キーを削除するための ALTER TABLE の使用をサポートします。

    ALTER TABLE tbl_name DROP FOREIGN KEY fk_symbol;

    詳細は、セクション14.6.6「InnoDB と FOREIGN KEY 制約」を参照してください。

  • MySQL 5.6.6 より前は、同じ ALTER TABLE ステートメントでの外部キーの追加と削除は、問題が発生する場合があるためサポートされていません。操作ごとに個別のステートメントを使用するようにしてください。MySQL 5.6.6 の時点では、同じ ALTER TABLE ステートメントでの外部キーの追加と削除は ALTER TABLE ... ALGORITHM=INPLACE ではサポートされますが、ALTER TABLE ... ALGORITHM=COPY では未サポートのままです。

  • .ibd ファイル内の独自のテーブルスペースで作成された InnoDB テーブルの場合は、そのファイルを破棄したり、インポートしたりできます。.ibd ファイルを破棄するには、次のステートメントを使用します。

    ALTER TABLE tbl_name DISCARD TABLESPACE;

    これにより、現在の .ibd ファイルが削除されるため、最初にバックアップがあることを確認してください。テーブルスペースファイルが破棄されている間にテーブルの内容を変更しようとすると、エラーが発生します。テーブルスペースファイルが破棄されている間に、セクション14.11「InnoDB とオンライン DDL」に示されている DDL 操作を実行できます。

    バックアップ .ibd ファイルを元のテーブルにインポートするには、それをデータベースディレクトリにコピーしてから、次のステートメントを発行します。

    ALTER TABLE tbl_name IMPORT TABLESPACE;

    テーブルスペースファイルは、必ずしも、あとでインポートされるサーバー上に作成されている必要はありません。MySQL 5.6 では、テーブルスペースファイルの別のサーバーからのインポートが機能するのは、両方のサーバーのステータスが GA (General Availablility) であり、かつそれらのバージョンが同じシリーズ内にある場合です。そうでない場合、そのファイルはインポートされるサーバー上に作成されている必要があります。

    注記

    ALTER TABLE ... IMPORT TABLESPACE 機能は、インポートされたデータに対して外部キー制約を課しません。

    セクション14.5.2「InnoDB File-Per-Table モード」を参照してください。

  • テーブルのデフォルトの文字セットおよびすべての文字カラム (CHARVARCHARTEXT) を新しい文字セットに変更するには、次のようなステートメントを使用します。

    ALTER TABLE tbl_nameCONVERT TO CHARACTER SET charset_name [COLLATE collation_name];

    このステートメントでは、すべての文字カラムの照合順序も変更されます。使用する照合順序を示す COLLATE 句を指定しない場合、このステートメントは、その文字セットのデフォルトの照合順序を使用します。この照合順序が目的とするテーブル使用に適していない (たとえば、大文字と小文字が区別される照合順序から大文字と小文字が区別されない照合順序に変更されてしまう) 場合は、照合順序を明示的に指定します。

    データ型が VARCHAR か、またはいずれかの TEXT 型であるカラムに対して、CONVERT TO CHARACTER SET は、新しいカラムが確実に元のカラムと同じ数の文字を格納できる十分な長さになるように、必要に応じてデータ型を変更します。たとえば、TEXT カラムには、そのカラム内の値のバイト長 (最大 65,535) を格納するための 2 バイト長があります。latin1TEXT カラムの場合は、各文字に 1 バイトが必要なため、このカラムには最大 65,535 文字を格納できます。このカラムが utf8 に変換された場合は、各文字に最大 3 バイトが必要になる可能性があるため、可能性のある最大の長さは 3 × 65,535 = 196,605 バイトになります。その長さは TEXT カラムのバイト長には収まらないため、MySQL はそのデータ型を、バイト長に 196,605 の値を記録できる最小の文字列型である MEDIUMTEXT に変換します。同様に、VARCHAR カラムは MEDIUMTEXT に変換される可能性があります。

    今説明した型のデータ型の変更を回避するには、CONVERT TO CHARACTER SET を使用しないでください。代わりに、MODIFY を使用して個々のカラムを変更します。例:

    ALTER TABLE t MODIFY latin1_text_col TEXT CHARACTER SET utf8;
    ALTER TABLE t MODIFY latin1_varchar_col VARCHAR(M) CHARACTER SET utf8;

    CONVERT TO CHARACTER SET binary を指定した場合、CHARVARCHAR、および TEXT カラムは、それぞれ対応するバイナリ文字列型 (BINARYVARBINARYBLOB) に変換されます。つまり、これらのカラムには文字セットが含まれなくなるため、以降の CONVERT TO 操作は適用されません。

    charset_nameDEFAULT である場合は、データベース文字セットが使用されます。

    警告

    CONVERT TO 操作は、文字セット間でカラム値を変換します。これは、ある文字セット (latin1 など) のカラムがあるが、格納された値が実際には、ほかの何らかの互換性のない文字セット (utf8 など) を使用している場合に必要なものではありません。この場合は、このようなカラムごとに、次を実行する必要があります。

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

    これが機能する理由は、BLOB カラムとの間で変換する場合は変換が発生しないためです。

    テーブルのデフォルトの文字セットのみを変更するには、次のステートメントを使用します。

    ALTER TABLE tbl_name DEFAULT CHARACTER SET charset_name;

    ワード DEFAULT はオプションです。デフォルトの文字セットは、あとで (たとえば、ALTER TABLE ... ADD column で) テーブルに追加するカラムの文字セットを指定しない場合に使用される文字セットです。

mysql_info() C API 関数を使用すると、ALTER TABLE によってコピーされた行数、および (IGNORE が使用されている場合は) 一意のキー値の重複のために削除された行数を確認できます。セクション23.7.7.35「mysql_info()」を参照してください。

13.1.7.1 ALTER TABLE パーティション操作

ALTER TABLE のパーティション化関連の句は、再パーティション化、パーティションの追加、削除、マージ、および分割、パーティション化の保守の実行などのために、パーティション化されたテーブルで使用できます。

  • 単に、パーティション化されたテーブルに対して ALTER TABLEpartition_options 句を使用するだけで、partition_options で定義されたパーティション化スキームに従って、そのテーブルが再パーティション化されます。この句は、常に PARTITION BY で始まり、CREATE TABLEpartition_options 句に適用されるのと同じ構文およびその他のルールに従います (詳細は、セクション13.1.17「CREATE TABLE 構文」を参照してください)。また、まだパーティション化されていない既存のテーブルのパーティション化にも使用できます。たとえば、次に示すように定義された (パーティション化されていない) テーブルを考えてみます。

    CREATE TABLE t1 ( id INT, year_col INT
    );

    このテーブルは、次のステートメントを使用し、id カラムをパーティション化キーとして使用して HASH によって 8 つのパーティションにパーティション化できます。

    ALTER TABLE t1 PARTITION BY HASH(id) PARTITIONS 8;

    MySQL 5.6.11 以降では、[SUB]PARTITION BY [LINEAR] KEYALGORITHM オプションがサポートされます。ALGORITHM=1 を指定すると、サーバーは、パーティション内の行の配置を計算するときに MySQL 5.1 と同じキーハッシュ関数を使用します。ALGORITHM=2 は、サーバーが、MySQL 5.5 以降で実装され、KEY によってパーティション化された新しいテーブルに対してデフォルトで使用されるキーハッシュ関数を使用することを示します。(MySQL 5.5 以降で採用されたキーハッシュ関数によって作成されたパーティション化されたテーブルを MySQL 5.1 サーバーで使用することはできません。)このオプションを指定しない場合は、ALGORITHM=2 を使用するのと同じ効果があります。このオプションは、主に [LINEAR] KEY によってパーティション化されたテーブルを MySQL 5.1 以降の MySQL バージョン間でアップグレードまたはダウングレードするときに使用するか、または MySQL 5.5 以降のサーバー上で、MySQL 5.1 サーバー上で使用できる KEY または LINEAR KEY によってパーティション化されたテーブルを作成することを目的にしています。

    MySQL 5.1 で作成された、KEY によってパーティション化されたテーブルをアップグレードするには、最初に SHOW CREATE TABLE を実行し、表示される正確なカラムおよびパーティションの数をメモします。次に、CREATE TABLE ステートメントとまったく同じカラムリストおよびパーティションの数を使用して ALTER TABLE ステートメントを実行しますが、そのとき PARTITION BY キーワードの直後に ALGORITHM=2 を追加します。(元のテーブル定義に LINEAR キーワードが使用されていた場合は、そのキーワードも含めるようにしてください。)mysql クライアントでのセッションの例を次に示します。

    mysql> SHOW CREATE TABLE p\G*************************** 1. row *************************** Table: p
    Create Table: CREATE TABLE `p` ( `id` int(11) NOT NULL AUTO_INCREMENT, `cd` datetime NOT NULL, PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=latin1
    1 row in set (0.00 sec)
    mysql> ALTER TABLE pPARTITION BY LINEAR KEY ALGORITHM=2 (id) PARTITIONS 32;Query OK, 0 rows affected (5.34 sec)
    Records: 0 Duplicates: 0 Warnings: 0
    mysql> SHOW CREATE TABLE p\G*************************** 1. row *************************** Table: p
    Create Table: CREATE TABLE `p` ( `id` int(11) NOT NULL AUTO_INCREMENT, `cd` datetime NOT NULL, PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=latin1
    1 row in set (0.00 sec)

    MySQL 5.5 以降で使用されているデフォルトのキーハッシュを使用して作成されたテーブルを、MySQL 5.1 サーバーで使用できるようにダウングレードする場合も同様です。ただし、この場合は、そのテーブルのパーティションが強制的に MySQL 5.1 のキーハッシュ関数を使用して再構築されるように、ALGORITHM=1 を使用するようにしてください。MySQL 5.5 以降ではデフォルトで使用される改善された KEY ハッシュ関数により、古い実装で見つかった多くの問題に対する修正が提供されるため、MySQL 5.1 サーバーとの互換性のために必要な場合を除き、これは行わないようにすることをお勧めします。

    注記

    ALTER TABLE ... PARTITION BY ALGORITHM=2 [LINEAR] KEY ... を使用してアップグレードされたテーブルは、MySQL 5.1 サーバーでは使用できなくなります。(このようなテーブルを MySQL 5.1 サーバーでふたたび使用できるようにするには、ALTER TABLE ... PARTITION BY ALGORITHM=1 [LINEAR] KEY ... を使用してダウングレードする必要があります。)

    ALTER TABLE ... PARTITION BY ステートメントを使用して作成されたテーブルは、CREATE TABLE ... PARTITION BY を使用して作成されたテーブルと同じルールに従う必要があります。これには、そのテーブルに含まれている可能性のあるすべての一意のキー (すべての主キーを含む) と、パーティショニング式で使用されている 1 つまたは複数のカラムの間の関係を管理するルールが含まれます。これについては、セクション19.6.1「パーティショニングキー、主キー、および一意キー」で説明されています。また、パーティションの数を指定するための CREATE TABLE ... PARTITION BY のルールも ALTER TABLE ... PARTITION BY に適用されます。

    ALTER TABLE ADD PARTITIONpartition_definition 句は、CREATE TABLE ステートメントの同じ名前の句と同じオプションをサポートしています。(構文と説明については、セクション13.1.17「CREATE TABLE 構文」を参照してください。)次に示すように作成されたパーティション化されたテーブルがあるとします。

    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)
    );

    このテーブルに、2002 より小さい値を格納するための新しいパーティション p3 を次のように追加できます。

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

    DROP PARTITION を使用すると、1 つ以上の RANGE または LIST パーティションを削除できます。このステートメントを HASH または KEY パーティションに使用することはできません。代わりに COALESCE PARTITION を使用します (下を参照してください)。partition_names リストで名前が指定されている削除されたパーティションに格納されていたデータはすべて破棄されます。たとえば、前に定義されたテーブル t1 の場合は、p0 および p1 という名前のパーティションを次に示すように削除できます。

    ALTER TABLE t1 DROP PARTITION p0, p1;
    注記

    DROP PARTITION は、NDB ストレージエンジンを使用するテーブルでは機能しません。セクション19.3.1「RANGE および LIST パーティションの管理」およびセクション18.1.6「MySQL Cluster の既知の制限」を参照してください。

    ADD PARTITIONDROP PARTITION は現在、IF [NOT] EXISTS をサポートしていません。

    パーティション化されたテーブルの名前変更がサポートされています。ALTER TABLE ... REORGANIZE PARTITION を使用して、間接的に個々のパーティションの名前を変更できます。ただし、この操作によってパーティションのデータのコピーが作成されます。

    MySQL 5.6 では、TRUNCATE PARTITION オプションを使用して、選択したパーティションの行を削除できます。このオプションは、1 つ以上のパーティション名のカンマ区切りリストを受け取ります。たとえば、次のように定義されたテーブル t1 を考えてみます。

    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), PARTITION p3 VALUES LESS THAN (2003), PARTITION p4 VALUES LESS THAN (2007)
    );

    パーティション p0 のすべての行を削除するには、次のステートメントを使用できます。

    ALTER TABLE t1 TRUNCATE PARTITION p0;

    今示したステートメントには、次の DELETE ステートメントと同じ効果があります。

    DELETE FROM t1 WHERE year_col < 1991;

    複数のパーティションを切り詰める場合、パーティションが連続している必要はありません。これにより、通常、DELETE ステートメントで実行された場合は非常に複雑な WHERE 条件が必要になる、パーティション化されたテーブルでの削除操作が大幅に簡素化される可能性があります。たとえば、次のステートメントは、パーティション p1p3 のすべての行を削除します。

    ALTER TABLE t1 TRUNCATE PARTITION p1, p3;

    同等の DELETE ステートメントを次に示します。

    DELETE FROM t1 WHERE (year_col >= 1991 AND year_col < 1995) OR (year_col >= 2003 AND year_col < 2007);

    パーティション名のリストの代わりに ALL キーワードを使用することもできます。この場合、このステートメントはテーブル内のすべてのパーティションに対して機能します。

    TRUNCATE PARTITION は行を削除するだけです。そのテーブル自体や、どのパーティションの定義も変更されません。

    注記

    TRUNCATE PARTITION は、サブパーティションでは機能しません。

    次のようなクエリーを使用して INFORMATION_SCHEMA.PARTITIONS テーブルをチェックすることにより、行が削除されたことを確認できます。

    SELECT PARTITION_NAME, TABLE_ROWS FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_NAME = 't1';

    TRUNCATE PARTITION は、MyISAMInnoDB、または MEMORY ストレージエンジンを使用するパーティション化されたテーブルでのみサポートされます。また、BLACKHOLE テーブルに対しても機能します (ただし、何の効果もありません)。ARCHIVE テーブルではサポートされません。

    HASH または KEY によってパーティション化されたテーブルで COALESCE PARTITION を使用すると、そのパーティションの数を number だけ減らすことができます。次の定義を使用して、テーブル t2 を作成したとします。

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

    t2 によって使用されるパーティションの数を、次のステートメントを使用して 6 から 4 に減らすことができます。

    ALTER TABLE t2 COALESCE PARTITION 2;

    最後の number 個のパーティションに含まれているデータは、残りのパーティションにマージされます。この場合は、パーティション 4 と 5 が最初の 4 つのパーティション (0、1、2、および 3 の番号を持つ各パーティション) にマージされます。

    パーティション化されたテーブルで使用される (すべてではなく) 一部のパーティションを変更するには、REORGANIZE PARTITION を使用できます。このステートメントは、次のいくつかの方法で使用できます。

    • 一連のパーティションを単一パーティションにマージします。これは、partition_names リストにいくつかのパーティションの名前を指定し、partition_definition に 1 つの定義を指定することによって実行できます。

    • 既存のパーティションをいくつかのパーティションに分割します。これは、partition_names に単一パーティションを指定し、複数の partition_definitions を指定することによって実行できます。

    • VALUES LESS THAN を使用して、定義されたパーティションのサブセットの範囲を変更するか、または VALUES IN を使用して、定義されたパーティションのサブセットの値リストを変更します。

    • このステートメントはまた、HASH パーティション化を使用して自動的にパーティション化されるテーブルに対して partition_names INTO (partition_definitions) オプションなしで使用すると、データを強制的に再配布できます。(現在、このように自動的にパーティション化されるのは NDB テーブルだけです。)これは、既存の MySQL Cluster に新しい MySQL Cluster データノードをオンラインで追加したあと、既存の MySQL Cluster テーブルデータを新しいデータノードに再配布する必要がある MySQL Cluster で役立ちます。このような場合は、ONLINE オプションを使用してこのステートメントを呼び出すようにしてください。つまり、次に示すようにします。

      ALTER ONLINE TABLE table REORGANIZE PARTITION;

      オンラインのテーブル再編成と同時にほかの DDL を実行することはできません。つまり、ALTER ONLINE TABLE ... REORGANIZE PARTITION ステートメントの実行中は、ほかの DDL ステートメントを発行できません。MySQL Cluster データノードをオンラインで追加する方法の詳細は、セクション18.5.13「MySQL Cluster データノードのオンライン追加」を参照してください。

      ALTER ONLINE TABLE ... REORGANIZE PARTITION は、MAX_ROWS オプションを使用して作成されたテーブルでは機能しません。このステートメントは、元の CREATE TABLE ステートメントで指定された一定の MAX_ROWS 値を使用して必要なパーティションの数を決定するため、新しいパーティションが作成されないためです。テーブルの行の最大数を増やすには、ALTER ONLINE TABLE ... MAX_ROWS=rows を使用できます。このあと、ALTER ONLINE TABLE ... REORGANIZE PARTITION は、この大きくなった新しい値を使用してパーティションの数を増やすことができます。これが機能するには、rows の値を、元の CREATE TABLE ステートメントで MAX_ROWS に指定された値より大きくする必要があります。

      明示的にパーティション化されたテーブルに対して、REORGANIZE PARTITIONpartition_names INTO (partition_definitions) オプションなしで使用しようとすると、REORGANIZE PARTITION without parameters can only be used on auto-partitioned tables using HASH partitioningエラーが発生します。

    注記

    明示的に名前が付けられていないパーティションに対して、MySQL は自動的に p0p1p2 などのデフォルト名を付けます。同じことがサブパーティションにも当てはまります。

    ALTER TABLE ... REORGANIZE PARTITION ステートメントの詳細および例については、セクション19.3.1「RANGE および LIST パーティションの管理」を参照してください。

  • MySQL 5.6 では、ALTER TABLE ... EXCHANGE PARTITION ステートメントを使用して、テーブルパーティションまたはサブパーティションを別のテーブルと交換できます。つまり、パーティションまたはサブパーティション内の既存の任意の行をパーティション化されていないテーブルに移動したり、パーティション化されていないテーブル内の既存の任意の行をテーブルパーティションまたはサブパーティションに移動したりできます。

    使用方法および例については、セクション19.3.3「パーティションとサブパーティションをテーブルと交換する」を参照してください。

  • いくつかの追加オプションによって、パーティション化されていないテーブルのために CHECK TABLEREPAIR TABLE などのステートメントによって実装されている機能 (これは、パーティション化されたテーブルでもサポートされます。詳細は、セクション13.7.2「テーブル保守ステートメント」を参照してください) に類似したパーティションの保守および修復機能が提供されます。これには、ANALYZE PARTITIONCHECK PARTITIONOPTIMIZE PARTITIONREBUILD PARTITION、および REPAIR PARTITION が含まれます。これらの各オプションは、1 つ以上のパーティション名から成るカンマで区切られた partition_names 句を受け取ります。これらのパーティションは、変更されるテーブル内にすでに存在する必要があります。partition_names の代わりに ALL キーワードを使用することもできます。その場合、このステートメントはテーブル内のすべてのパーティションに対して機能します。詳細および例については、セクション19.3.4「パーティションの保守」を参照してください。

    InnoDB などの一部の MySQL ストレージエンジンは、パーティションごとの最適化をサポートしていません。このようなストレージエンジンを使用したパーティション化されたテーブルに対して、ALTER TABLE ... OPTIMIZE PARTITION はテーブル全体を再構築します。これは既知の問題です。MySQL 5.6.9 から、このようなテーブルに対してこのステートメントを実行するとテーブル全体が再構築および分析され、該当する警告が発行されます。(Bug #11751825、Bug #42822)

    この問題を回避するには、代わりに、ステートメント ALTER TABLE ... REBUILD PARTITION および ALTER TABLE ... ANALYZE PARTITION を使用します。

    ANALYZE PARTITIONCHECK PARTITIONOPTIMIZE PARTITION、および REPAIR PARTITION オプションは、パーティション化されていないテーブルには許可されません。

  • REMOVE PARTITIONING を使用すると、テーブルのパーティション化を削除でき、そのテーブルやデータはそれ以外の影響を受けません。このオプションは、カラムやインデックスの追加、削除、名前変更などのために使用されるその他の ALTER TABLE オプションと組み合わせることができます。

  • ALTER TABLEENGINE オプションを使用すると、パーティション化に影響を与えることなく、テーブルで使用されるストレージエンジンが変更されます。

MySQL 5.6.6 より前は、MyISAM (または、テーブルレベルのロックを使用する別のストレージエンジン) を使用するパーティション化されたテーブルに対して ALTER TABLE ... EXCHANGE PARTITION または ALTER TABLE ... TRUNCATE PARTITION が実行されると、そのパーティション化されたテーブル全体がロックされました。MySQL 5.6.6 以降では、このような場合、実際に読み取られたパーティションのみがロックされます。これは、行レベルロックを採用している (InnoDB などの) ストレージエンジンを使用するパーティション化されたテーブルには影響しませんでした (現在も影響しません)。セクション19.6.4「パーティショニングとロック」を参照してください。

ALTER TABLE ステートメントには、ほかの変更指定に加えて、PARTITION BY または REMOVE PARTITIONING 句を含めることができますが、PARTITION BY または REMOVE PARTITIONING 句は、ほかのどの指定よりもあとの最後に指定する必要があります。

ADD PARTITIONDROP PARTITIONCOALESCE PARTITIONREORGANIZE PARTITIONANALYZE PARTITIONCHECK PARTITION、および REPAIR PARTITION オプションは、個々のパーティションに対して機能するため、1 つの ALTER TABLE 内でほかの変更指定と組み合わせることはできません。詳細は、セクション13.1.7.1「ALTER TABLE パーティション操作」を参照してください。

特定の ALTER TABLE ステートメントでは、次のいずれか 1 つのオプションの単一インスタンスのみを使用できます。PARTITION BYADD PARTITIONDROP PARTITIONTRUNCATE PARTITIONEXCHANGE PARTITIONREORGANIZE PARTITION、または COALESCE PARTITIONANALYZE PARTITIONCHECK PARTITIONOPTIMIZE PARTITIONREBUILD PARTITIONREMOVE PARTITIONING

たとえば、次の 2 つのステートメントは無効です。

ALTER TABLE t1 ANALYZE PARTITION p1, ANALYZE PARTITION p2;
ALTER TABLE t1 ANALYZE PARTITION p1, CHECK PARTITION p2;

最初のケースでは、次のように、分析される両方のパーティションを一覧表示した 1 つの ANALYZE PARTITION オプションを含む 1 つのステートメントを使用して、テーブル t1 のパーティション p1p2 を同時に分析できます。

ALTER TABLE t1 ANALYZE PARTITION p1, p2;

2 番目のケースでは、同じテーブルの別のパーティションに対する ANALYZE 操作と CHECK 操作を同時に実行することはできません。代わりに、次のように、2 つの個別のステートメントを発行する必要があります。

ALTER TABLE t1 ANALYZE PARTITION p1;
ALTER TABLE t1 CHECK PARTITION p2;

ANALYZECHECKOPTIMIZEREBUILDREPAIR、および TRUNCATE 操作は、サブパーティションではサポートされません。

13.1.7.2 MySQL Cluster での ALTER TABLE オンライン操作

このセクションでは、MySQL Cluster で実装されたオンラインのテーブルスキーマ変更について説明します。InnoDB ストレージエンジンもまた、MySQL Cluster によってサポートされるものとは異なる構文を使用して、このような操作をオンラインで実行できます。詳細は、セクション14.11「InnoDB とオンライン DDL」を参照してください。

NDB テーブルの可変幅カラム上のインデックスを追加および削除する操作はオンラインで実行されます。オンライン操作はコピーなしです。つまり、インデックスを再作成する必要はありません。変更されるテーブルが、MySQL Cluster 内のほかの API ノードによるアクセスからロックされることはありません (ただし、このセクションのあとの方にある「制限」を参照してください)。このような操作では、複数の API ノードを含むクラスタで行われる NDB テーブルの変更にシングルユーザーモードは必要ありません。オンライン DDL 操作中も、トランザクションは中断なく続行できます。

ONLINE キーワードを使用すると、NDB テーブルに対してオンライン ADD COLUMNADD INDEX (CREATE INDEX ステートメントを含む)、および DROP INDEX 操作を実行できます。また、NDB テーブルのオンラインでの名前変更もサポートされます。

注記

ONLINE および OFFLINE キーワードは、MySQL Cluster でのみサポートされます。標準の MySQL Server 5.6 リリースでは、ONLINE または OFFLINE キーワードを ALTER TABLECREATE INDEX、または DROP INDEX ステートメントで使用しようとすると、エラーが発生します。

ONLINE および OFFLINE キーワードは、MySQL Cluster NDB 7.3 から非推奨です。MySQL Cluster NDB 7.4 では引き続きサポートされますが、将来のバージョンの MySQL Cluster で削除される可能性があります。

現在、ディスクベースのカラムを NDB テーブルにオンラインで追加することはできません。つまり、テーブルレベルの STORAGE DISK オプションを使用する NDB テーブルにインメモリーカラムを追加する場合は、新しいカラムをメモリーベースのストレージの使用として明示的に宣言する必要があります。たとえば、すでにテーブルスペース ts1 を作成していると仮定して、テーブル t1 を次のように作成するとします。

mysql> CREATE TABLE t1 ( > c1 INT NOT NULL PRIMARY KEY, > c2 VARCHAR(30) > ) > TABLESPACE ts1 STORAGE DISK > ENGINE NDB;Query OK, 0 rows affected (1.73 sec)
Records: 0 Duplicates: 0 Warnings: 0

次に示すように、新しいインメモリーカラムをこのテーブルにオンラインで追加できます。

mysql> ALTER ONLINE TABLE t1 ADD COLUMN c3 INT COLUMN_FORMAT DYNAMIC STORAGE MEMORY;Query OK, 0 rows affected (1.25 sec)
Records: 0 Duplicates: 0 Warnings: 0

STORAGE MEMORY オプションが省略されている場合、このステートメントは失敗します。

mysql> ALTER ONLINE TABLE t1 ADD COLUMN c3 INT COLUMN_FORMAT DYNAMIC;ERROR 1235 (42000): This version of MySQL doesn't yet support
'ALTER ONLINE TABLE t1 ADD COLUMN c3 INT COLUMN_FORMAT DYNAMIC'

COLUMN_FORMAT DYNAMIC オプションを省略した場合は、動的なカラムフォーマットが自動的に使用されますが、次に示すような警告が発行されます。

mysql> ALTER ONLINE TABLE t1 ADD COLUMN c3 INT STORAGE MEMORY;Query OK, 0 rows affected, 1 warning (1.17 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> SHOW WARNINGS;+---------+------+---------------------------------------------------------------+
| Level | Code | Message |
+---------+------+---------------------------------------------------------------+
| Warning | 1478 | Converted FIXED field to DYNAMIC to enable on-line ADD COLUMN |
+---------+------+---------------------------------------------------------------+
1 row in set (0.00 sec)
mysql> SHOW CREATE TABLE t1\G*************************** 1. row *************************** Table: t1
Create Table: CREATE TABLE `t1` ( `c1` int(11) NOT NULL, `c2` varchar(30) DEFAULT NULL, `c3` int(11) DEFAULT NULL, `t4` int(11) DEFAULT NULL, PRIMARY KEY (`c1`)
) ENGINE=ndbcluster DEFAULT CHARSET=latin1
1 row in set (0.03 sec)
注記

STORAGE および COLUMN_FORMAT キーワードは、MySQL Cluster でのみサポートされます。ほかのどのバージョンの MySQL でも、このどちらかのキーワードを CREATE TABLE または ALTER TABLE ステートメントで使用しようとすると、エラーが発生します。

NDB テーブルに対して、ステートメント ALTER ONLINE TABLE ... REORGANIZE PARTITIONpartition_names INTO (partition_definitions) オプションなしで使用することもできます。これを使用すると、オンラインでクラスタに追加された新しいデータノードの間で MySQL Cluster データを再配布できます。このステートメントの詳細は、セクション13.1.7.1「ALTER TABLE パーティション操作」を参照してください。MySQL Cluster にデータノードをオンラインで追加する方法の詳細は、セクション18.5.13「MySQL Cluster データノードのオンライン追加」を参照してください。

MySQL Cluster オンライン操作の制限

オンライン DROP COLUMN 操作はサポートされていません。

カラムを追加するか、あるいはインデックスを追加または削除するオンライン ALTER TABLECREATE INDEX、または DROP INDEX ステートメントは、次の制限に従います。

  • 特定のオンライン ALTER TABLE では、ADD COLUMNADD INDEXDROP INDEX のいずれか 1 つのみを使用できます。1 つのステートメントで、1 つ以上のカラムをオンラインで追加できます。1 つのステートメントで、1 つのインデックスのみをオンラインで作成または削除できます。

  • 変更されるテーブルは、オンライン ALTER TABLEADD COLUMNADD INDEX、または DROP INDEX 操作 (あるいは CREATE INDEX または DROP INDEX ステートメント) が実行されている API ノード以外の API ノードに対してロックされません。ただし、オンライン操作が実行されている間、このテーブルは同じ API ノードから発信されているほかのすべての操作に対してロックされます。

  • 変更されるテーブルには明示的な主キーが存在する必要があります。NDB ストレージエンジンによって作成された非表示の主キーは、この目的には不十分です。

  • テーブルで使用されるストレージエンジンをオンラインで変更することはできません。

  • MySQL Cluster ディスクデータテーブルで使用された場合、カラムのストレージ型 (DISK または MEMORY) をオンラインで変更することはできません。つまり、操作がオンラインで実行されるような方法でインデックスを追加または削除するときに、1 つまたは複数のカラムのストレージ型が変更されるようにする場合は、インデックスを追加または削除するステートメントで OFFLINE キーワードを使用する必要があります。

オンラインで追加されるカラムは BLOB または TEXT 型を使用できず、次の条件を満たす必要があります。

  • このカラムは動的である必要があります。つまり、COLUMN_FORMAT DYNAMIC を使用して作成できる必要があります。COLUMN_FORMAT DYNAMIC オプションを省略した場合は、動的なカラムフォーマットが自動的に使用されます。

  • このカラムは NULL 値を許可する必要があり、NULL 以外の明示的なデフォルト値があってはなりません。オンラインで追加されるカラムは、次に示すように、DEFAULT NULL として自動的に作成されます。

    mysql> CREATE TABLE t1 ( > c1 INT NOT NULL AUTO_INCREMENT PRIMARY KEY > ) ENGINE=NDB;Query OK, 0 rows affected (1.44 sec)
    mysql> ALTER ONLINE TABLE t1 > ADD COLUMN c2 INT, > ADD COLUMN c3 INT;Query OK, 0 rows affected, 2 warnings (0.93 sec)
    mysql> SHOW CREATE TABLE t1\G*************************** 1. row *************************** Table: t1
    Create Table: CREATE TABLE `t1` ( `c1` int(11) NOT NULL AUTO_INCREMENT, `c2` int(11) DEFAULT NULL, `c3` int(11) DEFAULT NULL, PRIMARY KEY (`c1`)
    ) ENGINE=ndbcluster DEFAULT CHARSET=latin1
    1 row in set (0.00 sec)
  • このカラムは、既存のすべてのカラムのあとに追加する必要があります。既存のいずれかのカラムの前に、または FIRST キーワードを使用してオンラインでカラムを追加しようとすると、このステートメントはエラーで失敗します。

  • 既存のテーブルカラムをオンラインで並べ替えることはできません。

前の制限は、テーブルまたはカラムの名前を変更するだけの操作には適用されません。

NDB テーブルに対するオンライン ALTER TABLE 操作の場合、固定フォーマットのカラムは次に示すように、オンラインで追加されるか、またはインデックスがオンラインで作成または削除されたときに動的なカラムに変換されます。

mysql> CREATE TABLE t1 ( > c1 INT NOT NULL AUTO_INCREMENT PRIMARY KEY > ) ENGINE=NDB;Query OK, 0 rows affected (1.44 sec)
mysql> ALTER ONLINE TABLE t1 ADD COLUMN c2 INT, ADD COLUMN c3 INT;Query OK, 0 rows affected, 2 warnings (0.93 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> SHOW WARNINGS;+---------+------+---------------------------------------------------------------+
| Level | Code | Message |
+---------+------+---------------------------------------------------------------+
| Warning | 1475 | Converted FIXED field to DYNAMIC to enable on-line ADD COLUMN |
| Warning | 1475 | Converted FIXED field to DYNAMIC to enable on-line ADD COLUMN |
+---------+------+---------------------------------------------------------------+
2 rows in set (0.00 sec)
注記

既存のカラム (テーブルの主キーを含む) は、動的である必要はありません。動的である必要があるのは、オンラインで追加される 1 つまたは複数のカラムだけです。

mysql> CREATE TABLE t2 ( > c1 INT NOT NULL AUTO_INCREMENT PRIMARY KEY COLUMN_FORMAT FIXED > ) ENGINE=NDB;Query OK, 0 rows affected (2.10 sec)
mysql> ALTER ONLINE TABLE t2 ADD COLUMN c2 INT;Query OK, 0 rows affected, 1 warning (0.78 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> SHOW WARNINGS;+---------+------+---------------------------------------------------------------+
| Level | Code | Message |
+---------+------+---------------------------------------------------------------+
| Warning | 1475 | Converted FIXED field to DYNAMIC to enable on-line ADD COLUMN |
+---------+------+---------------------------------------------------------------+
1 row in set (0.00 sec)

名前の変更操作によって、カラムが FIXED から DYNAMIC のカラムフォーマットに変換されることはありません。COLUMN_FORMAT の詳細は、セクション13.1.17「CREATE TABLE 構文」を参照してください。

KEYCONSTRAINT、および IGNORE キーワードは、ONLINE キーワードを使用している ALTER TABLE ステートメントでサポートされます。

13.1.7.3 ALTER TABLE の例

次に示すように作成されているテーブル t1 から始めます。

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

テーブルの名前を t1 から t2 に変更するには、次のようにします。

ALTER TABLE t1 RENAME t2;

カラム aINTEGER から TINYINT NOT NULL に変更し (名前は同じままにします)、またカラム bCHAR(10) から CHAR(20) に変更し、さらにその名前を b から c に変更するには、次のようにします。

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

d という名前の新しい TIMESTAMP カラムを追加するには、次のようにします。

ALTER TABLE t2 ADD d TIMESTAMP;

カラム d にインデックスを、またカラム aUNIQUE インデックスを追加するには、次のようにします。

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

カラム c を削除するには、次のようにします。

ALTER TABLE t2 DROP COLUMN c;

c という名前の新しい AUTO_INCREMENT 整数カラムを追加するには、次のようにします。

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

AUTO_INCREMENT カラムにはインデックスを設定する必要があるため c に (PRIMARY KEY として) インデックスを設定し、また主キーカラムは NULL にできないため cNOT NULL として宣言します。

NDB テーブルの場合は、テーブルまたはカラムに使用されるストレージ型を変更することもできます。たとえば、次に示すように作成された NDB テーブルを考えてみます。

mysql> CREATE TABLE t1 (c1 INT) TABLESPACE ts_1 ENGINE NDB;Query OK, 0 rows affected (1.27 sec)

このテーブルをディスクベースのストレージに変換するには、次の ALTER TABLE ステートメントを使用できます。

mysql> ALTER TABLE t1 TABLESPACE ts_1 STORAGE DISK;Query OK, 0 rows affected (2.99 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> SHOW CREATE TABLE t1\G*************************** 1. row *************************** Table: t1
Create Table: CREATE TABLE `t1` ( `c1` int(11) DEFAULT NULL
)
ENGINE=ndbcluster DEFAULT CHARSET=latin1
1 row in set (0.01 sec)

テーブルが最初に作成されたときにテーブルスペースが参照されている必要はありませんが、テーブルスペースは ALTER TABLE によって参照される必要があります。

mysql> CREATE TABLE t2 (c1 INT) ts_1 ENGINE NDB;Query OK, 0 rows affected (1.00 sec)
mysql> ALTER TABLE t2 STORAGE DISK;ERROR 1005 (HY000): Can't create table 'c.#sql-1750_3' (errno: 140)mysql> ALTER TABLE t2 TABLESPACE ts_1 STORAGE DISK;Query OK, 0 rows affected (3.42 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> SHOW CREATE TABLE t2\G*************************** 1. row *************************** Table: t1
Create Table: CREATE TABLE `t2` ( `c1` int(11) DEFAULT NULL
)
ENGINE=ndbcluster DEFAULT CHARSET=latin1
1 row in set (0.01 sec)

個々のカラムのストレージ型を変更するには、ALTER TABLE ... MODIFY [COLUMN] を使用できます。たとえば、次の CREATE TABLE ステートメントを使用して、2 つのカラムを含む MySQL Cluster ディスクデータテーブルを作成するとします。

mysql> CREATE TABLE t3 (c1 INT, c2 INT) -> TABLESPACE ts_1 STORAGE DISK ENGINE NDB;Query OK, 0 rows affected (1.34 sec)

カラム c2 をディスクベースのストレージからインメモリーストレージに変更するには、次に示すように、ALTER TABLE ステートメントで使用されるカラム定義に STORAGE MEMORY 句を含めます。

mysql> ALTER TABLE t3 MODIFY c2 INT STORAGE MEMORY;Query OK, 0 rows affected (3.14 sec)
Records: 0 Duplicates: 0 Warnings: 0

同様の方法で STORAGE DISK を使用して、インメモリーカラムをディスクベースのカラムにすることができます。

カラム c1 は、ディスクベースのストレージを使用します。これが (CREATE TABLE ステートメント内のテーブルレベルの STORAGE DISK 句によって決定される) テーブルのデフォルトであるためです。ただし、次の SHOW CREATE TABLE の出力に示すように、カラム c2 はインメモリーストレージを使用します。

mysql> SHOW CREATE TABLE t3\G*************************** 1. row *************************** Table: t3
Create Table: CREATE TABLE `t3` ( `c1` int(11) DEFAULT NULL, `c2` int(11) DEFAULT NULL
) ENGINE=ndbcluster DEFAULT CHARSET=latin1
1 row in set (0.02 sec)

AUTO_INCREMENT カラムを追加すると、カラム値には、自動的にシーケンス番号が入力されます。MyISAM テーブルの場合は、ALTER TABLE の前に SET INSERT_ID=value を実行するか、または AUTO_INCREMENT=value テーブルオプションを使用することによって、最初のシーケンス番号を設定できます。セクション5.1.4「サーバーシステム変数」を参照してください。

MyISAM テーブルでは、AUTO_INCREMENT カラムを変更しない場合、シーケンス番号は影響を受けません。AUTO_INCREMENT カラムを削除してから、別の AUTO_INCREMENT カラムを追加した場合、シーケンス番号は 1 から付け直されます。

レプリケーションが使用されている場合は、テーブルに AUTO_INCREMENT カラムを追加しても、スレーブとマスターで行の順序が同じにならない可能性があります。これが発生するのは、行が番号付けされる順序が、テーブルに使用される固有のストレージエンジンおよび行が挿入された順序に依存するためです。マスターとスレーブで同じ順序を持つことが重要である場合は、行を並べ替えてから AUTO_INCREMENT 番号を割り当てる必要があります。テーブル t1AUTO_INCREMENT カラムを追加すると仮定した場合、次のステートメントは、t1 と同一であるが、AUTO_INCREMENT カラムを含む新しいテーブル t2 を生成します。

CREATE TABLE t2 (id INT AUTO_INCREMENT PRIMARY KEY)
SELECT * FROM t1 ORDER BY col1, col2;

ここでは、テーブル t1 にカラム col1col2 が存在することを前提にしています。

この一連のステートメントではまた、t1 と同一であるが、AUTO_INCREMENT カラムが追加された新しいテーブル t2 も生成されます。

CREATE TABLE t2 LIKE t1;
ALTER TABLE t2 ADD id INT AUTO_INCREMENT PRIMARY KEY;
INSERT INTO t2 SELECT * FROM t1 ORDER BY col1, col2;
重要

マスターとスレーブの両方で順序が同じになることを保証するには、ORDER BY 句で t1すべてのカラムを参照する必要があります。

AUTO_INCREMENT カラムを持つコピーを作成および移入するために使用する方法にかかわらず、最終手順は元のテーブルを削除してコピーの名前を変更することです。

DROP TABLE t1;
ALTER TABLE t2 RENAME t1;

13.1.8 ALTER TABLESPACE 構文

ALTER TABLESPACE tablespace_name {ADD|DROP} DATAFILE 'file_name' [INITIAL_SIZE [=] size] [WAIT] ENGINE [=] engine_name

このステートメントを使用すると、テーブルスペースへの新しいデータファイルの追加、またはテーブルスペースからのデータファイルの削除を実行できます。

ADD DATAFILE バリアントでは、INITIAL_SIZE 句を使用して初期サイズを指定できます。ここで、size はバイト単位で測定されます。デフォルト値は 134217728 (128M バイト) です。MySQL Cluster NDB 7.3.2 より前は、この値は数字で指定する必要がありました。(Bug #13116514、Bug #16104705、Bug #62858)。MySQL Cluster NDB 7.3.2 以降では、size のあとにオプションで、my.cnf で使用されるのと同様の、オーダーを示す 1 文字の略語を指定できます。一般に、これは M (M バイト) または G (G バイト) のどちらかの文字です。

注記

すべての MySQL Cluster ディスクデータオブジェクトが同じ名前空間を共有します。つまり、各ディスクデータオブジェクトは (単に、特定の型の各ディスクデータオブジェクトというだけでなく)、一意の名前が付けられている必要があります。たとえば、テーブルスペースとデータファイルを同じ名前にしたり、Undo ログファイルとテーブルスペースを同じ名前にしたりすることはできません。

32 ビットシステム上では、INITIAL_SIZE のサポートされる最大値は 4294967296 (4G バイト) です。(Bug #29186)

INITIAL_SIZE は、CREATE TABLESPACE と同様に明示的に丸められます。

データファイルが作成されたあと、そのサイズを変更することはできません。ただし、追加の ALTER TABLESPACE ... ADD DATAFILE ステートメントを使用して、テーブルスペースにさらに多くのデータファイルを追加できます。

DROP DATAFILEALTER TABLESPACE とともに使用すると、テーブルスペースからデータファイル 'file_name' が削除されます。いずれかのテーブルが使用しているテーブルスペースからはデータファイルを削除できません。つまり、そのデータファイルが空である (エクステントが使用されていない) ことが必要です。セクション18.5.12.1「MySQL Cluster ディスクデータオブジェクト」を参照してください。さらに、削除されるデータファイルはすべて、CREATE TABLESPACE または ALTER TABLESPACE で以前にそのテーブルスペースに追加されている必要があります。

ALTER TABLESPACE ... ADD DATAFILEALTER TABLESPACE ... DROP DATAFILE のどちらにも、そのテーブルスペースによって使用されるストレージエンジンを指定する ENGINE 句が必要です。現在、engine_name として受け入れられる値は NDBNDBCLUSTER だけです。

WAIT は解析されますが、それ以外は無視されるため、MySQL 5.6 では何の効果もありません。これは将来の拡張のために用意されています。

ALTER TABLESPACE ... ADD DATAFILEENGINE = NDB とともに使用された場合は、データファイルが各クラスタデータノード上に作成されます。INFORMATION_SCHEMA.FILES テーブルをクエリーすることによって、データファイルが作成されたことを確認したり、それらに関する情報を取得したりできます。たとえば、次のクエリーは、newts という名前のテーブルスペースに属するすべてのデータファイルを表示します。

mysql> SELECT LOGFILE_GROUP_NAME, FILE_NAME, EXTRA -> FROM INFORMATION_SCHEMA.FILES -> WHERE TABLESPACE_NAME = 'newts' AND FILE_TYPE = 'DATAFILE';+--------------------+--------------+----------------+
| LOGFILE_GROUP_NAME | FILE_NAME | EXTRA |
+--------------------+--------------+----------------+
| lg_3 | newdata.dat | CLUSTER_NODE=3 |
| lg_3 | newdata.dat | CLUSTER_NODE=4 |
| lg_3 | newdata2.dat | CLUSTER_NODE=3 |
| lg_3 | newdata2.dat | CLUSTER_NODE=4 |
+--------------------+--------------+----------------+
2 rows in set (0.03 sec)

セクション21.30.1「INFORMATION_SCHEMA FILES テーブル」を参照してください。

ALTER TABLESPACE は、MySQL Cluster のディスクデータストレージでのみ有効です。セクション18.5.12「MySQL Cluster ディスクデータテーブル」を参照してください。

13.1.9 ALTER VIEW 構文

ALTER [ALGORITHM = {UNDEFINED | MERGE | TEMPTABLE}] [DEFINER = { user | CURRENT_USER }] [SQL SECURITY { DEFINER | INVOKER }] VIEW view_name [(column_list)] AS select_statement [WITH [CASCADED | LOCAL] CHECK OPTION]

このステートメントは、ビューの定義を変更します。このビューは存在する必要があります。この構文は CREATE VIEW の構文に似ていますが、その効果は CREATE OR REPLACE VIEW と同じです。セクション13.1.20「CREATE VIEW 構文」を参照してください。このステートメントには、このビューに対する CREATE VIEW および DROP 権限と、SELECT ステートメントで参照される各カラムに対する何らかの権限が必要です。ALTER VIEW は、定義者または SUPER 権限を持つユーザーにのみ許可されます。

13.1.10 CREATE DATABASE 構文

CREATE {DATABASE | SCHEMA} [IF NOT EXISTS] db_name [create_specification] ...create_specification: [DEFAULT] CHARACTER SET [=] charset_name | [DEFAULT] COLLATE [=] collation_name

CREATE DATABASE は、指定された名前を持つデータベースを作成します。このステートメントを使用するには、このデータベースに対する CREATE 権限が必要です。CREATE SCHEMACREATE DATABASE のシノニムです。

そのデータベースが存在するときに IF NOT EXISTS を指定しなかった場合は、エラーが発生します。

MySQL 5.6 では、アクティブな LOCK TABLES ステートメントが存在するセッション内では CREATE DATABASE が許可されません。

create_specification オプションは、データベースの特性を指定します。データベースの特性は、データベースディレクトリ内の db.opt ファイルに格納されます。CHARACTER SET 句は、デフォルトのデータベース文字セットを指定します。COLLATE 句は、デフォルトのデータベース照合順序を指定します。セクション10.1「文字セットのサポート」では、文字セットと照合順序名について説明しています。

MySQL でのデータベースは、そのデータベース内のテーブルに対応するファイルを含むディレクトリとして実装されます。データベースが最初に作成されたとき、その中にはテーブルが存在しないため、CREATE DATABASE ステートメントは、MySQL データディレクトリの下のディレクトリと db.opt ファイルのみを作成します。許可されるデータベース名のルールは、セクション9.2「スキーマオブジェクト名」に示されています。データベース名に特殊文字が含まれている場合は、セクション9.2.3「識別子とファイル名のマッピング」で説明されているように、その文字のエンコードされたバージョンがデータベースディレクトリの名前に含まれます。

データディレクトリの下に (たとえば、mkdir で) ディレクトリを手動で作成すると、サーバーはそれをデータベースディレクトリと見なし、SHOW DATABASES の出力に表示します。

mysqladmin プログラムを使用してデータベースを作成することもできます。セクション4.5.2「mysqladmin — MySQL サーバーの管理を行うクライアント」を参照してください。

13.1.11 CREATE EVENT 構文

CREATE [DEFINER = { user | CURRENT_USER }] EVENT [IF NOT EXISTS] event_name ON SCHEDULE schedule [ON COMPLETION [NOT] PRESERVE] [ENABLE | DISABLE | DISABLE ON SLAVE] [COMMENT 'comment'] DO event_body;schedule: AT timestamp [+ INTERVAL interval] ... | EVERY interval [STARTS timestamp [+ INTERVAL interval] ...] [ENDS timestamp [+ INTERVAL interval] ...]interval: quantity {YEAR | QUARTER | MONTH | DAY | HOUR | MINUTE | WEEK | SECOND | YEAR_MONTH | DAY_HOUR | DAY_MINUTE | DAY_SECOND | HOUR_MINUTE | HOUR_SECOND | MINUTE_SECOND}

このステートメントは、新しいイベントを作成してスケジュールします。このイベントは、イベントスケジューラが有効になっていないかぎり実行されません。イベントスケジューラのステータスをチェックし、必要に応じてそれを有効にする方法については、セクション20.4.2「イベントスケジューラの構成」を参照してください。

CREATE EVENT には、イベントが作成されるスキーマに対する EVENT 権限が必要です。このセクションのあとの方で説明されているように、DEFINER 値によっては SUPER 権限も必要になる可能性があります。

有効な CREATE EVENT ステートメントの最小要件は次のとおりです。

  • キーワード CREATE EVENT に加えて、データベーススキーマ内のイベントを一意に識別するイベント名。

  • イベントが実行される時期と頻度を決定する ON SCHEDULE 句。

  • イベントによって実行される SQL ステートメントを含む DO 句。

最小限の CREATE EVENT ステートメントの例を次に示します。

CREATE EVENT myevent ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 HOUR DO UPDATE myschema.mytable SET mycol = mycol + 1;

前のステートメントは、myevent という名前のイベントを作成します。このイベントは、myschema.mytable テーブルの mycol カラムの値を 1 増分する SQL ステートメントを実行することによって (その作成の 1 時間後に) 1 回実行されます。

event_name は、最大長が 64 文字の有効な MySQL 識別子である必要があります。イベント名は大文字と小文字が区別されないため、myeventMyEvent という名前の 2 つのイベントを同じスキーマ内に含めることはできません。一般に、イベント名を管理するルールは、ストアドルーチンの名前の場合と同じです。セクション9.2「スキーマオブジェクト名」を参照してください。

イベントはスキーマに関連付けられています。event_name の一部としてスキーマが示されていない場合は、デフォルトの (現在の) スキーマと見なされます。イベントを特定のスキーマ内に作成するには、schema_name.event_name 構文を使用して、そのイベント名をスキーマで修飾します。

DEFINER 句は、イベントの実行時にアクセス権限を確認するときに使用される MySQL アカウントを指定します。user 値を指定する場合は、'user_name'@'host_name' (GRANT ステートメントで使用されるのと同じ形式)、CURRENT_USER、または CURRENT_USER() として指定された MySQL アカウントにしてください。DEFINER のデフォルト値は、CREATE EVENT ステートメントを実行するユーザーです。これは、明示的に DEFINER = CURRENT_USER を指定するのと同じです。

DEFINER 句を指定した場合は、次のルールによって有効な DEFINER ユーザーの値が決定されます。

  • SUPER 権限がない場合、許可される唯一の user 値は、リテラルで指定するか、または CURRENT_USER を使用して指定した自分のアカウントです。定義者をほかのアカウントに設定することはできません。

  • SUPER 権限がある場合は、構文として有効な任意のアカウント名を指定できます。そのアカウントが実際に存在しない場合は、警告が生成されます。

  • 存在しない DEFINER アカウントでイベントを作成することはできますが、そのアカウントが存在しない場合は、イベント実行時にエラーが発生します。

イベントのセキュリティーの詳細は、セクション20.6「ストアドプログラムおよびビューのアクセスコントロール」を参照してください。

イベント内では、CURRENT_USER() 関数が、イベント実行時に権限を確認するために使用されるアカウント (DEFINER ユーザー) を返します。イベント内のユーザー監査については、セクション6.3.13「SQL ベースの MySQL アカウントアクティビティーの監査」を参照してください。

CREATE EVENT での IF NOT EXISTS には、CREATE TABLE での場合と同じ意味があります。event_name という名前のイベントが同じスキーマ内にすでに存在する場合、アクションは実行されず、エラーも発生しません。(ただし、このような場合は警告が生成されます。)

ON SCHEDULE 句は、そのイベントに対して定義された event_body を繰り返す時期、頻度、および期間を決定します。この句は、次の 2 つの形式のいずれかを取ります。

  • 1 回限りのイベントには、AT timestamp が使用されます。これは、そのイベントが timestamp で指定された日付と時間に 1 回だけ実行されることを指定します。この値は、日付と時間の両方を含んでいるか、または datetime 値に解決される式である必要があります。この目的には、DATETIME または TIMESTAMP 型のどちらかの値を使用できます。日付が過去の日付である場合は、次に示すように、警告が発生します。

    mysql> SELECT NOW();+---------------------+
    | NOW() |
    +---------------------+
    | 2006-02-10 23:59:01 |
    +---------------------+
    1 row in set (0.04 sec)
    mysql> CREATE EVENT e_totals -> ON SCHEDULE AT '2006-02-10 23:59:00' -> DO INSERT INTO test.totals VALUES (NOW());Query OK, 0 rows affected, 1 warning (0.00 sec)
    mysql> SHOW WARNINGS\G*************************** 1. row *************************** Level: Note Code: 1588
    Message: Event execution time is in the past and ON COMPLETION NOT PRESERVE is set. The event was dropped immediately after creation.

    どのような理由であれ、それ自体が無効な CREATE EVENT ステートメントはエラーで失敗します。

    現在の日付と時間を指定するには、CURRENT_TIMESTAMP を使用できます。このような場合、イベントは、作成されるとすぐに機能します。

    現在の日付と時間を基準にした将来のある時点 (今から 3 週間後というフレーズで表される時点など) に発生するイベントを作成するには、オプションの句 + INTERVAL interval を使用できます。interval 部分は、数量と時間単位の 2 つの部分で構成され、DATE_ADD() 関数で使用される間隔を管理するのと同じ構文ルールに従います (セクション12.7「日付および時間関数」を参照してください)。また、単位のキーワードも、イベントを定義する場合はマイクロ秒を含む単位を使用できない点を除いて同じです。一部の間隔型では、複合の時間単位を使用できます。たとえば、2 分と 10 秒は、+ INTERVAL '2:10' MINUTE_SECOND として表すことができます。

    また、間隔を組み合わせることもできます。たとえば、AT CURRENT_TIMESTAMP + INTERVAL 3 WEEK + INTERVAL 2 DAY は、今から 3 週間と 2 日後と同等です。このような句の各部分は、+ INTERVAL で始まる必要があります。

  • アクションを定期的に繰り返すには、EVERY 句を使用します。EVERY キーワードのあとに、前の AT キーワードの説明に示されている interval を指定します。(EVERY では + INTERVAL は使用されません。)たとえば、EVERY 6 WEEK6 週間ごとを示します。

    EVERY 句では + INTERVAL 句は許可されていませんが、+ INTERVAL 内で許可されているのと同じ複合の時間単位を使用できます。

    EVERY 句には、オプションの STARTS 句を含めることができます。STARTS のあとに、このアクションがいつ繰り返しを開始するかを示す timestamp 値を指定します。また、+ INTERVAL interval を使用して、今からの時間を指定することもできます。たとえば、EVERY 3 MONTH STARTS CURRENT_TIMESTAMP + INTERVAL 1 WEEK は、今から 1 週間後に開始して 3 か月ごとを示します。同様に、今から 6 時間と 15 分後から開始して 2 週ごとを、EVERY 2 WEEK STARTS CURRENT_TIMESTAMP + INTERVAL '6:15' HOUR_MINUTE として表すことができます。STARTS を指定しないことは、STARTS CURRENT_TIMESTAMP を使用することと同じです。つまり、イベントに対して指定されたアクションは、そのイベントが作成されるとただちに繰り返しを開始します。

    EVERY 句には、オプションの ENDS 句を含めることができます。ENDS キーワードのあとに、このイベントがいつ繰り返しを停止するかを MySQL に指示する timestamp 値を指定します。また、ENDS とともに + INTERVAL interval を使用することもできます。たとえば、EVERY 12 HOUR STARTS CURRENT_TIMESTAMP + INTERVAL 30 MINUTE ENDS CURRENT_TIMESTAMP + INTERVAL 4 WEEK は、今から 30 分後に開始し、今から 4 週間後に終了するまで 12 時間ごとと同等です。ENDS を使用しないことは、このイベントがいつまでも実行を続行することを示します。

    ENDS は、複合の時間単位に対して STARTS と同じ構文をサポートします。

    EVERY 句では、STARTS または ENDS、あるいはその両方を使用できます。また、どちらも使用しないことも可能です。

    繰り返しイベントがスケジュール間隔内に終了しない場合は、イベントの複数のインスタンスが同時に実行される可能性があります。これが好ましくない場合は、同時インスタンスを回避するためのメカニズムを設けてください。たとえば、GET_LOCK() 関数や、行またはテーブルのロックを使用できます。

ON SCHEDULE 句では、組み込みの MySQL 関数やユーザー変数を含む式を使用して、そこに含まれているすべての timestamp または interval 値を取得できます。このような式でストアドファンクションやユーザー定義関数を使用したり、テーブル参照を使用したりすることはできません。ただし、SELECT FROM DUAL は使用できます。これは、CREATE EVENT ステートメントと ALTER EVENT ステートメントの両方に当てはまります。このような場合のストアドファンクション、ユーザー定義関数、およびテーブルへの参照は明確に禁止されており、エラーで失敗します (Bug #22830 を参照してください)。

ON SCHEDULE 句の時間は、現在のセッションの time_zone 値を使用して解釈されます。これがイベントのタイムゾーン、つまり、イベントのスケジューリングに使用され、イベントが実行されるとそのイベント内で有効になるタイムゾーンになります。これらの時間は UTC に変換され、イベントのタイムゾーンとともに mysql.event テーブル内に格納されます。これにより、サーバータイムゾーンまたはサマータイムの影響に対し生じた変更とは無関係に、定義されたとおりにイベントの実行を処理できます。イベントの時間の表現の詳細は、セクション20.4.4「イベントメタデータ」を参照してください。セクション13.7.5.19「SHOW EVENTS 構文」およびセクション21.7「INFORMATION_SCHEMA EVENTS テーブル」も参照してください。

通常は、イベントの期限が切れると、そのイベントはただちに削除されます。この動作は、ON COMPLETION PRESERVE を指定することによってオーバーライドできます。ON COMPLETION NOT PRESERVE を使用すると、単にデフォルトの非持続性の動作が明示的になるだけです。

DISABLE キーワードを使用すると、イベントは作成するが、それがアクティブにならないようにすることができます。あるいは、ENABLE を使用して、デフォルトステータス (アクティブ) を明示的にすることもできます。これは、ALTER EVENT と組み合わせるともっとも有効です (セクション13.1.2「ALTER EVENT 構文」を参照してください)。

ENABLEDISABLE の代わりに 3 番目の値を使用することもできます。DISABLE ON SLAVE は、イベントがマスター上で作成されてスレーブにレプリケートされたが、まだスレーブ上で実行されていないことを示すために、レプリケーションスレーブ上のイベントのステータスに対して設定されます。セクション17.4.1.11「呼び出される機能のレプリケーション」を参照してください。

COMMENT 句を使用して、イベントに対するコメントを指定できます。comment には、イベントの説明に使用する、最大 64 文字の任意の文字列を指定できます。コメントテキストは文字列リテラルであるため、引用符で囲む必要があります。

DO 句は、イベントによって実行されるアクションを指定するものであり、SQL ステートメントで構成されます。ストアドルーチンで使用できる有効な MySQL ステートメントのほぼすべてを、スケジュールされたイベントのアクションステートメントとしても使用できます。(セクションD.1「ストアドプログラムの制約」を参照してください。)たとえば、次のイベント e_hourly は、sessions テーブルのすべての行を 1 時間に 1 回削除します。ここで、このテーブルは site_activity スキーマの一部です。

CREATE EVENT e_hourly ON SCHEDULE EVERY 1 HOUR COMMENT 'Clears out sessions table each hour.' DO DELETE FROM site_activity.sessions;

MySQL は、イベントが作成または変更されたときの有効な sql_mode システム変数の設定を格納し、イベントが実行を開始したときの現在のサーバー SQL モードには関係なく、常にそのイベントを強制的にこの設定で実行します。

DO 句に ALTER EVENT ステートメントを含む CREATE EVENT ステートメントは成功したように見えます。ただし、結果として得られるスケジュールされたイベントをサーバーが実行しようとすると、その実行はエラーで失敗します。

注記

単に結果セットを返す SELECTSHOW などのステートメントは、イベントで使用されても何の効果もありません。これらのステートメントからの出力は MySQL モニターに送信されず、またどこにも格納されません。ただし、結果を格納する SELECT ... INTOINSERT INTO ... SELECT などのステートメントは使用できます。(後者の例については、このセクションにある次の例を参照してください。)

イベントが属するスキーマは、DO 句でのテーブル参照のためのデフォルトスキーマです。ほかのスキーマでのテーブルへの参照はすべて、正しいスキーマ名で修飾する必要があります。

次に示すように、ストアドルーチンと同様に、BEGIN および END キーワードを使用して DO 句で複合ステートメントの構文を使用できます。

delimiter |
CREATE EVENT e_daily ON SCHEDULE EVERY 1 DAY COMMENT 'Saves total number of sessions then clears the table each day' DO BEGIN INSERT INTO site_activity.totals (time, total) SELECT CURRENT_TIMESTAMP, COUNT(*) FROM site_activity.sessions; DELETE FROM site_activity.sessions; END |
delimiter ;

この例では、delimiter コマンドを使用して、ステートメント区切り文字を変更します。セクション20.1「ストアドプログラムの定義」を参照してください。

イベントでは、ストアドルーチンで使用されているような、より複雑な複合ステートメントを使用できます。この例では、ローカル変数、エラーハンドラ、およびフロー制御構造構文を使用しています。

delimiter |
CREATE EVENT e ON SCHEDULE EVERY 5 SECOND DO BEGIN DECLARE v INTEGER; DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN END; SET v = 0; WHILE v < 5 DO INSERT INTO t1 VALUES (0); UPDATE t2 SET s1 = s1 + 1; SET v = v + 1; END WHILE; END |
delimiter ;

イベントに、またはイベントから直接パラメータを渡す方法はありませんが、パラメータを持つストアドルーチンをイベント内で呼び出すことは可能です。

CREATE EVENT e_call_myproc ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 DAY DO CALL myproc(5, 27);

イベントの定義者に SUPER 権限がある場合、そのイベントはグローバル変数の読み取りおよび書き込みが可能です。この権限を付与すると悪用される可能性があるため、これを行う場合は十分に注意する必要があります。

一般に、ストアドルーチンで有効なすべてのステートメントを、イベントによって実行されるアクションステートメントに使用できます。ストアドルーチン内で許可されるステートメントの詳細は、セクション20.2.1「ストアドルーチンの構文」を参照してください。ストアドルーチンの一部としてイベントを作成できますが、イベントを別のイベントで作成することはできません。

13.1.12 CREATE FUNCTION 構文

CREATE FUNCTION ステートメントは、ストアドファンクションやユーザー定義関数 (UDF) を作成するために使用されます。

13.1.13 CREATE INDEX 構文

CREATE [ONLINE|OFFLINE] [UNIQUE|FULLTEXT|SPATIAL] INDEX index_name [index_type] ON tbl_name (index_col_name,...) [index_option] [algorithm_option | lock_option] ...index_col_name: col_name [(length)] [ASC | DESC]index_type: USING {BTREE | HASH}index_option: KEY_BLOCK_SIZE [=] value | index_type | WITH PARSER parser_name | COMMENT 'string'algorithm_option: ALGORITHM [=] {DEFAULT|INPLACE|COPY}lock_option: LOCK [=] {DEFAULT|NONE|SHARED|EXCLUSIVE}

CREATE INDEX は、インデックスを作成するために ALTER TABLE ステートメントにマップされます。セクション13.1.7「ALTER TABLE 構文」を参照してください。CREATE INDEX を使用して PRIMARY KEY を作成することはできません。代わりに ALTER TABLE を使用します。インデックスの詳細は、セクション8.3.1「MySQL のインデックスの使用の仕組み」を参照してください。

通常、テーブル上のすべてのインデックスは、そのテーブル自体が CREATE TABLE で作成された時点で作成します。セクション13.1.17「CREATE TABLE 構文」を参照してください。このガイドラインは、主キーによってデータファイル内の行の物理配列が決定される InnoDB テーブルの場合に特に重要です。CREATE INDEX では、既存のテーブルにインデックスを追加できます。

(col1,col2,...) という形式のカラムリストは、マルチカラムインデックスを作成します。インデックスキーの値は、特定のカラムの値を連結することによって形成されます。

col_name(length) 構文を使用してインデックスプリフィクス長を指定することにより、カラム値の先頭の部分のみを使用するインデックスを作成できます。

  • プリフィクスは、CHARVARCHARBINARY、および VARBINARY カラムに対して指定できます。

  • BLOB および TEXT カラムにもインデックスを設定できますが、プリフィクス長を指定する必要があります

  • プリフィクス長は、バイナリ以外の文字列型の場合は文字数で、バイナリ文字列型の場合はバイト単位で指定されます。つまり、インデックスエントリは、CHARVARCHAR、および TEXT カラムの場合は各カラム値の最初の length 文字、BINARYVARBINARY、および BLOB カラムの場合は各カラム値の最初の length バイトで構成されます。

  • このセクションのあとの方で説明されているように、空間カラムの場合はプリフィクス値を指定できません。

次に示すステートメントは、name カラムの最初の 10 文字を使用してインデックスを作成します。

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

カラム内の名前が一般に最初の 10 文字と異なっている場合は、このインデックスが、name カラム全体から作成されたインデックスよりはるかに遅いことはないはずです。また、インデックスにカラムプリフィクスを使用するとインデックスファイルをはるかに小さくできるため、多くのディスク領域が節約されるだけでなく、INSERT 操作も高速化される可能性があります。

プリフィクスのサポートやプリフィクスの長さ (サポートされている場合) は、ストレージエンジンに依存します。たとえば、InnoDB テーブルではプリフィクスの長さを最大 767 バイトに、また innodb_large_prefix オプションが有効になっている場合は 3072 バイトにすることができます。MyISAM テーブルの場合、プリフィクスの制限は 1000 バイトです。

注記

プリフィクスの制限がバイト単位で測定されるのに対して、CREATE INDEX ステートメントでのプリフィクス長は、バイナリ以外のデータ型 (CHARVARCHARTEXT) では文字数として解釈されます。複数バイトの文字セットを使用するカラムのプリフィクス長を指定する場合は、この点を考慮に入れてください。

NDBCLUSTER テーブルの可変幅カラム上のインデックスはオンラインで、つまり、テーブルコピーを行うことなく作成されます。このテーブルは、この操作の期間中、同じ API ノードに対するほかの操作に対してロックされますが、ほかの MySQL Cluster API ノードからのアクセスに対してはロックされません。これは、サーバーが実行できると判断した場合は常に、そのサーバーによって自動的に実行されます。これを実行するために、特殊な SQL 構文やサーバーオプションを使用する必要はありません。

標準の MySQL 5.6 リリースでは、サーバーがテーブルコピーなしでインデックスを作成すると決定したとき、そのサーバーをオーバーライドすることはできません。MySQL Cluster では、OFFLINE キーワードを使用してインデックスをオフラインで作成できます (これにより、そのテーブルはクラスタ内のすべての API ノードに対してロックされます)。CREATE OFFLINE INDEX および CREATE ONLINE INDEX を管理するルールや制限は、ALTER OFFLINE TABLE ... ADD INDEX および ALTER ONLINE TABLE ... ADD INDEX の場合と同じです。ONLINE キーワードを使用して、通常はオフラインで作成されるインデックスのコピーなし作成が実行されるようにすることはできません。CREATE INDEX 操作をテーブルコピーなしで実行できない場合、サーバーは ONLINE キーワードを無視します。詳細は、セクション13.1.7.2「MySQL Cluster での ALTER TABLE オンライン操作」を参照してください。

ONLINE および OFFLINE キーワードは、MySQL Cluster でのみ使用できます。これらのキーワードを標準の MySQL Server 5.6 リリースで使用しようとすると、構文エラーが発生します。ONLINE および OFFLINE キーワードは、MySQL Cluster NDB 7.3 では非推奨です。MySQL Cluster NDB 7.4 では引き続きサポートされますが、将来の MySQL Cluster リリースで削除される可能性があります。

UNIQUE インデックスは、そのインデックス内のすべての値が異なっている必要があるという制約を作成します。既存の行に一致するキー値を持つ新しい行を追加しようとすると、エラーが発生します。すべてのエンジンについて、UNIQUE インデックスは、NULL を含むことができるカラムでの複数の NULL 値を許可します。UNIQUE インデックス内のカラムのプリフィクス値を指定する場合は、カラム値がプリフィクス内で一意である必要があります。

FULLTEXT インデックスは InnoDB および MyISAM テーブルでのみサポートされ、CHARVARCHAR、および TEXT カラムのみを含めることができます。インデックス設定は常に、カラム全体に対して実行されます。カラムプリフィクスのインデックス設定はサポートされていないため、プリフィクス長が指定されてもすべて無視されます。操作の詳細は、セクション12.9「全文検索関数」を参照してください。

MyISAMInnoDBNDB、および ARCHIVE ストレージエンジンは、POINTGEOMETRY などの空間カラムをサポートしています。(セクション11.5「空間データの拡張」では、空間データ型について説明しています。)ただし、空間カラムのインデックス設定に対するサポートはエンジンによって異なります。空間および非空間インデックスは、次のルールに従って使用できます。

(SPATIAL INDEX を使用して作成された) 空間インデックスには、次の特性があります。

  • MyISAM テーブルでのみ使用できます。その他のストレージエンジンに対して SPATIAL INDEX を指定すると、エラーが発生します。

  • インデックス付きカラムは NOT NULL である必要があります。

  • MySQL 5.6 では、カラムプリフィクス長は禁止されています。各カラムの幅全体にインデックスが設定されます。

INDEXUNIQUE、または PRIMARY KEY で作成された非空間インデックスの特性は次のとおりです。

  • ARCHIVE を除く空間カラムをサポートするすべてのストレージエンジンに対して許可されます。

  • インデックスが主キーでないかぎり、カラムを NULL にすることができます。

  • POINT カラムを除く非 SPATIAL インデックス内の空間カラムごとに、カラムプリフィクス長を指定する必要があります。(これは、インデックス付き BLOB カラムの場合と同じ要件です。)プリフィクス長は、バイト単位で指定されます。

  • SPATIAL インデックスのインデックスタイプは、ストレージエンジンによって異なります。現在は、B ツリーが使用されます。

MySQL 5.6 では次のとおりです。

  • NULL 値を持つことができるカラムにインデックスを追加できるのは、InnoDBMyISAM、または MEMORY ストレージエンジンを使用している場合だけです。

  • BLOB または TEXT カラムにインデックスを追加できるのは、InnoDB または MyISAM ストレージエンジンを使用している場合だけです。

  • innodb_stats_persistent 設定が有効になっている場合は、InnoDB テーブル上でインデックスを作成したあと、そのテーブルに対して ANALYZE TABLE ステートメントを実行します。

index_col_name の指定を ASC または DESC で終了させることができます。これらのキーワードは、インデックス値の昇順または降順での格納を指定する将来の拡張のために許可されています。現在、これらは解析されますが、無視されます。インデックス値は、常に昇順で格納されます。

インデックスカラムリストのあとに、インデックスオプションを指定できます。index_option 値には、次のいずれかを指定できます。

  • KEY_BLOCK_SIZE [=] value

    オプションで、インデックスキーのブロックに使用するサイズをバイト単位で指定します。この値はヒントとして扱われます。必要に応じて、異なるサイズが使用される可能性があります。

    注記

    KEY_BLOCK_SIZE は、InnoDB に対してテーブルレベルでのみサポートされます。セクション13.1.17「CREATE TABLE 構文」を参照してください。

  • index_type

    一部のストレージエンジンでは、インデックスの作成時にインデックスタイプを指定できます。ストレージエンジンごとにサポートされている許可されるインデックスタイプ値を次の表に示します。複数のインデックスタイプが示されている場合は、最初のものが、インデックスタイプ指示子が指定されないときのデフォルトになります。

    ストレージエンジン許可されるインデックスタイプ
    InnoDBBTREE
    MyISAMBTREE
    MEMORY/HEAPHASHBTREE
    NDBHASHBTREE (テキストの注を参照してください)

    例:

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

    BTREE インデックスは、NDBCLUSTER ストレージエンジンによって T ツリーインデックスとして実装されます。

    注記

    NDB テーブルカラム上のインデックスの場合、USING オプションは、一意のインデックスまたは主キーに対してのみ指定できます。USING HASH は、暗黙的な順序付けされたインデックスが作成されないようにします。それ以外の場合は、NDB テーブル上に一意のインデックスまたは主キーを作成すると、順序付けされたインデックスとハッシュインデックスの両方が自動的に作成され、それぞれが同じ一連のカラムにインデックスを設定します。

    つまり、NULL カラム上の一意のインデックスまたは主キーを使用するクエリーは常に、NDB によってテーブルのフルスキャンで処理されます。特に、NDB テーブルの一意のインデックスまたは主キーカラムに関連した IS NULL または IS NOT NULL 条件を使用する予定がある場合は、このようなインデックスをすべて USING HASH なしで作成するようにしてください。

    index_type 句を SPATIAL INDEX とともに使用することはできません。

    特定のストレージエンジンに対して有効でないインデックスタイプを指定したが、そのエンジンがクエリー結果に影響を与えることなく使用できる使用可能な別のインデックスタイプが存在する場合、エンジンはその使用可能なタイプを使用します。パーサーは RTREE をタイプ名として認識しますが、現在、これはどのストレージエンジンに対しても指定できません。

    このオプションを ON tbl_name 句の前に使用することは非推奨です。このオプションをこの位置で使用するためのサポートは、将来の MySQL リリースで削除される予定です。index_type オプションが前とあとの両方の位置で指定された場合は、最後のオプションが適用されます。

    TYPE type_name は、USING type_name のシノニムとして認識されます。ただし、推奨される形式は USING です。

  • WITH PARSER parser_name

    このオプションは、FULLTEXT インデックスとともにのみ使用できます。これは、全文インデックス設定および検索操作に特殊な処理が必要な場合に、パーサープラグインをインデックスに関連付けます。プラグインの作成の詳細は、セクション24.2「MySQL プラグイン API」を参照してください。

  • COMMENT 'string'

    インデックス定義には、最大 1024 文字のオプションのコメントを含めることができます。

MySQL 5.6.6 の時点では、ALGORITHM および LOCK 句を指定できます。これらは、テーブルコピーの方法や、インデックスが変更されている間のテーブルの読み取りと書き込みの並列性のレベルに影響を与えます。これらには、ALTER TABLE ステートメントの場合と同じ意味があります。詳細は、セクション13.1.7「ALTER TABLE 構文」を参照してください。

13.1.14 CREATE LOGFILE GROUP 構文

CREATE LOGFILE GROUP logfile_group ADD UNDOFILE 'undo_file' [INITIAL_SIZE [=] initial_size] [UNDO_BUFFER_SIZE [=] undo_buffer_size] [REDO_BUFFER_SIZE [=] redo_buffer_size] [NODEGROUP [=] nodegroup_id] [WAIT] [COMMENT [=] comment_text] ENGINE [=] engine_name

このステートメントは、'undo_file' という名前の 1 つの UNDO ファイルを持つ logfile_group という名前の新しいログファイルグループを作成します。CREATE LOGFILE GROUP ステートメントには、ADD UNDOFILE 句が 1 つだけ存在します。ログファイルグループの命名を管理するルールについては、セクション9.2「スキーマオブジェクト名」を参照してください。

注記

すべての MySQL Cluster ディスクデータオブジェクトが同じ名前空間を共有します。つまり、各ディスクデータオブジェクトは (単に、特定の型の各ディスクデータオブジェクトというだけでなく)、一意の名前が付けられている必要があります。たとえば、テーブルスペースとログファイルグループを同じ名前にしたり、テーブルスペースとデータファイルを同じ名前にしたりすることはできません。

MySQL Cluster NDB 7.3 以降では、クラスタあたり、常に 1 つのログファイルグループしか作成できません。(Bug #16386 を参照してください)

オプションの INITIAL_SIZE パラメータは、UNDO ファイルの初期サイズを設定します。指定されていない場合は、デフォルトで 128M (128M バイト) になります。オプションの UNDO_BUFFER_SIZE パラメータは、ログファイルグループの UNDO バッファーで使用されるサイズを設定します。UNDO_BUFFER_SIZE のデフォルト値は 8M (8M バイト) です。この値が、使用可能なシステムメモリーの量を超えることはできません。これらのパラメータは、どちらもバイト単位で指定されます。MySQL Cluster NDB 7.3.2 以降では、これらの両方またはどちらか一方のあとにオプションで、my.cnf で使用されるのと同様の、桁を示す 1 文字の略語を指定できます。一般に、これは M (M バイト) または G (G バイト) のどちらかの文字です。MySQL Cluster NDB 7.3.2 より前は、これらのオプションの値は数字でしか指定できませんでした。(Bug #13116514、Bug #16104705、Bug #62858)

INITIAL_SIZEUNDO_BUFFER_SIZE の両方に使用されるメモリーは、サイズが SharedGlobalMemory データノード構成パラメータの値によって決定されるグローバルプールから取得されます。これには、InitialLogFileGroup データノード構成パラメータの設定により、これらのオプションに暗黙的に指定されるデフォルト値もすべて含まれます。

UNDO_BUFFER_SIZE に許可される最大値は 629145600 (600M バイト) です。

32 ビットシステム上では、INITIAL_SIZE のサポートされる最大値は 4294967296 (4G バイト) です。(Bug #29186)

INITIAL_SIZE の許可される最小値は 1048576 (1M バイト) です。

ENGINE オプションは、このログファイルグループによって使用されるストレージエンジンを決定します。ここで、engine_name はそのストレージエンジンの名前です。MySQL 5.6 では、これは NDB (または NDBCLUSTER) である必要があります。ENGINE が設定されていない場合、MySQL は、default_storage_engine サーバーシステム変数 (以前の storage_engine) で指定されたエンジンを使用しようとします。いずれにしても、エンジンが NDB または NDBCLUSTER として指定されていない場合、CREATE LOGFILE GROUP ステートメントは成功したように見えますが、次に示すように、実際にはログファイルグループの作成に失敗します。

mysql> CREATE LOGFILE GROUP lg1 -> ADD UNDOFILE 'undo.dat' INITIAL_SIZE = 10M;Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> SHOW WARNINGS;+-------+------+------------------------------------------------------------------------------------------------+
| Level | Code | Message |
+-------+------+------------------------------------------------------------------------------------------------+
| Error | 1478 | Table storage engine 'InnoDB' does not support the create option 'TABLESPACE or LOGFILE GROUP' |
+-------+------+------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
mysql> DROP LOGFILE GROUP lg1 ENGINE = NDB;ERROR 1529 (HY000): Failed to drop LOGFILE GROUPmysql> CREATE LOGFILE GROUP lg1 -> ADD UNDOFILE 'undo.dat' INITIAL_SIZE = 10M -> ENGINE = NDB;Query OK, 0 rows affected (2.97 sec)

NDB 以外のストレージエンジンが指定されたときに CREATE LOGFILE GROUP ステートメントが実際にはエラーを返さず、成功したように見えるという事実は、MySQL Cluster の将来のリリースで対処したいと考えている既知の問題です。

REDO_BUFFER_SIZENODEGROUPWAIT、および COMMENT は解析されますが、無視されるため、MySQL 5.6 では何の効果もありません。これらのオプションは、将来の拡張のために用意されています。

ENGINE [=] NDB とともに使用された場合は、ログファイルグループとそれに関連付けられた UNDO ログファイルが各クラスタデータノード上に作成されます。INFORMATION_SCHEMA.FILES テーブルをクエリーすることによって、UNDO ファイルが作成されたことを確認したり、それらに関する情報を取得したりできます。例:

mysql> SELECT LOGFILE_GROUP_NAME, LOGFILE_GROUP_NUMBER, EXTRA -> FROM INFORMATION_SCHEMA.FILES -> WHERE FILE_NAME = 'undo_10.dat';+--------------------+----------------------+----------------+
| LOGFILE_GROUP_NAME | LOGFILE_GROUP_NUMBER | EXTRA |
+--------------------+----------------------+----------------+
| lg_3 | 11 | CLUSTER_NODE=3 |
| lg_3 | 11 | CLUSTER_NODE=4 |
+--------------------+----------------------+----------------+
2 rows in set (0.06 sec)

CREATE LOGFILE GROUP は、MySQL Cluster のディスクデータストレージでのみ有効です。セクション18.5.12「MySQL Cluster ディスクデータテーブル」を参照してください。

13.1.15 CREATE PROCEDURE および CREATE FUNCTION 構文

CREATE [DEFINER = { user | CURRENT_USER }] PROCEDURE sp_name ([proc_parameter[,...]]) [characteristic ...] routine_bodyCREATE [DEFINER = { user | CURRENT_USER }] FUNCTION sp_name ([func_parameter[,...]]) RETURNS type [characteristic ...] routine_bodyproc_parameter: [ IN | OUT | INOUT ] param_nametypefunc_parameter: param_nametypetype: Any valid MySQL data typecharacteristic: COMMENT 'string' | LANGUAGE SQL | [NOT] DETERMINISTIC | { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA } | SQL SECURITY { DEFINER | INVOKER }routine_body: Valid SQL routine statement

これらのステートメントは、ストアドルーチンを作成します。デフォルトでは、ルーチンはデフォルトデータベースに関連付けられます。ルーチンを明示的に特定のデータベースに関連付けるには、そのルーチンの作成時に、その名前を db_name.sp_name として指定します。

CREATE FUNCTION ステートメントはまた、UDF (ユーザー定義関数) をサポートするために MySQL でも使用されます。セクション24.3「MySQL への新しい関数の追加」を参照してください。UDF は、外部のストアドファンクションと見なすことができます。ストアドファンクションは、その名前空間を UDF と共有します。各種の関数への参照をサーバーが解釈する方法を記述したルールについては、セクション9.2.4「関数名の構文解析と解決」を参照してください。

ストアドプロシージャーを呼び出すには、CALL ステートメントを使用します (セクション13.2.1「CALL 構文」を参照してください)。ストアドファンクションを呼び出すには、式でその関数を参照します。その関数は、式の評価中に値を返します。

CREATE PROCEDURE および CREATE FUNCTION には、CREATE ROUTINE 権限が必要です。このセクションのあとの方で説明されているように、DEFINER 値によっては SUPER 権限も必要になる可能性があります。バイナリロギングが有効になっている場合は、セクション20.7「ストアドプログラムのバイナリロギング」で説明されているように、CREATE FUNCTIONSUPER 権限が必要になることがあります。

デフォルトでは、MySQL は、ルーチン作成者に ALTER ROUTINE および EXECUTE 権限を自動的に付与します。この動作は、automatic_sp_privileges システム変数を無効にすることによって変更できます。セクション20.2.2「ストアドルーチンと MySQL 権限」を参照してください。

DEFINER および SQL SECURITY 句は、このセクションのあとの方で説明されているように、ルーチンの実行時にアクセス権限を確認するときに使用されるセキュリティーコンテキストを指定します。

ルーチン名が組み込みの SQL 関数の名前と同じである場合は、そのルーチンを定義するか、またはあとで呼び出すときに名前とそれに続く括弧の間にスペースを使用しないかぎり、構文エラーが発生します。このため、ユーザー独自のストアドルーチンに既存の SQL 関数の名前を使用することは避けてください。

IGNORE_SPACE SQL モードは、ストアドルーチンではなく、組み込み関数に適用されます。ストアドルーチン名のあとのスペースは、IGNORE_SPACE が有効になっているかどうかには関係なく、常に許可されます。

括弧で囲まれたパラメータリストは、常に存在する必要があります。パラメータが存在しない場合は、() の空のパラメータリストを使用するようにしてください。パラメータ名は大文字と小文字が区別されません。

各パラメータは、デフォルトでは IN パラメータです。それ以外のパラメータを指定するには、パラメータ名の前にキーワード OUT または INOUT を使用します。

注記

INOUT、または INOUT としてのパラメータの指定は、PROCEDURE に対してのみ有効です。FUNCTION の場合、パラメータは常に IN パラメータと見なされます。

IN パラメータは、プロシージャーへの値を渡します。プロシージャーはその値を変更する可能性がありますが、そのプロシージャーから戻ったとき、その変更は呼び出し元に表示されません。OUT パラメータは、プロシージャーから呼び出し元に値を渡します。その初期値はプロシージャー内では NULL であり、そのプロシージャーから戻ったとき、その値は呼び出し元に表示されます。INOUT パラメータは呼び出し元によって初期化され、プロシージャーで変更できます。そのプロシージャーから戻ったとき、プロシージャーによって行われた変更はすべて呼び出し元に表示されます。

OUT または INOUT パラメータごとに、プロシージャーを呼び出す CALL ステートメントでユーザー定義変数を渡して、プロシージャーから戻ったときにその値を取得できるようにします。そのプロシージャーを別のストアドプロシージャーまたはストアドファンクション内から呼び出している場合は、IN または INOUT パラメータとしてルーチンパラメータまたはローカルルーチン変数を渡すこともできます。

ルーチン内に準備されたステートメントでルーチンパラメータを参照することはできません。セクションD.1「ストアドプログラムの制約」を参照してください。

次の例は、OUT パラメータを使用する単純なストアドプロシージャーを示しています。

mysql> delimiter //mysql> CREATE PROCEDURE simpleproc (OUT param1 INT) -> BEGIN -> SELECT COUNT(*) INTO param1 FROM t; -> END//Query OK, 0 rows affected (0.00 sec)
mysql> delimiter ;mysql> CALL simpleproc(@a);Query OK, 0 rows affected (0.00 sec)
mysql> SELECT @a;+------+
| @a |
+------+
| 3 |
+------+
1 row in set (0.00 sec)

この例では、プロシージャーの定義中に mysql クライアントの delimiter コマンドを使用して、ステートメント区切り文字を ; から // に変更しています。これにより、プロシージャー本体で使用される ; 区切り文字を、mysql 自体が解釈するのではなく、サーバーに渡すようにすることができます。セクション20.1「ストアドプログラムの定義」を参照してください。

RETURNS 句は、FUNCTION (これには必須です) に対してのみ指定できます。これは関数の戻り型を示すものであり、関数本体には RETURN value ステートメントが含まれている必要があります。RETURN ステートメントが異なる型の値を返した場合、その値は正しい型に強制的に変更されます。たとえば、ある関数が RETURNS 句で ENUM または SET 値を指定しているが、RETURN ステートメントが整数を返した場合、その関数から返される値は SET メンバーのセットの対応する ENUM メンバーを示す文字列になります。

次の関数例はパラメータを受け取り、SQL 関数を使用して操作を実行したあと、結果を返します。この場合は、関数定義に内部の ; ステートメント区切り文字が含まれていないため、delimiter を使用する必要はありません。

mysql> CREATE FUNCTION hello (s CHAR(20))mysql> RETURNS CHAR(50) DETERMINISTIC -> RETURN CONCAT('Hello, ',s,'!');Query OK, 0 rows affected (0.00 sec)
mysql> SELECT hello('world');+----------------+
| hello('world') |
+----------------+
| Hello, world! |
+----------------+
1 row in set (0.00 sec)

パラメータ型と関数の戻り型は、任意の有効なデータ型を使用するように宣言できます。前に CHARACTER SET 属性がある場合は、COLLATE 属性を使用できます。

routine_body は、有効な SQL ルーチンステートメントで構成されます。これは SELECTINSERT などの単純なステートメントでも、BEGINEND を使用して記述された複合ステートメントでもかまいません。複合ステートメントには、宣言、ループ、およびその他の制御構造ステートメントを含めることができます。これらのステートメントの構文については、セクション13.6「MySQL 複合ステートメント構文」で説明されています。

MySQL では、ルーチンに CREATEDROP などの DDL ステートメントを含めることが許可されます。MySQL ではまた、ストアドプロシージャーに COMMIT などの SQL トランザクションステートメントを含めることも許可されます (ただし、ストアドファンクションには許可されません)。ストアドファンクションには、明示的または暗黙的なコミットまたはロールバックを実行するステートメントを含めることはできません。これらのステートメントのサポートは、SQL 標準では必要ありません。SQL 標準では、各 DBMS ベンダーがこれらのステートメントを許可するかどうかを決められると定めています。

結果セットを返すステートメントはストアドプロシージャー内で使用できますが、ストアドファンクション内では使用できません。この禁止には、INTO var_list 句を含まない SELECT ステートメントや、SHOWEXPLAINCHECK TABLE などのその他のステートメントが含まれます。結果セットを返すことを関数の定義時に判定できるステートメントの場合は、Not allowed to return a result set from a function エラーが発生します (ER_SP_NO_RETSET)。結果セットを返すことを実行時にしか判定できないステートメントの場合は、PROCEDURE %s can't return a result set in the given context エラーが発生します (ER_SP_BADSELECT)。

ストアドルーチン内での USE ステートメントは許可されていません。ルーチンが呼び出されると、暗黙的な USE db_name が実行されます (また、そのルーチンが終了すると元に戻されます)。これにより、そのルーチンには実行中、特定のデフォルトデータベースが割り当てられます。ルーチンのデフォルトデータベース以外のデータベース内のオブジェクトへの参照は、適切なデータベース名で修飾するようにしてください。

ストアドルーチン内では許可されないステートメントの詳細は、セクションD.1「ストアドプログラムの制約」を参照してください。

MySQL インタフェースを備える言語で記述されたプログラム内からのストアドプロシージャーの呼び出しについては、セクション13.2.1「CALL 構文」を参照してください。

MySQL は、ルーチンが作成または変更されたときの有効な sql_mode システム変数の設定を格納し、ルーチンが実行を開始したときの現在のサーバー SQL モードには関係なく、常にそのルーチンを強制的にこの設定で実行します。

呼び出し元の SQL モードからそのルーチンの SQL モードへの切り替えは、引数を評価し、結果として得られる値をルーチンパラメータに割り当てたあとに実行されます。あるルーチンを厳密な SQL モードで定義したが、その呼び出しを非厳密モードで行なった場合は、引数のルーチンパラメータへの割り当てが厳密モードで実行されません。ルーチンに渡される式を厳密な SQL モードで割り当てる必要がある場合は、そのルーチンを厳密モードが有効な状態で呼び出すようにしてください。

COMMENT 特性は MySQL 拡張であり、そのストアドルーチンの説明のために使用できます。この情報は、SHOW CREATE PROCEDURE および SHOW CREATE FUNCTION ステートメントによって表示されます。

LANGUAGE 特性は、そのルーチンが記述されている言語を示します。サーバーはこの特性を無視します。SQL ルーチンのみがサポートされています。

ルーチンは、同じ入力パラメータに対して常に同じ結果を生成する場合は決定的と見なされ、それ以外の場合は非決定的と見なされます。ルーチン定義で DETERMINISTICNOT DETERMINISTIC のどちらも指定されていない場合、デフォルトは NOT DETERMINISTIC になります。関数が決定的であることを宣言するには、明示的に DETERMINISTIC を指定する必要があります。

ルーチンの性質の評価は、作成者の誠実さに基づいています。MySQL は、DETERMINISTIC と宣言されたルーチンに非決定的な結果を生成するステートメントが含まれていないかどうかをチェックしません。ただし、ルーチンの誤った宣言は、その結果やパフォーマンスに影響を与える可能性があります。非決定的なルーチンを DETERMINISTIC として宣言すると、オプティマイザが正しくない実行計画を選択するために、予期しない結果を招くことがあります。決定的なルーチンを NONDETERMINISTIC として宣言すると、使用可能な最適化が使用されなくなるために、パフォーマンスが低下することがあります。

バイナリロギングが有効になっている場合、DETERMINISTIC 特性は、MySQL がどのルーチン定義を受け入れるかに影響を与えます。セクション20.7「ストアドプログラムのバイナリロギング」を参照してください。

NOW() 関数 (または、そのシノニム) あるいは RAND() を含むルーチンは非決定的ですが、引き続きレプリケーションに対して安全である可能性があります。NOW() の場合、バイナリログにはタイムスタンプが含まれ、正しくレプリケートされます。RAND() もまた、ルーチンの実行中に 1 回だけ呼び出されるかぎり、正しくレプリケートされます。(ルーチン実行のタイムスタンプや乱数シードは、マスターとスレーブ上で同一の暗黙的な入力と見なすことができます。)

いくつかの特性によって、ルーチンによるデータ使用の性質に関する情報が提供されます。MySQL では、これらの特性はアドバイザリにすぎません。サーバーがこれらを使用して、あるルーチンにどのような種類のステートメントの実行を許可するかを制約することはありません。

  • CONTAINS SQL は、そのルーチンに、データの読み取りや書き込みを行うステートメントが含まれていないことを示します。これは、これらのどの特性も明示的に指定されていない場合のデフォルトです。このようなステートメントの例として、実行されてもデータの読み取りや書き込みを行わない SET @x = 1 または DO RELEASE_LOCK('abc') があります。

  • NO SQL は、そのルーチンに SQL ステートメントが含まれていないことを示します。

  • READS SQL DATA は、そのルーチンに、データを読み取るステートメント (SELECT など) が含まれているが、データを書き込むステートメントは含まれていないことを示します。

  • MODIFIES SQL DATA は、そのルーチンに、データを書き込む可能性のあるステートメント (INSERTDELETE など) が含まれていることを示します。

SQL SECURITY 特性は、セキュリティーコンテキストを指定する DEFINER または INVOKER のどちらかです。これは、そのルーチンがルーチンの DEFINER 句で指定されたアカウント、またはそのルーチンを呼び出すユーザーのどちらの権限を使用して実行されるかを示します。このアカウントには、そのルーチンが関連付けられているデータベースにアクセスするためのアクセス権が必要です。デフォルト値は DEFINER です。そのルーチンを呼び出すユーザーには、それに対する EXECUTE 権限が必要です。また、そのルーチンが定義者のセキュリティーコンテキストで実行される場合は、DEFINER アカウントにもその権限が必要です。

DEFINER 句は、SQL SECURITY DEFINER 特性を持つルーチンのルーチン実行時にアクセス権限を確認するときに使用される MySQL アカウントを指定します。

DEFINER 句に user 値を指定する場合は、'user_name'@'host_name' (GRANT ステートメントで使用されるのと同じ形式)、CURRENT_USER、または CURRENT_USER() として指定された MySQL アカウントにするようにしてください。DEFINER のデフォルト値は、CREATE PROCEDURE または CREATE FUNCTION ステートメントを実行するユーザーです。これは、明示的に DEFINER = CURRENT_USER を指定するのと同じです。

DEFINER 句を指定した場合は、次のルールによって有効な DEFINER ユーザーの値が決定されます。

  • SUPER 権限がない場合、許可される唯一の user 値は、リテラルで指定するか、または CURRENT_USER を使用して指定した自分のアカウントです。定義者をほかのアカウントに設定することはできません。

  • SUPER 権限がある場合は、構文として有効な任意のアカウント名を指定できます。そのアカウントが実際に存在しない場合は、警告が生成されます。

  • 存在しない DEFINER アカウントでルーチンを作成することはできますが、SQL SECURITY 値が DEFINER であるが、定義者アカウントが存在しない場合は、ルーチン実行時にエラーが発生します。

ストアドルーチンのセキュリティーの詳細は、セクション20.6「ストアドプログラムおよびビューのアクセスコントロール」を参照してください。

SQL SECURITY DEFINER 特性を使用して定義されたストアドルーチン内で、CURRENT_USER は、そのルーチンの DEFINER 値を返します。ストアドルーチン内のユーザー監査については、セクション6.3.13「SQL ベースの MySQL アカウントアクティビティーの監査」を参照してください。

mysql.user テーブルにリストされている MySQL アカウントの数を表示する次のプロシージャーを考えてみます。

CREATE DEFINER = 'admin'@'localhost' PROCEDURE account_count()
BEGIN SELECT 'Number of accounts:', COUNT(*) FROM mysql.user;
END;

このプロシージャーには、それがどのユーザーによって定義されている場合でも、'admin'@'localhost'DEFINER アカウントが割り当てられます。また、それがどのユーザーから呼び出された場合でも、そのアカウントの権限で実行されます (デフォルトのセキュリティー特性は DEFINER であるため)。このプロシージャーは、呼び出し元にそれに対する EXECUTE 権限があり、かつ 'admin'@'localhost'mysql.user テーブルに対する SELECT 権限があるかどうかに応じて成功または失敗します。

ここで、このプロシージャーが SQL SECURITY INVOKER 特性を使用して定義されているとします。

CREATE DEFINER = 'admin'@'localhost' PROCEDURE account_count()
SQL SECURITY INVOKER
BEGIN SELECT 'Number of accounts:', COUNT(*) FROM mysql.user;
END;

このプロシージャーは、依然として 'admin'@'localhost'DEFINER を持っていますが、この場合は呼び出し元ユーザーの権限で実行されます。そのため、このプロシージャーは、呼び出し元にそれに対する EXECUTE 権限と、mysql.user テーブルに対する SELECT 権限があるかどうかに応じて成功または失敗します。

サーバーは、ルーチンパラメータ、DECLARE を使用して作成されたローカルルーチン変数、または関数の戻り値のデータ型を次のように処理します。

  • データ型の不一致やオーバーフローがないかどうか割り当てがチェックされます。変換やオーバーフローの問題によって警告が発生するか、または厳密な SQL モードではエラーが発生します。

  • スカラー値のみを割り当てることができます。たとえば、SET x = (SELECT 1, 2) などのステートメントは無効です。

  • 文字データ型で、宣言内に CHARACTER SET 属性が存在する場合は、指定された文字セットとそのデフォルトの照合順序が使用されます。COLLATE 属性も存在する場合は、デフォルトの照合順序ではなく、その照合順序が使用されます。

    CHARACTER SET および COLLATE 属性が存在しない場合は、ルーチンの作成時に有効なデータベース文字セットおよび照合順序が使用されます。サーバーでデータベース文字セットおよび照合順序が使用されないようにするには、文字データパラメータとして明示的な CHARACTER SET および COLLATE 属性を指定します。

    データベースのデフォルトの文字セットまたは照合順序を変更する場合は、データベースのデフォルトを使用するストアドルーチンを削除および再作成して、それらが新しいデフォルトを使用するようにする必要があります。

    データベース文字セットおよび照合順序は、character_set_database および collation_database システム変数の値で指定されます。詳細は、セクション10.1.3.2「データベース文字セットおよび照合順序」を参照してください。

13.1.16 CREATE SERVER 構文

CREATE SERVER server_name FOREIGN DATA WRAPPER wrapper_name OPTIONS (option [, option] ...)option: { HOST character-literal | DATABASE character-literal | USER character-literal | PASSWORD character-literal | SOCKET character-literal | OWNER character-literal | PORT numeric-literal }

このステートメントは、FEDERATED ストレージエンジンで使用するためのサーバーの定義を作成します。CREATE SERVER ステートメントは、mysql データベース内の servers テーブルに新しい行を作成します。このステートメントには、SUPER 権限が必要です。

server_name は、そのサーバーへの一意の参照にしてください。サーバー定義は、そのサーバーのスコープ内ではグローバルであるため、サーバー定義を特定のデータベースに対して修飾することはできません。server_name の最大長は 64 文字であり (64 文字より長い名前は暗黙のうちに切り捨てられます)、大文字小文字を区別しません。この名前は、引用符で囲まれた文字列として指定できます。

wrapper_namemysql にしてください。また、それを単一引用符で囲むことができます。wrapper_name に対するその他の値は現在、サポートされていません。

option について、文字リテラルまたは数値リテラルのどちらかを指定する必要があります。文字リテラルは UTF-8 であり、64 文字の最大長をサポートし、デフォルトではブランク (空) の文字列になります。文字列リテラルは、暗黙のうちに 64 文字に切り捨てられます。数値リテラルは 0 から 9999 までの数字である必要があり、デフォルト値は 0 です。

注記

OWNER オプションは現在、適用されず、作成されるサーバー接続の所有権または操作には影響を与えません。

CREATE SERVER ステートメントは、mysql.servers テーブル内にエントリを作成します。これは、あとで FEDERATED テーブルを作成するときに CREATE TABLE ステートメントで使用できます。指定したオプションは、mysql.servers テーブル内のカラムを移入するために使用されます。テーブルカラムは、Server_nameHostDbUsernamePasswordPort、および Socket です。

例:

CREATE SERVER s
FOREIGN DATA WRAPPER mysql
OPTIONS (USER 'Remote', HOST '192.168.1.106', DATABASE 'test');

サーバーへの接続を確立するために必要なすべてのオプションを指定する必要があります。ユーザー名、ホスト名、およびデータベース名は必須です。パスワードなどの、その他のオプションも必要になる可能性があります。

このテーブルに格納されたデータは、FEDERATED テーブルへの接続を作成するときに使用できます。

CREATE TABLE t (s1 INT) ENGINE=FEDERATED CONNECTION='s';

詳細は、セクション15.8「FEDERATED ストレージエンジン」を参照してください。

CREATE SERVER では、自動コミットが実行されます。

MySQL 5.6 では、使用されているロギング形式には関係なく、CREATE SERVER はバイナリログに書き込まれません。

MySQL 5.6.11 でのみ、このステートメントを発行する前に、gtid_nextAUTOMATIC に設定する必要があります。(Bug #16062608、Bug #16715809、Bug #69045)

13.1.17 CREATE TABLE 構文

CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name (create_definition,...) [table_options] [partition_options]
CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name [(create_definition,...)] [table_options] [partition_options] select_statementCREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name { LIKE old_tbl_name | (LIKE old_tbl_name) }create_definition: col_namecolumn_definition | [CONSTRAINT [symbol]] PRIMARY KEY [index_type] (index_col_name,...) [index_option] ... | {INDEX|KEY} [index_name] [index_type] (index_col_name,...) [index_option] ... | [CONSTRAINT [symbol]] UNIQUE [INDEX|KEY] [index_name] [index_type] (index_col_name,...) [index_option] ... | {FULLTEXT|SPATIAL} [INDEX|KEY] [index_name] (index_col_name,...) [index_option] ... | [CONSTRAINT [symbol]] FOREIGN KEY [index_name] (index_col_name,...) reference_definition | CHECK (expr)column_definition: data_type [NOT NULL | NULL] [DEFAULT default_value] [AUTO_INCREMENT] [UNIQUE [KEY] | [PRIMARY] KEY] [COMMENT 'string'] [COLUMN_FORMAT {FIXED|DYNAMIC|DEFAULT}] [STORAGE {DISK|MEMORY|DEFAULT}] [reference_definition]data_type: BIT[(length)] | 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[(fsp)] | TIMESTAMP[(fsp)] | DATETIME[(fsp)] | YEAR | CHAR[(length)] [CHARACTER SET charset_name] [COLLATE collation_name] | VARCHAR(length) [CHARACTER SET charset_name] [COLLATE collation_name] | BINARY[(length)] | VARBINARY(length) | TINYBLOB | BLOB | MEDIUMBLOB | LONGBLOB | TINYTEXT [BINARY] [CHARACTER SET charset_name] [COLLATE collation_name] | TEXT [BINARY] [CHARACTER SET charset_name] [COLLATE collation_name] | MEDIUMTEXT [BINARY] [CHARACTER SET charset_name] [COLLATE collation_name] | LONGTEXT [BINARY] [CHARACTER SET charset_name] [COLLATE collation_name] | ENUM(value1,value2,value3,...) [CHARACTER SET charset_name] [COLLATE collation_name] | SET(value1,value2,value3,...) [CHARACTER SET charset_name] [COLLATE collation_name] | spatial_typeindex_col_name: col_name [(length)] [ASC | DESC]index_type: USING {BTREE | HASH}index_option: KEY_BLOCK_SIZE [=] value | index_type | WITH PARSER parser_name | COMMENT 'string'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 ACTIONtable_options: table_option [[,] table_option] ...table_option: ENGINE [=] engine_name | AUTO_INCREMENT [=] value | AVG_ROW_LENGTH [=] value | [DEFAULT] CHARACTER SET [=] charset_name | CHECKSUM [=] {0 | 1} | [DEFAULT] COLLATE [=] collation_name | COMMENT [=] 'string' | CONNECTION [=] 'connect_string' | DATA DIRECTORY [=] 'absolute path to directory' | DELAY_KEY_WRITE [=] {0 | 1} | INDEX DIRECTORY [=] 'absolute path to directory' | INSERT_METHOD [=] { NO | FIRST | LAST } | KEY_BLOCK_SIZE [=] value | MAX_ROWS [=] value | MIN_ROWS [=] value | PACK_KEYS [=] {0 | 1 | DEFAULT} | PASSWORD [=] 'string' | ROW_FORMAT [=] {DEFAULT|DYNAMIC|FIXED|COMPRESSED|REDUNDANT|COMPACT} | STATS_AUTO_RECALC [=] {DEFAULT|0|1} | STATS_PERSISTENT [=] {DEFAULT|0|1} | STATS_SAMPLE_PAGES [=] value | TABLESPACE tablespace_name [STORAGE {DISK|MEMORY|DEFAULT}] | UNION [=] (tbl_name[,tbl_name]...)partition_options: PARTITION BY { [LINEAR] HASH(expr) | [LINEAR] KEY [ALGORITHM={1|2}] (column_list) | RANGE{(expr) | COLUMNS(column_list)} | LIST{(expr) | COLUMNS(column_list)} } [PARTITIONS num] [SUBPARTITION BY { [LINEAR] HASH(expr) | [LINEAR] KEY [ALGORITHM={1|2}] (column_list) } [SUBPARTITIONS num] ] [(partition_definition [, partition_definition] ...)]partition_definition: PARTITION partition_name [VALUES {LESS THAN {(expr | value_list) | 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 valid select statement)

CREATE TABLE は、指定された名前を持つテーブルを作成します。このテーブルに対する CREATE 権限が必要です。

許可されるテーブル名のルールは、セクション9.2「スキーマオブジェクト名」に示されています。デフォルトでは、テーブルは InnoDB ストレージエンジンを使用して、デフォルトデータベース内に作成されます。テーブルがすでに存在する場合、デフォルトデータベースが存在しない場合、またはデータベースが存在しない場合はエラーが発生します。

特定のデータベース内にテーブルを作成するには、テーブル名を db_name.tbl_name として指定できます。そのデータベースが存在すると仮定すると、これは、デフォルトデータベースが存在するかどうかには関係なく機能します。引用符で囲まれた識別子を使用する場合は、データベース名とテーブル名を個別に引用符で囲みます。たとえば、`mydb.mytbl` ではなく、`mydb`.`mytbl` と記述します。

一時テーブル

テーブルの作成時に TEMPORARY キーワードを使用できます。TEMPORARY テーブルは現在のセッションにのみ表示され、そのセッションが閉じられると自動的に削除されます。つまり、2 つの異なるセッションが同じ一時テーブル名を使用することができ、互いに、または同じ名前の既存の TEMPORARY 以外のテーブルと競合することはありません。(既存のテーブルは、一時テーブルが削除されるまで非表示になります。)一時テーブルを作成するには、CREATE TEMPORARY TABLES 権限が必要です。

注記

TEMPORARY キーワードを使用した場合、CREATE TABLE は、現在のアクティブなトランザクションを自動的にはコミットしません。

注記

TEMPORARY テーブルは、データベース (スキーマ) と非常に疎な関係を持っています。データベースを削除しても、そのデータベース内で作成されたどの TEMPORARY テーブルも自動的には削除されません。また、CREATE TABLE ステートメントでテーブル名をデータベース名で修飾した場合は、存在しないデータベース内に TEMPORARY テーブルを作成することもできます。この場合は、そのテーブルへの以降のすべての参照をデータベース名で修飾する必要があります。

同じ名前を持つ既存のテーブル

キーワード IF NOT EXISTS は、テーブルがすでに存在する場合にエラーが発生しないようにします。ただし、既存のテーブルの構造が CREATE TABLE ステートメントによって示されている構造と同一であることの検証は行われません。

物理表現

MySQL は、各テーブルを、データベースディレクトリ内にある .frm テーブル形式 (定義) ファイルで表します。そのテーブルのストレージエンジンによって、ほかのファイルが作成されることもあります。

InnoDB テーブルの場合、ファイルストレージは、innodb_file_per_table 構成オプションによって制御されます。このオプションがオフになっている場合、InnoDB テーブルおよびインデックスはすべて、1 つ以上の .ibd ファイルによって表されるシステムテーブルスペースに格納されます。このオプションがオンになっているときに作成された各 InnoDB テーブルでは、テーブルデータとそれに関連付けられたすべてのインデックスは、データベースディレクトリ内にある .ibd ファイルに格納されます。

MyISAM テーブルの場合は、ストレージエンジンがデータおよびインデックスファイルを作成します。そのため、MyISAM テーブル tbl_name ごとに 3 つのディスクファイルが存在します。

ファイル目的
tbl_name.frmテーブル形式 (定義) ファイル
tbl_name.MYDデータファイル
tbl_name.MYIインデックスファイル

第15章「代替ストレージエンジンでは、テーブルを表すために各ストレージエンジンがどのようなファイルを作成するかについて説明しています。テーブル名に特殊文字が含まれている場合は、セクション9.2.3「識別子とファイル名のマッピング」で説明されているように、その文字のエンコードされたバージョンがテーブルファイルの名前に含まれます。

カラムのデータ型および属性

data_type は、カラム定義内のデータ型を表します。spatial_type は、空間データ型を表します。示されているデータ型の構文は代表的な例にすぎません。カラムデータ型を指定するために使用できる構文の完全な説明や、各型のプロパティーに関する情報については、第11章「データ型およびセクション11.5「空間データの拡張」を参照してください。

属性の中には、すべてのデータ型には適用されないものがあります。AUTO_INCREMENT は、整数型と浮動小数点型にのみ適用されます。DEFAULT は、BLOB または TEXT 型には適用されません。

  • NULLNOT NULL のどちらも指定されていない場合、そのカラムは NULL が指定されたかのように処理されます。

  • 整数または浮動小数点のカラムには、追加の属性 AUTO_INCREMENT を指定できます。インデックスが設定された AUTO_INCREMENT カラムに NULL (推奨) または 0 の値を挿入すると、カラムは次のシーケンス値に設定されます。通常、これは value+1 です。ここで value は現在テーブルにあるカラムの最大値です。AUTO_INCREMENT シーケンスは 1 で始まります。

    行を挿入したあとに AUTO_INCREMENT 値を取得するには、LAST_INSERT_ID() SQL 関数または mysql_insert_id() C API 関数を使用します。セクション12.14「情報関数」およびセクション23.7.7.37「mysql_insert_id()」を参照してください。

    NO_AUTO_VALUE_ON_ZERO SQL モードが有効になっている場合は、新しいシーケンス値を生成することなく、0AUTO_INCREMENT カラム内に 0 として格納できます。セクション5.1.7「サーバー SQL モード」を参照してください。

    注記

    テーブルごとに存在できる AUTO_INCREMENT カラムは 1 つだけです。このカラムはインデックス付きである必要があり、DEFAULT 値を割り当てることはできません。AUTO_INCREMENT カラムは、正の値だけが含まれている場合にのみ正しく機能します。負の数を挿入すると、非常に大きな正の数を挿入したと見なされます。これは、数字が正から負にラップするときの精度の問題を回避すると同時に、0 を含む AUTO_INCREMENT カラムを誤って取得してしまわないようにするために行われます。

    MyISAM テーブルの場合は、マルチカラムキー内の AUTO_INCREMENT セカンダリカラムを指定できます。セクション3.6.9「AUTO_INCREMENT の使用」を参照してください。

    MySQL を一部の ODBC アプリケーションと互換性があるようにするために、次のクエリーを使用して、最後に挿入された行の AUTO_INCREMENT 値を見つけることができます。

    SELECT * FROM tbl_name WHERE auto_col IS NULL

    InnoDBAUTO_INCREMENT については、セクション14.6.5「InnoDB での AUTO_INCREMENT 処理」を参照してください。AUTO_INCREMENT と MySQL レプリケーションについては、セクション17.4.1.1「レプリケーションと AUTO_INCREMENT」を参照してください。

  • 文字データ型 (CHARVARCHARTEXT) には、そのカラムの文字セットと照合順序を指定するための CHARACTER SET および COLLATE 属性を含めることができます。詳細は、セクション10.1「文字セットのサポート」を参照してください。CHARSETCHARACTER SET のシノニムです。例:

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

    MySQL 5.6 は、文字カラム定義内の長さの指定を文字数で解釈します。(MySQL 4.1 より前のバージョンでは、バイト単位で解釈されました。)BINARYVARBINARY の長さはバイト単位です。

  • DEFAULT 句は、カラムのデフォルト値を指定します。例外が 1 つあります。デフォルト値は定数である必要があるので、関数または式にはできません。これは、たとえば日付カラムのデフォルト値に NOW()CURRENT_DATE などの関数の値を設定できないことを意味します。例外として、TIMESTAMP または (MySQL 5.6.5 の時点では) DATETIME カラムのデフォルトとして CURRENT_TIMESTAMP を指定できることがあります。セクション11.3.5「TIMESTAMP および DATETIME の自動初期化および更新機能」を参照してください。

    カラム定義に明示的な DEFAULT 値が含まれていない場合、MySQL は、セクション11.6「データ型デフォルト値」で説明されているようにデフォルト値を決定します。

    BLOB および TEXT カラムにはデフォルト値を割り当てられません。

    NO_ZERO_DATE または NO_ZERO_IN_DATE SQL モードが有効になっているときに、日付の値のデフォルトがそのモードに従って正しくない場合、CREATE TABLE では厳密な SQL モードが有効になっていない場合は警告を、厳密モードが有効になっている場合はエラーを生成します。たとえば、NO_ZERO_IN_DATE が有効になっている場合は、c1 DATE DEFAULT '2010-00-00' によって警告が生成されます。(MySQL 5.6.6 より前は、厳密モードが有効になっていない場合でも、このステートメントはエラーを生成します。)

  • COMMENT オプションを使用して、カラムのコメントを最大 1024 文字の長さで指定できます。このコメントは、SHOW CREATE TABLE および SHOW FULL COLUMNS ステートメントによって表示されます。

  • MySQL Cluster では、COLUMN_FORMAT を使用して、NDB テーブルの個々のカラムのデータストレージフォーマットを指定することもできます。許可されるカラムフォーマットは、FIXEDDYNAMIC、および DEFAULT です。FIXED は固定幅のストレージを指定するために使用され、DYNAMIC はカラムが可変幅になることを許可し、DEFAULT はカラムで、そのカラムのデータ型によって決定される固定幅または可変幅のストレージが使用されるようにします (ROW_FORMAT 指定子によってオーバーライドされる可能性があります)。

    NDB テーブルの場合、COLUMN_FORMAT のデフォルト値は DEFAULT です。

    COLUMN_FORMAT は現在、NDB 以外のストレージエンジンを使用しているテーブルのカラムには影響を与えません。MySQL 5.6 以降では、COLUMN_FORMAT は暗黙のうちに無視されます。

  • NDB テーブルの場合は、STORAGE 句を使用して、カラムがディスク上またはメモリー内のどちらに格納されるかを指定することもできます。STORAGE DISK を指定するとカラムはディスク上に格納され、STORAGE MEMORY を指定するとインメモリーストレージが使用されます。使用される CREATE TABLE ステートメントには、引き続き TABLESPACE 句が含まれている必要があります。

    mysql> CREATE TABLE t1 ( -> c1 INT STORAGE DISK, -> c2 INT STORAGE MEMORY -> ) ENGINE NDB;ERROR 1005 (HY000): Can't create table 'c.t1' (errno: 140)mysql> CREATE TABLE t1 ( -> c1 INT STORAGE DISK, -> c2 INT STORAGE MEMORY -> ) TABLESPACE ts_1 ENGINE NDB;Query OK, 0 rows affected (1.06 sec)

    NDB テーブルの場合、STORAGE DEFAULTSTORAGE MEMORY と同等です。

    STORAGE 句は、NDB 以外のストレージエンジンを使用しているテーブルには影響を与えません。STORAGE キーワードは、MySQL Cluster に付属の mysqld の構築でのみサポートされます。ほかのどのバージョンの MySQL でも認識されません。その場合は、STORAGE キーワードを使用しようとすると、必ず構文エラーが発生します。

  • KEY は通常、INDEX のシノニムです。キー属性 PRIMARY KEY もまた、カラム定義内で指定する場合は、単に KEY として指定できます。これは、ほかのデータベースシステムとの互換性のために実装されました。

  • UNIQUE インデックスは、そのインデックス内のすべての値が異なっている必要があるという制約を作成します。既存の行に一致するキー値を持つ新しい行を追加しようとすると、エラーが発生します。すべてのエンジンについて、UNIQUE インデックスは、NULL を含むことができるカラムでの複数の NULL 値を許可します。

  • PRIMARY KEY は、すべてのキーカラムを NOT NULL として定義する必要のある一意のインデックスです。それらが NOT NULL として明示的に宣言されていない場合、MySQL は、それらを暗黙的に (かつ警告なしで) そのように宣言します。テーブルに存在できる PRIMARY KEY は 1 つだけです。PRIMARY KEY の名前は、常に PRIMARY です。そのため、これをその他のどの種類のインデックスの名前としても使用できません。

    PRIMARY KEY が存在しないときに、アプリケーションがテーブル内の PRIMARY KEY を要求した場合、MySQL は、NULL カラムのない最初の UNIQUE インデックスを PRIMARY KEY として返します。

    InnoDB テーブルでは、セカンダリインデックスのためのストレージのオーバーヘッドを最小限に抑えるために、PRIMARY KEY を短い値に維持してください。各セカンダリインデックスエントリには、対応する行の主キーカラムのコピーが含まれています。(セクション14.2.13「InnoDB テーブルおよびインデックスの構造」を参照してください。)

  • 作成されたテーブルでは、PRIMARY KEY が最初に配置され、そのあとにすべての UNIQUE インデックス、さらに一意でないインデックスが続きます。これは、MySQL オプティマイザが、使用するインデックスに優先順位を付けたり、重複した UNIQUE キーをよりすばやく検出したりするのに役立ちます。

  • PRIMARY KEY をマルチカラムインデックスにすることができます。ただし、カラム指定で PRIMARY KEY キー属性を使用してマルチカラムインデックスを作成することはできません。それを行なっても、その単一カラムがプライマリとしてマークされるだけです。個別の PRIMARY KEY(index_col_name, ...) 句を使用する必要があります。

  • PRIMARY KEY または UNIQUE インデックスが、整数型を含む 1 つのカラムのみで構成されている場合は、SELECT ステートメントでそのカラムを _rowid として参照することもできます。

  • MySQL では、PRIMARY KEY の名前は PRIMARY です。その他のインデックスでは、名前を割り当てなかった場合、そのインデックスには最初のインデックス付きカラムと同じ名前が割り当てられ、それを一意にするためにオプションのサフィクス (_2_3...) が付けられます。テーブルのインデックス名は、SHOW INDEX FROM tbl_name を使用して確認できます。セクション13.7.5.23「SHOW INDEX 構文」を参照してください。

  • 一部のストレージエンジンでは、インデックスの作成時にインデックスタイプを指定できます。index_type 指定子の構文は、USING type_name です。

    例:

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

    USING の推奨される位置は、インデックスカラムリストのあとです。カラムリストの前にも指定できますが、このオプションをその位置で使用するためのサポートは非推奨であり、将来の MySQL リリースで削除される予定です。

    index_option 値は、インデックスの追加オプションを指定します。USING はそのようなオプションの 1 つです。許可される index_option 値の詳細は、セクション13.1.13「CREATE INDEX 構文」を参照してください。

    インデックスの詳細は、セクション8.3.1「MySQL のインデックスの使用の仕組み」を参照してください。

  • MySQL 5.6 では、NULL 値を持つことができるカラム上のインデックスをサポートするのは InnoDBMyISAM、および MEMORY だけです。それ以外の場合は、インデックス付きカラムを NOT NULL として宣言する必要があります。そうしないと、エラー結果が発生します。

  • CHARVARCHARBINARY、および VARBINARY カラムの場合は、col_name(length) 構文を使用してインデックスプリフィクス長を指定することにより、カラム値の先頭の部分のみを使用するインデックスを作成できます。BLOB および TEXT カラムにもインデックスを設定できますが、プリフィクス長を指定する必要があります。プリフィクス長は、バイナリ以外の文字列型の場合は文字数で、バイナリ文字列型の場合はバイト単位で指定されます。つまり、インデックスエントリは、CHARVARCHAR、および TEXT カラムの場合は各カラム値の最初の length 文字、BINARYVARBINARY、および BLOB カラムの場合は各カラム値の最初の length バイトで構成されます。このようにカラム値のプリフィクスのみにインデックスを設定すると、インデックスファイルをはるかに小さくできます。セクション8.3.4「カラムインデックス」を参照してください。

    BLOB および TEXT カラム上のインデックス設定をサポートするのは、InnoDB および MyISAM ストレージエンジンだけです。例:

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

    InnoDB テーブルではプリフィクスの長さを最大 767 バイトに、また innodb_large_prefix オプションが有効になっている場合は 3072 バイトにすることができます。プリフィクスの制限がバイト単位で測定されるのに対して、CREATE TABLE ステートメントでのプリフィクス長は、バイナリ以外のデータ型 (CHARVARCHARTEXT) では文字数として解釈されます。複数バイトの文字セットを使用するカラムのプリフィクス長を指定する場合は、この点を考慮に入れてください。

  • index_col_name の指定を ASC または DESC で終了させることができます。これらのキーワードは、インデックス値の昇順または降順での格納を指定する将来の拡張のために許可されています。現在、これらは解析されますが、無視されます。インデックス値は、常に昇順で格納されます。

  • SELECT 内でカラムに対して ORDER BY または GROUP BY を使用すると、サーバーは、max_sort_length システム変数によって示されている初期のバイト数のみを使用して値をソートします。

  • 全文検索に使用される特殊な FULLTEXT インデックスを作成できます。FULLTEXT インデックスをサポートするのは、InnoDB および MyISAM だけです。これらは、CHARVARCHAR、および TEXT カラムからのみ作成できます。インデックス設定は常に、カラム全体に対して実行されます。カラムプリフィクスのインデックス設定はサポートされていないため、プリフィクス長が指定されてもすべて無視されます。操作の詳細は、セクション12.9「全文検索関数」を参照してください。WITH PARSER 句は、全文インデックス設定および検索操作に特殊な処理が必要な場合にパーサープラグインをインデックスに関連付けるために、index_option 値として指定できます。この句は、FULLTEXT インデックスに対してのみ有効です。プラグインの作成の詳細は、セクション24.2「MySQL プラグイン API」を参照してください。

  • 空間データ型に SPATIAL インデックスを作成できます。空間型は MyISAM テーブルでのみサポートされ、インデックス付きカラムを NOT NULL として宣言する必要があります。セクション11.5「空間データの拡張」を参照してください。

  • MySQL 5.6 では、インデックス定義に最大 1024 文字のオプションのコメントを含めることができます。

  • InnoDB および NDB テーブルは、外部キー制約のチェックをサポートしています。参照されるテーブルのカラムには、常に明示的に名前を付ける必要があります。外部キーに対しては ON DELETEON UPDATE の両方のアクションがサポートされています。詳細および例については、セクション13.1.17.2「外部キー制約の使用」を参照してください。InnoDB での外部キーに固有の情報については、セクション14.6.6「InnoDB と FOREIGN KEY 制約」を参照してください。

    その他のストレージエンジンの場合、MySQL Server は、CREATE TABLE ステートメント内の FOREIGN KEY および REFERENCES 構文を解析して無視します。CHECK 句は、すべてのストレージエンジンによって解析されますが、無視されます。セクション1.7.2.4「外部キーの違い」を参照してください。

    重要

    ANSI/ISO SQL 標準に精通しているユーザーの場合は、参照整合性の制約定義で使用される MATCH 句を認識または適用するストレージエンジンは (InnoDB を含め) 存在しません。明示的な MATCH 句を使用しても、指定された効果が得られないだけでなく、ON DELETE および ON UPDATE 句が無視される原因にもなります。これらの理由により、MATCH の指定は避けるようにしてください。

    SQL 標準での MATCH 句は、複合 (マルチカラム) 外部キー内の NULL 値が、主キーとの比較時にどのように処理されるかを制御します。InnoDB は基本的に、外部キーをすべてまたは部分的に NULL にすることが許可される、MATCH SIMPLE で定義されるセマンティクスを実装しています。その場合は、このような外部キーを含む (子テーブルの) 行の挿入が許可され、その行は参照される (親) テーブル内のどの行にも一致しません。トリガーを使用して、ほかのセマンティクスを実装できます。

    さらに、MySQL ではパフォーマンスのために、参照されるカラムにインデックスを設定する必要があります。ただし、参照されるカラムを UNIQUE または NOT NULL として宣言するという要件は適用されません。一意でないキーまたは NULL 値を含むキーへの外部キー参照の処理は、UPDATEDELETE CASCADE などの操作に対して適切に定義されていません。UNIQUE (または PRIMARY) と NOT NULL の両方であるキーのみを参照する外部キーを使用することをお勧めします。

    MySQL は、参照がカラム指定の一部として定義されている (SQL 標準で定義された) インラインの REFERENCES 指定を認識せず、またサポートもしていません。MySQL は、個別の FOREIGN KEY 指定の一部として指定されている場合にのみ REFERENCES 句を受け入れます。

    注記

    InnoDB ストレージエンジンを使用するパーティション化されたテーブルは、外部キーをサポートしていません。KEY または LINEAR KEY によってパーティション化された NDB テーブルは、この制限によって影響を受けません。詳細については、セクション19.6「パーティショニングの制約と制限」を参照してください。

  • テーブルあたり 4096 カラムという強い制限値がありますが、特定のテーブルでは、実際の最大数がこれより少なくなる可能性があります。実際の最大数は、セクションD.10.4「テーブルカラム数と行サイズの制限」で説明されている要因によって異なります。

TABLESPACE および STORAGE テーブルオプションは、NDB テーブルでのみ使用されます。tablespace_name という名前のテーブルスペースが、すでに CREATE TABLESPACE を使用して作成されている必要があります。STORAGE は、使用されるストレージのタイプ (ディスクまたはメモリー) を決定するものであり、DISKMEMORYDEFAULT のいずれかです。

TABLESPACE ... STORAGE DISK は、MySQL Cluster ディスクデータテーブルスペースにテーブルを割り当てます。詳細は、セクション18.5.12「MySQL Cluster ディスクデータテーブル」を参照してください。

重要

STORAGE 句を、TABLESPACE 句のない CREATE TABLE ステートメントで使用することはできません。

Storage Engines (ストレージエンジン)

ENGINE テーブルオプションは、次の表に示されている名前のいずれかを使用して、テーブルのストレージエンジンを指定します。エンジン名は、引用符で囲んでも囲まなくてもかまいません。引用符で囲まれた名前 'DEFAULT' は認識されますが、無視されます。

ストレージエンジン説明
InnoDB行ロックと外部キーを備えたトランザクションセーフテーブル。新しいテーブルのためのデフォルトのストレージエンジン。MySQL は経験しているが、InnoDB がはじめてである場合は、第14章「InnoDB ストレージエンジン、そのなかでも特にセクション14.1.1「デフォルトの MySQL ストレージエンジンとしての InnoDB」を参照してください。
MyISAM主に読み取り専用または読み取りが大半のワークロードに使用される、バイナリの移植可能なストレージエンジン。セクション15.2「MyISAM ストレージエンジン」を参照してください。
MEMORYこのストレージエンジンのデータは、メモリー内にのみ格納されます。セクション15.3「MEMORY ストレージエンジン」を参照してください。
CSVカンマ区切り値形式で行を格納するテーブル。セクション15.4「CSV ストレージエンジン」を参照してください。
ARCHIVEアーカイブストレージエンジン。セクション15.5「ARCHIVE ストレージエンジン」を参照してください。
EXAMPLEサンプルのエンジン。セクション15.9「EXAMPLE ストレージエンジン」を参照してください。
FEDERATEDリモートテーブルにアクセスするストレージエンジン。セクション15.8「FEDERATED ストレージエンジン」を参照してください。
HEAPこれは MEMORY のシノニムです。
MERGE1 つのテーブルとして使用される MyISAM テーブルのコレクション。MRG_MyISAM とも呼ばれます。セクション15.7「MERGE ストレージエンジン」を参照してください。
NDBトランザクションと外部キーをサポートする、クラスタ化された、耐障害の、メモリーベースのテーブル。NDBCLUSTER とも呼ばれます。第18章「MySQL Cluster NDB 7.3 および MySQL Cluster NDB 7.4を参照してください。

使用できないストレージエンジンが指定されている場合、MySQL は、代わりにデフォルトのエンジンを使用します。通常、これは MyISAM です。たとえば、テーブル定義に ENGINE=INNODB オプションが含まれているが、MySQL サーバーが INNODB テーブルをサポートしていない場合、テーブルは MyISAM テーブルとして作成されます。これにより、マスター上にはトランザクションテーブルが存在するが、スレーブ上に作成されるテーブルは (高速化のために) 非トランザクションであるようなレプリケーションセットアップを行うことが可能になります。MySQL 5.6 では、ストレージエンジンの指定が受け付けられない場合は警告が発生します。

セクション5.1.7「サーバー SQL モード」で説明されているように、NO_ENGINE_SUBSTITUTION SQL モードの設定によってエンジンの置換を制御できます。

注記

ENGINE のシノニムであった古い TYPE オプションは、MySQL 5.5 で削除されました。MySQL 5.5 以降にアップグレードする場合は、TYPE に依存する既存のアプリケーションを、代わりに ENGINE を使用するように変換する必要があります

パフォーマンスの最適化

その他のテーブルオプションは、テーブルの動作を最適化するために使用されます。ほとんどの場合は、それらのうちのどれも指定する必要はありません。特に示されていないかぎり、これらのオプションはすべてのストレージエンジンに適用されます。特定のストレージエンジンに適用されないオプションは、テーブル定義の一部として受け入れられ、記憶される可能性があります。それにより、あとで ALTER TABLE を使用して、別のストレージエンジンを使用するようにテーブルを変換した場合に、このようなオプションが適用されます。

  • AUTO_INCREMENT

    テーブルの初期の AUTO_INCREMENT 値。MySQL 5.6 では、これは MyISAMMEMORYInnoDB、および ARCHIVE テーブルに対して機能します。AUTO_INCREMENT テーブルオプションをサポートしていないエンジンの最初の自動インクリメント値を設定するには、テーブルを作成したあとに目的の値より 1 小さい値を持つダミーの行を挿入してから、そのダミーの行を削除します。

    CREATE TABLE ステートメント内の AUTO_INCREMENT テーブルオプションをサポートするエンジンの場合は、ALTER TABLE tbl_name AUTO_INCREMENT = N を使用して AUTO_INCREMENT 値をリセットすることもできます。この値を、現在カラム内にある最大値より小さく設定することはできません。

  • AVG_ROW_LENGTH

    テーブルの平均の行の長さの近似値。これを設定する必要があるのは、可変サイズの行を持つ大きなテーブルの場合だけです。

    MyISAM テーブルを作成すると、MySQL は MAX_ROWS および AVG_ROW_LENGTH オプションの積を使用して、結果として得られるテーブルがどれくらいの大きさになるかを判定します。どちらのオプションも指定しない場合、MyISAM データおよびインデックスファイルの最大サイズは、デフォルトで 256T バイトになります。(オペレーティングシステムでその大きさのファイルがサポートされていない場合、テーブルサイズはファイルサイズ制限によって制約されます。)インデックスをより小さく、かつ高速にするためにポインタサイズを小さく維持したいと考えており、実際に大きなファイルが必要でない場合は、myisam_data_pointer_size システム変数を設定することによってデフォルトのポインタサイズを小さくすることができます。(セクション5.1.4「サーバーシステム変数」を参照してください。)すべてのテーブルをデフォルトの制限を超えて拡張できるようにしたいと考えており、テーブルが必要以上に少し遅く、かつ大きくなってもかまわない場合は、この変数を設定することによってデフォルトのポインタサイズを大きくすることができます。この値を 7 に設定すると、最大 65,536T バイトのテーブルサイズが許可されます。

  • [DEFAULT] CHARACTER SET

    テーブルのデフォルトの文字セットを指定します。CHARSETCHARACTER SET のシノニムです。文字セット名が DEFAULT である場合は、データベース文字セットが使用されます。

  • CHECKSUM

    MySQL ですべての行のライブチェックサム (つまり、テーブルが変更されると MySQL が自動的に更新するチェックサム) が保持されるようにする場合は、これを 1 に設定します。これにより、テーブルの更新が少し遅くなりますが、破損したテーブルを見つけることが容易になります。CHECKSUM TABLE ステートメントは、このチェックサムをレポートします。(MyISAM のみ。)

  • [DEFAULT] COLLATE

    テーブルのデフォルトの照合順序を指定します。

  • COMMENT

    テーブルのコメントであり、長さは最大 2048 文字です。

  • CONNECTION

    FEDERATED テーブルの接続文字列。

    注記

    古いバージョンの MySQL は、接続文字列に COMMENT オプションを使用していました。

  • DATA DIRECTORYINDEX DIRECTORY

    InnoDB では、DATA DIRECTORY='directory' オプションを使用すると、MySQL データディレクトリ以外の場所に新しい InnoDB file-per-table テーブルスペースを作成できます。MySQL は、指定されたディレクトリ内にデータベース名に対応するサブディレクトリを作成し、さらにその中に新しいテーブルの .ibd ファイルを作成します。InnoDB テーブルで DATA DIRECTORY オプションを使用するには、innodb_file_per_table 構成オプションを有効にする必要があります。このディレクトリは、ディレクトリへの (相対パスではなく) フルパス名である必要があります。詳細は、セクション14.5.4「テーブルスペースの位置の指定」を参照してください。

    MyISAM テーブルを作成する場合は、DATA DIRECTORY='directory' 句、INDEX DIRECTORY='directory' 句、またはその両方を使用できます。これらは、それぞれ MyISAM テーブルのデータファイルとインデックスファイルを配置する場所を指定します。InnoDB テーブルとは異なり、DATA DIRECTORY または INDEX DIRECTORY オプションで MyISAM テーブルを作成する場合、MySQL はデータベース名に対応するサブディレクトリを作成しません。各ファイルは、指定されたディレクトリ内に作成されます。

    重要

    テーブルレベルの DATA DIRECTORY および INDEX DIRECTORY オプションは、パーティション化されたテーブルでは無視されます。(Bug #32091)

    これらのオプションは、--skip-symbolic-links オプションを使用していない場合にのみ機能します。また、オペレーティングシステムにも、機能するスレッドに対して安全な realpath() 呼び出しが存在する必要があります。詳細は、セクション8.11.3.1.2「Unix 上の MyISAM へのシンボリックリンクの使用」を参照してください。

    MyISAM テーブルが DATA DIRECTORY オプションなしで作成される場合、.MYD ファイルがデータベースディレクトリ内に作成されます。デフォルトでは、MyISAM が既存の .MYD ファイルを検出した場合、そのファイルを上書きします。INDEX DIRECTORY オプションを指定せずに作成されたテーブルについて、.MYI ファイルに同じことが当てはまります。この動作を抑制するには、--keep_files_on_create オプションを使用してサーバーを起動します。その場合、MyISAM は既存のファイルを上書きせず、代わりにエラーを返します。

    MyISAM テーブルが DATA DIRECTORY または INDEX DIRECTORY オプションを使用して作成され、既存の .MYD または .MYI ファイルが見つかった場合、MyISAM は常にエラーを返します。指定されたディレクトリ内のファイルは上書きされません。

    重要

    DATA DIRECTORY または INDEX DIRECTORY では、MySQL データディレクトリを含むパス名を使用できません。これには、パーティション化されたテーブルや個々のテーブルパーティションが含まれます。(Bug #32167 を参照してください。)

  • DELAY_KEY_WRITE

    テーブルのキー更新をテーブルが閉じられるまで遅らせる場合は、これを 1 に設定します。セクション5.1.4「サーバーシステム変数」にある delay_key_write システム変数の説明を参照してください。(MyISAM のみ。)

  • INSERT_METHOD

    MERGE テーブルにデータを挿入する場合は、INSERT_METHOD を使用して、行を挿入するテーブルを指定する必要があります。INSERT_METHOD は、MERGE テーブルにのみ役立つオプションです。最初または最後のテーブルに挿入するには FIRST または LAST の値を、挿入されないようにするには NO の値を使用します。セクション15.7「MERGE ストレージエンジン」を参照してください。

  • KEY_BLOCK_SIZE

    圧縮されたInnoDB テーブルでは、オプションで、ページに使用するサイズをバイト単位で指定します。この値はヒントとして扱われます。InnoDB では、必要に応じて異なるサイズが使用される可能性があります。値 0 は、innodb_page_size 値の半分であるデフォルトの圧縮済みページサイズを表します。KEY_BLOCK_SIZE 値は、innodb_page_size 値以下にしかできません。innodb_page_size 値を超える値を指定した場合は、その値が無視され、警告が発行されます。また、KEY_BLOCK_SIZEinnodb_page_size 値の半分に設定されます。innodb_strict_mode=ON の場合、無効な KEY_BLOCK_SIZE 値を指定するとエラーが返されます。使用法の詳細は、セクション14.7「InnoDB 圧縮テーブル」を参照してください。

    個々のインデックス定義では、テーブルの値をオーバーライドする独自の KEY_BLOCK_SIZE 値を指定できます。

    注記

    InnoDB テーブルに対して KEY_BLOCK_SIZE 句を使用している場合は、innodb_strict_mode を有効にすることをお勧めします。

  • MAX_ROWS

    テーブル内に格納することを予定している行の最大数。これは強い制限値ではなく、どちらかと言うと、テーブルが少なくともこの行数を格納できる必要があるという、ストレージエンジンへのヒントです。

    NDB ストレージエンジンは、この値を最大値として扱います。非常に大きな (数百万行を含む) MySQL Cluster テーブルを作成する予定がある場合は、このオプションを使用して MAX_ROWS = 2 * rows を設定することにより、テーブルの主キーのハッシュを格納するために使用されるハッシュテーブル内に NDB によって十分な数のインデックススロットが割り当てられることを保証するようにしてください。ここで、rows はテーブルに挿入することが予測される行数です。

    MAX_ROWS の最大値は 4294967295 です。これを超える値は、この制限に切り捨てられます。

  • MIN_ROWS

    テーブル内に格納することを予定している行の最小数。MEMORY ストレージエンジンは、このオプションをメモリー使用に関するヒントとして使用します。

  • PACK_KEYS

    PACK_KEYS は、MyISAM テーブルでのみ有効になります。インデックスを小さくする場合は、このオプションを 1 に設定します。通常は、これによって更新は遅く、読み取りは高速になります。このオプションを 0 に設定すると、キーのすべてのパッキングが無効になります。これを DEFAULT に設定すると、長い CHARVARCHARBINARY、または VARBINARY カラムのみをパックするようストレージエンジンに指示します。

    PACK_KEYS を使用しない場合、デフォルトでは文字列をパックしますが、数値はパックしません。PACK_KEYS=1 を使用した場合は、数値もパックされます。

    2 進数のキーをパックする場合、MySQL は次のプリフィクス圧縮を使用します。

    • 前のキーの何バイトが次のキーと同じであるかを示すために、すべてのキーに 1 バイトが余分に必要になります。

    • 行へのポインタは、圧縮率を向上させるために、キーの直後に高位バイトが先に来る順序で格納されます。

    つまり、2 つの連続した行に等しいキーが多数存在する場合は、次の同じキーはすべて、通常 (行へのポインタを含め) 2 バイトしか占有しません。これを、次のキーが storage_size_for_key + pointer_size (ここで、ポインタサイズは通常 4) を占有する通常のケースと比較してください。逆に言うと、プリフィクス圧縮から大きな利点が得られるのは、同じ数値が多数存在する場合だけです。すべてのキーが完全に異なっている場合は、そのキーが NULL 値を持つことができるキーでないかぎり、キーあたり 1 バイト多く使用されます。(この場合、パックされたキーの長さは、キーが NULL であるかどうかをマークするために使用されるのと同じバイトに格納されます。)

  • PASSWORD

    このオプションは使用されません。.frm ファイルを暗号化し、ほかのどの MySQL サーバーからも使用できないようにする必要がある場合は、当社の販売部門に問い合わせてください。

  • ROW_FORMAT

    行が格納される物理フォーマットを定義します。これらの選択は、テーブルに使用されているストレージエンジンによって異なります。

    InnoDB テーブルの場合:

    • デフォルトでは、行は圧縮形式 (ROW_FORMAT=COMPACT) で格納されます。

    • 古いバージョンの MySQL で使用されていた非圧縮形式は、ROW_FORMAT=REDUNDANT を指定することによって引き続き要求できます。

    • InnoDB テーブルの圧縮を有効にするには、ROW_FORMAT=COMPRESSED を指定し、セクション14.7「InnoDB 圧縮テーブル」の手順に従います。

    • データ型 (特に BLOB 型) の InnoDB ストレージの効率を向上させるには、ROW_FORMAT=DYNAMIC を指定し、セクション14.9.3「DYNAMIC および COMPRESSED 行フォーマット」の手順に従います。COMPRESSED および DYNAMIC 行フォーマットはどちらも、構成設定 innodb_file_per_table=1 および innodb_file_format=barracuda を使用してテーブルを作成する必要があります。

    • デフォルト以外の ROW_FORMAT 句を指定する場合は、innodb_strict_mode 構成オプションも有効にすることを考慮してください。

    • InnoDB 行フォーマットの詳細は、セクション14.9「InnoDB の行ストレージと行フォーマット」を参照してください。

    MyISAM テーブルの場合は、このオプション値を、静的行フォーマットまたは可変長行フォーマットを示す FIXED または DYNAMIC に設定できます。myisampack は、この型を COMPRESSED に設定します。セクション15.2.3「MyISAM テーブルのストレージフォーマット」を参照してください。

    注記

    CREATE TABLE ステートメントを実行するとき、テーブルに使用しているストレージエンジンでサポートされていない行フォーマットを指定した場合、テーブルはそのストレージエンジンのデフォルトの行フォーマットを使用して作成されます。SHOW TABLE STATUS に応答してこのカラムでレポートされる情報は、使用されている実際の行フォーマットです。作成中は元の CREATE TABLE 定義が保持されているため、これは Create_options カラム内の値とは異なる可能性があります。

  • STATS_AUTO_RECALC

    InnoDB テーブルの永続的統計を自動的に再計算するかどうかを指定します。値 DEFAULT を指定すると、テーブルの永続的統計設定は innodb_stats_auto_recalc 構成オプションによって決定されます。値 1 を指定すると、統計は、テーブル内のデータの 10% が変更されたときに再計算されます。値 0 は、このテーブルの自動再計算が行われないようにします。この設定の場合、テーブルへの大幅な変更を行なったあとに統計を再計算するには、ANALYZE TABLE ステートメントを発行します。永続的統計機能の詳細は、セクション14.13.16.1「永続的オプティマイザ統計のパラメータの構成」を参照してください。

  • STATS_PERSISTENT

    InnoDB テーブルの永続的統計を有効にするかどうかを指定します。値 DEFAULT を指定すると、テーブルの永続的統計設定は innodb_stats_persistent 構成オプションによって決定されます。値 1 がテーブルの永続的統計を有効にするのに対して、値 0 はこの機能を無効にします。CREATE TABLE または ALTER TABLE ステートメントを使用して永続的統計を有効にしたあと、代表的なデータのテーブルへのロード後に統計を計算するには、ANALYZE TABLE ステートメントを発行します。永続的統計機能の詳細は、セクション14.13.16.1「永続的オプティマイザ統計のパラメータの構成」を参照してください。

  • STATS_SAMPLE_PAGES

    インデックス付きカラムのカーディナリティーやその他の統計 (ANALYZE TABLE によって計算される統計など) を推定するときにサンプリングするインデックスページの数。詳細は、セクション14.13.16.1「永続的オプティマイザ統計のパラメータの構成」を参照してください。

  • UNION

    UNION は、同一の MyISAM テーブルのコレクションを 1 つのものとしてアクセスする場合に使用されます。これは、MERGE テーブルでのみ機能します。セクション15.7「MERGE ストレージエンジン」を参照してください。

    MERGE テーブルにマップするテーブルに対する SELECTUPDATE、および DELETE 権限が必要です。

    注記

    以前は、使用されるすべてのテーブルが MERGE テーブル自体と同じデータベース内に存在する必要がありました。この制限は適用されなくなりました。

パーティション化

partition_options を使用すると、CREATE TABLE で作成されたテーブルのパーティション化を制御できます。

重要

このセクションの最初にある partition_options の構文に示されているすべてのオプションが、すべてのパーティショニングタイプに使用できるわけではありません。各タイプに固有の情報については、次の個々のタイプのリストを参照してください。また、MySQL でのパーティション化の動作や使用に関するより詳細な情報、および MySQL のパーティション化に関連したテーブル作成やその他のステートメントの追加の例については、第19章「パーティション化を参照してください。

partition_options 句が使用される場合、この句は PARTITION BY で始まります。この句には、パーティションを決定するために使用される関数が含まれています。この関数は、1 から num までの範囲の整数値を返します。ここで、num はパーティションの数です。(テーブルに含めることのできるユーザー定義パーティションの最大数は 1024 です。この最大数には、このセクションのあとの方で説明されているサブパーティションの数が含まれています。)MySQL 5.6 で、この関数に使用可能な選択肢を次のリストに示します。

  • HASH(expr): 行の配置および検索のためのキーを作成するために 1 つ以上のカラムをハッシュします。expr は、1 つ以上のテーブルカラムを使用した式です。これは、1 つの整数値が得られる任意の有効な MySQL 式 (MySQL 関数を含む) にすることができます。たとえば、次はどちらも、PARTITION BY HASH を使用した有効な CREATE TABLE ステートメントです。

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

    PARTITION BY HASH では、VALUES LESS THAN または VALUES IN のどちらの句も使用できません。

    PARTITION BY HASH は、expr をパーティションの数で割った余り (つまり、法) を使用します。例および追加情報については、セクション19.2.4「HASH パーティショニング」を参照してください。

    LINEAR キーワードには、いくぶん異なるアルゴリズムが必要になります。この場合、行が格納されるパーティションの数は、1 つ以上の論理的な AND 演算の結果として計算されます。線形ハッシュの説明および例については、セクション19.2.4.1「LINEAR HASH パーティショニング」を参照してください。

  • KEY(column_list): これは HASH に似ていますが、均一なデータ分散を保証するために MySQL がハッシュ関数を提供する点が異なります。column_list 引数は、単純に 1 つ以上のテーブルカラム (最大 16 個) のリストです。この例は、4 つのパーティションを持つ、キーによってパーティション化された単純なテーブルを示しています。

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

    キーによってパーティション化されたテーブルの場合は、LINEAR キーワードを使用して線形パーティション化を採用できます。これには、HASH によってパーティション化されたテーブルの場合と同じ効果があります。つまり、パーティション番号は法ではなく、& 演算子を使用して見つけられます (詳細は、セクション19.2.4.1「LINEAR HASH パーティショニング」およびセクション19.2.5「KEY パーティショニング」を参照してください)。この例では、キーによる線形パーティション化を使用して 5 つのパーティション間でデータを分散させます。

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

    ALGORITHM={1|2} オプションは、MySQL 5.6.11 から [SUB]PARTITION BY [LINEAR] KEY でサポートされています。ALGORITHM=1 を指定すると、サーバーは MySQL 5.1 と同じキーハッシュ関数を使用します。ALGORITHM=2 は、サーバーが、MySQL 5.5 以降で実装され、KEY によってパーティション化された新しいテーブルに対してデフォルトで使用されるキーハッシュ関数を採用することを示します。(MySQL 5.5 以降で採用されたキーハッシュ関数によって作成されたパーティション化されたテーブルを MySQL 5.1 サーバーで使用することはできません。)このオプションを指定しない場合は、ALGORITHM=2 を使用するのと同じ効果があります。このオプションは、主に [LINEAR] KEY によってパーティション化されたテーブルを MySQL 5.1 以降の MySQL バージョン間でアップグレードまたはダウングレードするときに使用するか、または MySQL 5.5 以降のサーバー上で、MySQL 5.1 サーバー上で使用できる KEY または LINEAR KEY によってパーティション化されたテーブルを作成することを目的にしています。詳細は、セクション13.1.7.1「ALTER TABLE パーティション操作」を参照してください。

    MySQL 5.6.11 以降の mysqldump は、このオプションをバージョン管理されたコメント内に次のように書き込みます。

    CREATE TABLE t1 (a INT) 

    これにより、MySQL 5.6.10 以前のサーバーはこのオプションを無視するようになります。これらのバージョンでは、通常であれば構文エラーが発生します。KEY によってパーティション化またはサブパーティション化されたテーブルを使用している MySQL 5.5.31 またはそれ以降の MySQL 5.5 サーバー上で作成されたダンプを、バージョン 5.6.11 より前の MySQL 5.6 サーバーにロードする予定がある場合は、続行する前に、必ずセクション2.11.1.3「MySQL 5.5 から 5.6 へのアップグレード」を参照するようにしてください。(そこで見つかった情報は、MySQL 5.6.11 以降のサーバーから作成された KEY によってパーティション化またはサブパーティション化されたテーブルを含むダンプを、MySQL 5.5.30 以前のサーバーにロードする場合にも適用されます。)

    また、MySQL 5.6.11 以降では、ALGORITHM=1mysqldump と同じ方法で、バージョン管理されたコメントを使用して SHOW CREATE TABLE の出力に必要に応じて表示されます。ALGORITHM=2 は、元のテーブルを作成するときにこのオプションが指定された場合でも、SHOW CREATE TABLE の出力から常に省略されます。

    PARTITION BY KEY では、VALUES LESS THAN または VALUES IN のどちらの句も使用できません。

  • RANGE(expr): この場合、expr は、VALUES LESS THAN 演算子のセットを使用して値の範囲を示します。範囲のパーティション化を使用する場合は、VALUES LESS THAN を使用して、少なくとも 1 つのパーティションを定義する必要があります。範囲のパーティション化では VALUES IN を使用できません。

    注記

    RANGE によってパーティション化されたテーブルでは、VALUES LESS THAN を整数リテラル値、または 1 つの整数値に評価される式のどちらかとともに使用する必要があります。MySQL 5.6 では、このセクションのあとの方で説明されている、PARTITION BY RANGE COLUMNS を使用して定義されたテーブルでこの制限を克服できます。

    次のスキームに従って、年の値を含むカラムに関してパーティション化するテーブルがあるとします。

    パーティション番号:年の範囲:
    01990 以前
    11991 から 1994 まで
    21995 から 1998 まで
    31999 から 2002 まで
    42003 から 2005 まで
    52006 以降

    このようなパーティション化スキームを実装するテーブルは、次に示す CREATE TABLE ステートメントによって実現できます。

    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 ... ステートメントは、連続的に機能します。VALUES LESS THAN MAXVALUE は、それ以外で指定されている最大値より大きい残りの値を指定するように機能します。

    VALUES LESS THAN 句は (C、Java、PHP などの多くのプログラミング言語に見られるような) switch ... case ブロックの case 部分と同様の方法で連続的に機能します。つまり、この句は、連続した各 VALUES LESS THAN で指定されている上限が前の句の上限より大きく、かつ MAXVALUE を参照している句がリスト内のすべての句の最後に来るような方法で配置されている必要があります。

  • RANGE COLUMNS(column_list): RANGE に対するこのバリアントは、複数のカラムに関する範囲条件を使用した (つまり、WHERE a = 1 AND b < 10WHERE a = 1 AND b = 10 AND c < 10 などの条件を持つ) クエリーに対するパーティションプルーニングを容易にします。これにより、COLUMNS 句内のカラムのリストと、各 PARTITION ... VALUES LESS THAN (value_list) パーティション定義句内のカラム値のセットを使用して、複数のカラム内の値の範囲を指定できるようになります。(もっとも単純なケースでは、このセットは単一カラムで構成されます。)column_list および value_list で参照できるカラムの最大数は 16 です。

    COLUMNS 句で使用される column_list には、カラムの名前のみを含めることができます。リスト内の各カラムは MySQL のデータ型のうち、整数型、文字列型、および時間または日付カラム型のいずれかである必要があります。BLOBTEXTSETENUMBIT、または空間データ型を使用したカラムは許可されていません。浮動小数点数型を使用するカラムも許可されていません。また、COLUMNS 句では、関数や演算式も使用できません。

    パーティション定義で使用される VALUES LESS THAN 句は、COLUMNS() 句に現れるカラムごとにリテラル値を指定する必要があります。つまり、各 VALUES LESS THAN 句で使用される値のリストには、COLUMNS 句にリストされているカラムの数と同じ数の値が含まれている必要があります。VALUES LESS THAN 句で COLUMNS 句に存在する数より多いか、または少ない値を使用しようとすると、このステートメントはエラー Inconsistency in usage of column lists for partitioning... で失敗します。VALUES LESS THAN に現れるどの値にも NULL は使用できません。この例に示すように、最初のカラム以外の特定のカラムで MAXVALUE を複数回使用できます。

    CREATE TABLE rc ( a INT NOT NULL, b INT NOT NULL
    )
    PARTITION BY RANGE COLUMNS(a,b) ( PARTITION p0 VALUES LESS THAN (10,5), PARTITION p1 VALUES LESS THAN (20,10), PARTITION p2 VALUES LESS THAN (MAXVALUE,15), PARTITION p3 VALUES LESS THAN (MAXVALUE,MAXVALUE)
    );

    VALUES LESS THAN 値リストで使用されている各値が、対応するカラムの型に正確に一致している必要があります。変換は行われません。たとえば、整数型を使用するカラムに一致する値として文字列 '1' を使用したり (代わりに、数値 1 を使用する必要があります)、文字列型を使用するカラムに一致する値として数値 1 を使用したりすることはできません (このような場合は、引用符で囲まれた文字列 '1' を使用する必要があります)。

    詳細は、セクション19.2.1「RANGE パーティショニング」およびセクション19.4「パーティションプルーニング」を参照してください。

  • LIST(expr): これは、州または国コードなどの、制限された指定可能な値のセットを持つテーブルカラムに基づいてパーティションを割り当てる場合に役立ちます。このような場合は、特定の州または国に関連するすべての行を単一パーティションに割り当てたり、特定の州または国のセットのためにパーティションを予約したりできます。これは RANGE に似ていますが、各パーティションに許可される値を指定するために VALUES IN しか使用できない点が異なります。

    VALUES IN は、一致させる値のリストとともに使用されます。たとえば、次のようなパーティション化スキームを作成できます。

    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)
    );

    リストのパーティション化を使用する場合は、VALUES IN を使用して、少なくとも 1 つのパーティションを定義する必要があります。PARTITION BY LIST では VALUES LESS THAN を使用できません。

    注記

    LIST によってパーティション化されたテーブルでは、VALUES IN で使用される値リストを整数値のみで構成する必要があります。MySQL 5.6 では、このセクションのあとの方で説明されている、LIST COLUMNS によるパーティション化を使用してこの制限を克服できます。

  • LIST COLUMNS(column_list): LIST に対するこのバリアントは、複数のカラムに関する比較条件を使用した (つまり、WHERE a = 5 AND b = 5WHERE a = 1 AND b = 10 AND c = 5 などの条件を持つ) クエリーに対するパーティションプルーニングを容易にします。これにより、COLUMNS 句内のカラムのリストと、各 PARTITION ... VALUES IN (value_list) パーティション定義句内のカラム値のセットを使用して、複数のカラム内の値を指定できるようになります。

    LIST COLUMNS(column_list) で使用されるカラムリストと VALUES IN(value_list) で使用される値リストに関連したデータ型を管理するルールは、VALUES IN 句では MAXVALUE が許可されず、NULL を使用できる点を除き、それぞれ RANGE COLUMNS(column_list) で使用されるカラムリストと VALUES LESS THAN(value_list) で使用される値リストの場合のルールと同じです。

    PARTITION BY LIST COLUMNSVALUES IN に使用される値のリストには、PARTITION BY LIST で使用された場合と比較して重要な違いが 1 つあります。PARTITION BY LIST COLUMNS で使用された場合、VALUES IN 句内の各要素は、カラム値のセットである必要があります。各セット内の値の数は COLUMNS 句で使用されているカラム数と同じである必要があり、これらの値のデータ型はそれらのカラムのデータ型に一致している (しかも、同じ順序で現れる) 必要があります。もっとも単純なケースでは、このセットは単一カラムで構成されます。column_list および value_list を構成する各要素で使用できるカラムの最大数は 16 です。

    次の CREATE TABLE ステートメントで定義されるテーブルは、LIST COLUMNS パーティション化を使用したテーブルの例を示しています。

    CREATE TABLE lc ( a INT NULL, b INT NULL
    )
    PARTITION BY LIST COLUMNS(a,b) ( PARTITION p0 VALUES IN( (0,0), (NULL,NULL) ), PARTITION p1 VALUES IN( (0,1), (0,2), (0,3), (1,1), (1,2) ), PARTITION p2 VALUES IN( (1,0), (2,0), (2,1), (3,0), (3,1) ), PARTITION p3 VALUES IN( (1,3), (2,2), (2,3), (3,2), (3,3) )
    );
  • オプションで、PARTITIONS num 句を使用してパーティションの数を指定できます。ここで、num はパーティションの数です。この句ほかのいずれかの PARTITION 句の両方が使用されている場合、num は、PARTITION 句を使用して宣言されているすべてのパーティションの総数と同じである必要があります。

    注記

    RANGE または LIST によってパーティション化されたテーブルの作成で PARTITIONS 句を使用するかどうかにかかわらず、テーブル定義には引き続き、少なくとも 1 つの PARTITION VALUES 句を含める必要があります (下を参照してください)。

  • オプションで、パーティションを複数のサブパーティションに分割できます。これは、オプションの SUBPARTITION BY 句を使用して示すことができます。サブパーティション化は、HASH または KEY によって実行できます。これらのどちらも LINEAR にすることができます。これらは、同等のパーティショニングタイプについて前に説明したのと同じように機能します。(LIST または RANGE によってサブパーティション化することはできません。)

    サブパーティションの数は、SUBPARTITIONS キーワードと、そのあとの整数値を使用して示すことができます。

  • PARTITIONS または SUBPARTITIONS 句で使用されている値の厳密なチェックが適用され、この値は次のルールに従っている必要があります。

    • この値は 0 以外の正の整数である必要があります。

    • 先頭の 0 は許可されません。

    • この値は整数リテラルである必要があり、式にすることはできません。たとえば、0.2E+012 に評価されたとしても、PARTITIONS 0.2E+01 は許可されません。(Bug #15890)

注記

PARTITION BY 句で使用される式 (expr) は、作成されているテーブルにはないどのカラムも参照できません。このような参照は明確に禁止されており、そのステートメントがエラーで失敗する原因になります。(Bug #29444)

各パーティションは、partition_definition 句を使用して個別に定義できます。この句を構成する個別の部分は次のとおりです。

  • PARTITION partition_name: これはパーティションの論理名を指定します。

  • VALUES 句: 範囲のパーティション化では、各パーティションに VALUES LESS THAN 句が含まれている必要があります。リストのパーティション化では、パーティションごとに VALUES IN 句を指定する必要があります。これは、このパーティションにどの行を格納するかを決定するために使用されます。構文の例については、第19章「パーティション化にあるパーティショニングタイプの説明を参照してください。

  • オプションの COMMENT 句を使用すると、このパーティションを説明する文字列を指定できます。例:

    COMMENT = 'Data for the years previous to 1999'

    MySQL 5.6.6 から、パーティションのコメントの最大長は 1024 文字です。(以前は、この制限が明示的に定義されていませんでした。)

  • DATA DIRECTORYINDEX DIRECTORY は、それぞれ、このパーティションのデータとインデックスが格納されるディレクトリを示すために使用できます。data_dirindex_dir はどちらも、絶対システムパス名である必要があります。例:

    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 p2002 VALUES IN (1998, 2002, 2006) DATA DIRECTORY = '/var/appdata/98/data' INDEX DIRECTORY = '/var/appdata/98/idx'
    );

    DATA DIRECTORYINDEX DIRECTORY は、MyISAM テーブルに使用される CREATE TABLE ステートメントの table_option 句と同じように動作します。

    パーティションごとに 1 つのデータディレクトリと 1 つのインデックスディレクトリを指定できます。指定されないままになっている場合、データとインデックスは、デフォルトではそのテーブルのデータベースディレクトリ内に格納されます。

    Windows では、DATA DIRECTORY および INDEX DIRECTORY オプションは MyISAM テーブルの個々のパーティションまたはサブパーティションに対してサポートされず、INDEX DIRECTORY オプションは InnoDB テーブルの個々のパーティションまたはサブパーティションに対してサポートされません。これらのオプションは、警告が生成される点を除き、Windows では無視されます。(Bug #30459)

    注記

    DATA DIRECTORY および INDEX DIRECTORY オプションは、NO_DIR_IN_CREATE が有効になっている場合、パーティション化されたテーブルの作成では無視されます。(Bug #24633)

  • MAX_ROWSMIN_ROWS は、それぞれ、このパーティションに格納される行の最大数と最小数を指定するために使用できます。max_number_of_rowsmin_number_of_rows の値は正の整数である必要があります。同じ名前を持つテーブルレベルのオプションと同様に、これらはサーバーへの提案としてのみ機能し、強い制限値ではありません。

  • オプションの TABLESPACE 句を使用すると、このパーティションのテーブルスペースを指定できます。MySQL Cluster にのみ使用されます。

  • パーティション化ハンドラは、PARTITIONSUBPARTITION の両方について [STORAGE] ENGINE オプションを受け入れます。現在、これを使用するには、すべてのパーティションまたはすべてのサブパーティションを同じストレージエンジンに設定するしか方法がなく、同じテーブル内のパーティションまたはサブパーティションに対して異なるストレージエンジンを設定しようとするとエラー ERROR 1469 (HY000): The mix of handlers in the partitions is not permitted in this version of MySQL が発生します。将来の MySQL リリースでは、このパーティション化に関する制限を解消する予定です。

  • オプションで、パーティション定義に 1 つ以上の subpartition_definition 句を含めることができます。これらの各句は、少なくとも SUBPARTITION name で構成されます。ここで、name はそのサブパーティションの識別子です。PARTITION キーワードが SUBPARTITION に置き換えられる点を除き、サブパーティション定義の構文はパーティション定義の構文と同じです。

    サブパーティション化は HASH または KEY によって実行する必要があり、RANGE または LIST パーティションに対してのみ実行できます。セクション19.2.6「サブパーティショニング」を参照してください。

パーティションに対しては変更、マージ、テーブルへの追加、およびテーブルからの削除が可能です。これらのタスクを実行するための MySQL ステートメントに関する基本情報については、セクション13.1.7「ALTER TABLE 構文」を参照してください。より詳細な説明および例については、セクション19.3「パーティション管理」を参照してください。

重要

元の CREATE TABLE ステートメント (すべての指定およびテーブルオプションを含む) は、そのテーブルが作成されるときに MySQL によって格納されます。この情報が保持されるのは、ALTER TABLE ステートメントを使用してストレージエンジン、照合順序、またはその他の設定を変更した場合に、指定された元のテーブルオプションが保持されるようにするためです。これにより、2 つのエンジンによってサポートされる行フォーマットが異なっていても、InnoDBMyISAM のテーブルタイプ間での変更が可能になります。

元のステートメントのテキストは保持されますが、特定の値やオプション (ROW_FORMAT など) が暗黙のうちに再構成される可能性があるため、アクティブなテーブル定義 (DESCRIBE または SHOW TABLE STATUS によってアクセス可能) やテーブル作成文字列 (SHOW CREATE TABLE によってアクセス可能) は異なる値をレポートします。

テーブルのクローニングまたはコピー

CREATE TABLE ステートメントの最後に SELECT ステートメントを追加することによって、あるテーブルを別のテーブルから作成できます。

CREATE TABLE new_tbl SELECT * FROM orig_tbl;

詳細は、セクション13.1.17.1「CREATE TABLE ... SELECT 構文」を参照してください。

別のテーブルの定義 (元のテーブルで定義されているすべてのカラム属性やインデックスを含む) に基づいて空のテーブルを作成するには、LIKE を使用します。

CREATE TABLE new_tbl LIKE orig_tbl;

このコピーは、元のテーブルと同じバージョンのテーブルストレージフォーマットを使用して作成されます。元のテーブルに対する SELECT 権限が必要です。

LIKE は、ビューに対してではなく、ベーステーブルに対してのみ機能します。

重要

MySQL 5.6.1 から、LOCK TABLES ステートメントが有効になっている間は CREATE TABLE または CREATE TABLE ... LIKE を実行できません。

また MySQL 5.6.1 の時点では、CREATE TABLE ... LIKECREATE TABLE と同じチェックを行い、単に .frm ファイルをコピーするだけではありません。つまり、現在の SQL モードが、元のテーブルが作成されたときの有効なモードとは異なっている場合、テーブル定義が新しいモードでは無効と見なされる可能性があり、ステートメントは失敗します。

CREATE TABLE ... LIKE は、元のテーブルや、すべての外部キー定義に対して指定されたどの DATA DIRECTORY または INDEX DIRECTORY テーブルオプションも保持しません。

元のテーブルが TEMPORARY テーブルである場合、CREATE TABLE ... LIKETEMPORARY を保持しません。TEMPORARY 宛先テーブルを作成するには、CREATE TEMPORARY TABLE ... LIKE を使用します。

13.1.17.1 CREATE TABLE ... SELECT 構文

CREATE TABLE ステートメントの最後に SELECT ステートメントを追加することによって、あるテーブルを別のテーブルから作成できます。

CREATE TABLE new_tbl [AS] SELECT * FROM orig_tbl;

MySQL は、SELECT 内のすべての要素に対して新しいカラムを作成します。例:

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

これにより、abc の 3 つのカラムを含む MyISAM テーブルが作成されます。ENGINE オプションは CREATE TABLE ステートメントの一部であるため、SELECT のあとに使用してはいけません。これにより、構文エラーが発生します。CHARSET などのその他の CREATE TABLE オプションにも同じことが当てはまります。

SELECT ステートメントからのカラムは、テーブルにオーバーラップされるのではなく、テーブルの右側に付加されます。次の例を考えてみます。

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)

テーブル foo 内の行ごとに、foo からの値と新しいカラムのデフォルト値を持つ行が bar 内に挿入されます。

CREATE TABLE ... SELECT の結果として得られるテーブルでは、CREATE TABLE 部分でのみ指定されているカラムが最初に来ます。両方の部分で指定されているカラム、または SELECT 部分でのみ指定されているカラムがそのあとに来ます。SELECT カラムのデータ型は、CREATE TABLE 部分にあるカラムも指定することによってオーバーライドできます。

テーブルへのデータのコピー中にエラーが発生した場合、そのデータは自動的に削除され、作成されません。

一意のキー値を複製する行を処理する方法を示すために、SELECT の前に IGNORE または REPLACE を指定できます。IGNORE を指定すると、一意のキー値に関して既存の行を複製する行は破棄されます。REPLACE を指定すると、新しい行によって同じ一意のキー値を持つ行が置き換えられます。IGNOREREPLACE のどちらも指定されていない場合は、重複した一意のキー値によってエラーが発生します。

ベースとなる SELECT ステートメント内の行の順序を常に特定することはできないため、MySQL 5.6.4 以降では、CREATE TABLE ... IGNORE SELECT および CREATE TABLE ... REPLACE SELECT ステートメントには、ステートメントベースのレプリケーションには安全でないというフラグが付けられます。この変更により、このようなステートメントは、ステートメントベースモードを使用しているときはログ内に警告を生成し、MIXED モードを使用しているときは行ベース形式を使用してログに記録されます。セクション17.1.2.1「ステートメントベースおよび行ベースレプリケーションのメリットとデメリット」も参照してください。

CREATE TABLE ... SELECT は、どのインデックスも自動的には作成しません。これは、ステートメントをできるだけ柔軟にするために意図的に行われます。作成されたテーブル内にインデックスを設定する場合は、これらを SELECT ステートメントの前に指定するようにしてください。

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

何らかのデータ型の変換が実行される可能性があります。たとえば、AUTO_INCREMENT 属性が保持されないため、VARCHAR カラムは CHAR カラムになることができます。リトレインされる属性は NULL (または NOT NULL) と、それらを含むカラムの場合は、CHARACTER SETCOLLATIONCOMMENT、および DEFAULT 句です。

CREATE TABLE ... SELECT を使用してテーブルを作成する場合は、クエリー内のすべての関数呼び出しまたは式にエイリアスを付けるようにしてください。そうしないと、CREATE ステートメントが失敗するか、または好ましくないカラム名が生成される可能性があります。

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;

また、生成されるカラムのデータ型を明示的に指定することもできます。

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

CREATE TABLE ... SELECT で、IF NOT EXISTS が指定されているときに宛先テーブルがすでに存在する場合、その結果はバージョンに依存します。MySQL 5.5.6 より前は、MySQL はこのステートメントを次のように処理します。

  • CREATE TABLE 部分で指定されているテーブル定義は無視されます。その定義が既存のテーブルの定義に一致しない場合でも、エラーは発生しません。MySQL は、いずれにしても SELECT 部分から行を挿入しようとします。

  • テーブル内のカラム数と、SELECT 部分によって生成されたカラム数の間に不一致がある場合、選択された値は右端のカラムに割り当てられます。たとえば、テーブルに n 個のカラムが含まれているとき、SELECT によって m 個のカラムが生成される場合 (ここで、m < n)、選択された値はテーブル内の右端の m 個のカラムに割り当てられます。最初の n - m 個の各カラムにはデフォルト値が割り当てられます。このデフォルト値は、カラム定義で明示的に、またはその定義にデフォルトが含まれていない場合は暗黙的なカラムデータ型のデフォルトで指定されます。SELECT 部分によって生成されるカラムが多すぎる場合は (m > n)、エラーが発生します。

  • 厳密な SQL モードが有効になっており、かつこれらの最初のカラムのいずれにも明示的なデフォルト値が含まれていない場合、このステートメントはエラーで失敗します。

次の例は、IF NOT EXISTS の処理を示しています。

mysql> CREATE TABLE t1 (i1 INT DEFAULT 0, i2 INT, i3 INT, i4 INT);Query OK, 0 rows affected (0.05 sec)
mysql> CREATE TABLE IF NOT EXISTS t1 (c1 CHAR(10)) SELECT 1, 2;Query OK, 1 row affected, 1 warning (0.01 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> SELECT * FROM t1;+------+------+------+------+
| i1 | i2 | i3 | i4 |
+------+------+------+------+
| 0 | NULL | 1 | 2 |
+------+------+------+------+
1 row in set (0.00 sec)

MySQL 5.5.6 の時点で、CREATE TABLE IF NOT EXISTS ... SELECT ステートメントの処理は、宛先テーブルがすでに存在するケースに関して変更されました。また、この変更には 5.1.51 以降の MySQL 5.1 での変更も含まれています。

  • 以前は、CREATE TABLE IF NOT EXISTS ... SELECT の場合、MySQL はテーブルが存在するという警告を生成しましたが、いずれにしてもそれらの行を挿入し、そのステートメントをバイナリログに書き込みました。これに対して、CREATE TABLE ... SELECT (IF NOT EXISTS がありません) はエラーで失敗しましたが、MySQL は行を挿入せず、バイナリログにもステートメントを書き込みませんでした。

  • MySQL は現在、宛先テーブルが存在する場合、両方のステートメントを同じ方法で処理します。つまり、どちらのステートメントも行を挿入せず、またバイナリログにも書き込まれません。これらの違いは、IF NOT EXISTS が存在する場合は MySQL が警告を生成し、存在しない場合はエラーを生成することです。

この変更は、前の例で言うと、MySQL 5.5.6 の時点では CREATE TABLE IF NOT EXISTS ... SELECT ステートメントが宛先テーブルに何も挿入しないことを示します。

この IF NOT EXISTS の処理の変更により、元の動作を行う MySQL 5.1 マスターから、新しい動作を行う MySQL 5.5 スレーブへのステートメントベースのレプリケーションで非互換性が発生します。CREATE TABLE IF NOT EXISTS ... SELECT がマスター上で実行されたときに、宛先テーブルが存在しているとします。その結果、マスター上では行が挿入されますが、スレーブ上では挿入されません。(行ベースのレプリケーションにはこの問題はありません。)

この問題に対処するために、MySQL 5.1 では、CREATE TABLE IF NOT EXISTS ... SELECT に対するステートメントベースのバイナリロギングが 5.1.51 の時点で変更されました。

  • 宛先テーブルが存在しない場合は、変更ありません。ステートメントはそのままログに記録されます。

  • 宛先テーブルが存在しない場合、ステートメントは CREATE TABLE IF NOT EXISTS および INSERT ... SELECT ステートメントの同等のペアとしてログに記録されます。(元のステートメント内の SELECT の前に IGNORE または REPLACE が指定されている場合は、INSERT がそれぞれ、INSERT IGNORE または REPLACE になります。)

この変更により、宛先テーブルが存在する場合はマスターとスレーブの両方で行が挿入されるため、MySQL 5.1 から 5.5 へのステートメントベースのレプリケーションでの上位互換性が提供されます。この互換性対策を利用するには、5.1 サーバーは少なくとも 5.1.51 である必要があり、5.5 サーバーは少なくとも 5.5.6 である必要があります。

既存の 5.1 から 5.5 へのレプリケーションシナリオをアップグレードするには、最初にマスターを 5.1.51 以降にアップグレードします。これは、最初にスレーブをアップグレードするという、通常のレプリケーションアップグレードのアドバイスとは異なります。

元の効果 (宛先テーブルが存在するかどうかには関係なく行が挿入される) を実現したいアプリケーションには、CREATE TABLE IF NOT EXISTS ... SELECT ステートメントではなく、CREATE TABLE IF NOT EXISTS および INSERT ... SELECT ステートメントを使用するという回避方法があります。

今説明した変更とともに、次の関連する変更が行われました。以前は、CREATE TABLE IF NOT EXISTS ... SELECT の宛先テーブルとして既存のビューが指定された場合、基礎となるベーステーブルに行が挿入され、このステートメントがバイナリログに書き込まれました。MySQL 5.1.51 および 5.5.6 の時点では、何も挿入されたり、ログに記録されたりしません。

バイナリログを使用して元のテーブルを確実に再作成できるようにするために、MySQL では、CREATE TABLE ... SELECT 中の並列挿入が許可されません。

重要

CREATE TABLE new_table SELECT ... FROM old_table ... などのステートメントで SELECT の一部として FOR UPDATE を使用することはできません。それを行おうとすると、このステートメントは失敗します。これは、CREATE TABLE ... SELECT ステートメントが作成されているテーブル以外のテーブルで変更を行うことを許可していた、MySQL 5.5 およびそれ以前からの動作の変更を表しています。

この変更はまた、古いマスターから MySQL 5.6 以降のスレーブへのステートメントベースのレプリケーションにも影響を与える場合があります。詳細は、セクション17.4.1.5「CREATE TABLE ... SELECT ステートメントのレプリケーション」を参照してください。

13.1.17.2 外部キー制約の使用

MySQL は、関連データのテーブルにまたがる相互参照を可能にする外部キーと、この分散したデータの整合性を維持するために役立つ外部キー制約をサポートします。CREATE TABLE または ALTER TABLE ステートメントで外部キー制約を定義するための基本的な構文は次のようになります。

[CONSTRAINT [symbol]] FOREIGN KEY [index_name] (index_col_name, ...) REFERENCES tbl_name (index_col_name,...) [ON DELETE reference_option] [ON UPDATE reference_option]reference_option: RESTRICT | CASCADE | SET NULL | NO ACTION

index_name は、外部キー ID を表します。外部キーをサポートできる子テーブル上に明示的に定義されたインデックスがすでに存在する場合、index_name 値は無視されます。それ以外の場合、MySQL は、次のルールに従って名前が付けられた外部キーのインデックスを暗黙的に作成します。

  • 定義されている場合は、CONSTRAINTsymbol 値が使用されます。それ以外の場合は、FOREIGN KEYindex_name 値が使用されます。

  • CONSTRAINTsymbolFOREIGN KEYindex_name のどちらも定義されていない場合、外部キーのインデックス名は、参照している外部キーカラムの名前を使用して生成されます。

外部キー定義は、次の条件に従います。

  • 外部キー関係には、中央のデータ値を保持している親テーブルと、その元の親を指す同一の値を持っている子テーブルが含まれます。FOREIGN KEY 句は、子テーブルで指定されます。親テーブルと子テーブルは、同じストレージエンジンを使用する必要があります。これらは、TEMPORARY テーブルであってはいけません。

  • 外部キー内の対応するカラムと、参照されるキーは同様のデータ型を持っている必要があります。整数型のサイズと符号が同じである必要があります。文字列型の長さが同じである必要はありません。バイナリ以外の (文字の) 文字列カラムの場合、文字セットと照合順序が同じである必要があります。

  • MySQL では、外部キーチェックを高速に実行でき、かつテーブルスキャンが必要なくなるように、外部キーおよび参照されるキーに関するインデックスが必要です。参照しているテーブルには、外部キーカラムが同じ順序で最初のカラムとしてリストされているインデックスが存在する必要があります。このようなインデックスが存在しない場合は、参照しているテーブル上に自動的に作成されます。このインデックスは、外部キー制約を適用するために使用できる別のインデックスを作成した場合、あとで暗黙のうちに削除される可能性があります。index_name (指定されている場合) は、前に説明したとおりに使用されます。

  • InnoDB では、外部キーが任意のインデックスカラムまたはカラムのグループを参照することが許可されます。ただし、参照されるテーブルには、参照されるカラムが同じ順序で最初のカラムとして一覧表示されているインデックスが存在する必要があります。

    NDB には、外部キーとして参照されるいずれかのカラム上の明示的な一意のキー (または主キー) が必要です。

  • 外部キーカラム上のインデックスプリフィクスはサポートされていません。この 1 つの影響として、BLOB および TEXT カラム上のインデックスには常にプリフィクス長が含まれている必要があるため、それらのカラムを外部キーに含めることができない点があります。

  • CONSTRAINT symbol 句が指定されている場合、symbol 値 (使用されている場合) はデータベース内で一意である必要があります。symbol が重複している場合は、次のようなエラーが発生します: ERROR 1022 (2300): 書き込めません。テーブル '#sql- 464_1' に重複するキーがあります'。この句が指定されていない場合や、CONSTRAINT キーワードのあとに symbol が含まれていない場合は、制約の名前が自動的に作成されます。

  • 現在、InnoDB ではユーザー定義のパーティションを持つテーブルの外部キーがサポートされていません。これには、親テーブルと子テーブルの両方が含まれます。

    この制限は、KEY または LINEAR KEY によってパーティション化された NDB テーブル (NDB ストレージエンジンによってサポートされる唯一のユーザーパーティショニングタイプ) には適用されません。これらは外部キー参照を含むか、またはこのような参照のターゲットになることができます。

  • NDB テーブルでは、参照先が親テーブルの主キーである場合、ON UPDATE CASCADE はサポートされません。

参照アクション

このセクションでは、外部キーが参照整合性の保証にどのように役立つかについて説明します。

外部キーをサポートするストレージエンジンで、親テーブル内に一致する候補のキー値が存在しない場合、MySQL は、子テーブル内に外部キー値を作成しようとするすべての INSERT または UPDATE 操作を拒否します。

UPDATE または DELETE 操作が、子テーブル内に一致する行を持つ親テーブル内のキー値に影響を与える場合、その結果は、FOREIGN KEY 句の ON UPDATE および ON DELETE サブ句を使用して指定された参照アクションによって異なります。MySQL は、実行されるアクションに関連した次の 5 つのオプションをサポートしています。

  • CASCADE: 親テーブルの行を削除または更新し、子テーブル内の一致する行を自動的に削除または更新します。ON DELETE CASCADEON UPDATE CASCADE の両方がサポートされています。2 つのテーブル間で、親テーブルまたは子テーブル内の同じカラムに対して機能する複数の ON UPDATE CASCADE 句を定義しないでください。

    注記

    現在、カスケードされた外部キーのアクションではトリガーがアクティブになっていません。

  • SET NULL: 親テーブルの行を削除または更新し、子テーブル内の 1 つまたは複数の外部キーカラムを NULL に設定します。ON DELETE SET NULL 句と ON UPDATE SET NULL 句の両方がサポートされています。

    SET NULL アクションを指定する場合は、子テーブル内のカラムを NOT NULL として宣言していないことを確認してください

  • RESTRICT: 親テーブルに対する削除または更新操作を拒否します。RESTRICT (または NO ACTION) を指定することは、ON DELETE または ON UPDATE 句を省略することと同じです。

  • NO ACTION: 標準 SQL のキーワード。MySQL では、RESTRICT と同等です。MySQL Server は、参照されるテーブル内に関連する外部キー値が存在する場合、親テーブルに対する削除または更新操作を拒否します。一部のデータベースシステムは遅延チェックを備えており、その場合、NO ACTION は遅延チェックです。MySQL では、外部キー制約はただちにチェックされるため、NO ACTIONRESTRICT と同じです。

  • SET DEFAULT: このアクションは MySQL パーサーによって認識されますが、InnoDBNDB はどちらも、ON DELETE SET DEFAULT または ON UPDATE SET DEFAULT 句を含むテーブル定義を拒否します。

指定されていない ON DELETE または ON UPDATE では、デフォルトのアクションは常に RESTRICT です。

MySQL は、1 つのテーブル内のあるカラムと別のカラムの間の外部キー参照をサポートしています。(あるカラムが、それ自体への外部キー参照を持つことはできません。)これらの場合、子テーブルのレコードは、実際に同じテーブル内の依存レコードを参照します。

外部キー句の例

単一カラム外部キーを使用して parent および child テーブルを関連付ける単純な例を次に示します。

CREATE TABLE parent ( id INT NOT NULL, PRIMARY KEY (id)
) ENGINE=INNODB;
CREATE TABLE child ( id INT, parent_id INT, INDEX par_ind (parent_id), FOREIGN KEY (parent_id) REFERENCES parent(id) ON DELETE CASCADE
) ENGINE=INNODB;

product_order テーブルにほかの 2 つのテーブルへの外部キーが存在する、より複雑な例。1 つの外部キーが、product テーブル内の 2 カラムのインデックスを参照しています。もう一方の外部キーは、customer テーブル内の単一カラムインデックスを参照しています。

CREATE TABLE product ( category INT NOT NULL, id INT NOT NULL, price DECIMAL, PRIMARY KEY(category, id)
) ENGINE=INNODB;
CREATE TABLE customer ( id INT NOT NULL, PRIMARY KEY (id)
) ENGINE=INNODB;
CREATE TABLE product_order ( no INT NOT NULL AUTO_INCREMENT, product_category INT NOT NULL, product_id INT NOT NULL, customer_id INT NOT NULL, PRIMARY KEY(no), INDEX (product_category, product_id), INDEX (customer_id), FOREIGN KEY (product_category, product_id) REFERENCES product(category, id) ON UPDATE CASCADE ON DELETE RESTRICT, FOREIGN KEY (customer_id) REFERENCES customer(id)
) ENGINE=INNODB;
外部キーの追加

ALTER TABLE を使用して、既存のテーブルに新しい外部キー制約を追加できます。このステートメントの外部キーに関連した構文を次に示します。

ALTER TABLE tbl_name ADD [CONSTRAINT [symbol]] FOREIGN KEY [index_name] (index_col_name, ...) REFERENCES tbl_name (index_col_name,...) [ON DELETE reference_option] [ON UPDATE reference_option]

外部キーは、自己参照型にする (同じテーブルを参照する) ことができます。ALTER TABLE を使用してテーブルに外部キー制約を追加する場合は、まず必要なインデックスを作成することを忘れないでください。

外部キーの削除

次に示す構文を使用して、ALTER TABLE で外部キーを削除することもできます。

ALTER TABLE tbl_name DROP FOREIGN KEY fk_symbol;

外部キーを作成したときに FOREIGN KEY 句に CONSTRAINT の名前が含まれていた場合は、その名前を参照して外部キーを削除できます。それ以外の場合は、外部キーが作成されるときに fk_symbol 値が内部的に生成されます。外部キーを削除するときにシンボル値を見つけるには、次に示すように、SHOW CREATE TABLE ステートメントを使用します。

mysql> SHOW CREATE TABLE ibtest11c\G*************************** 1. row *************************** Table: ibtest11c
Create Table: CREATE TABLE `ibtest11c` ( `A` int(11) NOT NULL auto_increment, `D` int(11) NOT NULL default '0', `B` varchar(200) NOT NULL default '', `C` varchar(175) default NULL, PRIMARY KEY (`A`,`D`,`B`), KEY `B` (`B`,`C`), KEY `C` (`C`), CONSTRAINT `0_38775` FOREIGN KEY (`A`, `D`)
REFERENCES `ibtest11a` (`A`, `D`)
ON DELETE CASCADE ON UPDATE CASCADE, CONSTRAINT `0_38776` FOREIGN KEY (`B`, `C`)
REFERENCES `ibtest11a` (`B`, `C`)
ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=INNODB CHARSET=latin1
1 row in set (0.01 sec)
mysql> ALTER TABLE ibtest11c DROP FOREIGN KEY `0_38775`;

MySQL 5.6.6 より前は、同じ ALTER TABLE ステートメントでの外部キーの追加と削除は、問題が発生する場合があるためサポートされていません。操作ごとに個別のステートメントを使用するようにしてください。MySQL 5.6.6 の時点では、同じ ALTER TABLE ステートメントでの外部キーの追加と削除は ALTER TABLE ... ALGORITHM=INPLACE ではサポートされますが、ALTER TABLE ... ALGORITHM=COPY では未サポートのままです。

MySQL 5.6.7 より前は、ALTER TABLE を使用して外部キーカラムの定義を変更すると、参照整合性が失われる可能性がありました。たとえば、NULL 値を含む外部キーカラムを NOT NULL になるように変更すると、NULL 値が空の文字列になりました。同様に、親テーブル内の行を削除する ALTER TABLE IGNORE によって、参照整合性が破壊される可能性がありました。

5.6.7 の時点では、参照整合性が失われる可能性のある外部キーカラムへの変更がサーバーによって禁止されます。回避方法として、カラム定義を変更する前に ALTER TABLE ... DROP FOREIGN KEY を使用し、あとで ALTER TABLE ... ADD FOREIGN KEY を使用します。

外部キーおよびその他の MySQL ステートメント

FOREIGN KEY ... REFERENCES ... 句内のテーブルとカラムの識別子は、逆引用符 (`) で囲むことができます。あるいは、ANSI_QUOTES SQL モードが有効になっている場合は、二重引用符 (") を使用できます。また、lower_case_table_names システム変数の設定も考慮に入れられます。

SHOW CREATE TABLE ステートメントの出力の一部として、子テーブルの外部キー定義を表示できます。

SHOW CREATE TABLE tbl_name;

INFORMATION_SCHEMA.KEY_COLUMN_USAGE テーブルをクエリーすることによって、外部キーに関する情報を取得することもできます。

INNODB_SYS_FOREIGN および INNODB_SYS_FOREIGN_COLS テーブル、さらには INFORMATION_SCHEMA データベース内の InnoDB テーブルによって使用される外部キーに関する情報を検索できます。

mysqldump は、テーブルの正しい定義 (子テーブルへの外部キーを含む) をダンプファイル内に生成します。

外部キー関係を持つテーブルのダンプファイルのリロードを容易にするために、mysqldump は、foreign_key_checks を 0 に設定するステートメントをダンプ出力内に自動的に含めます。これにより、ダンプがリロードされるときに特定の順序でリロードする必要のあるテーブルに関する問題が回避されます。また、この変数を手動で設定することもできます。

mysql> SET foreign_key_checks = 0;mysql> SOURCE dump_file_name;mysql> SET foreign_key_checks = 1;

これにより、外部キーに関して正しく順序付けられていないテーブルがダンプファイルに含まれている場合でも、そのテーブルを任意の順序でインポートできます。また、インポート操作も高速化されます。foreign_key_checks を 0 に設定することは、LOAD DATA および ALTER TABLE 操作中に外部キー制約を無視するためにも役立つ場合があります。ただし、foreign_key_checks = 0 の場合でも、MySQL では、カラムが一致しないカラム型を参照している外部キー制約の作成は許可されません。また、テーブルに外部キー制約が存在する場合は、ALTER TABLE を使用して、そのテーブルを別のストレージエンジンを使用するように変更することはできません。ストレージエンジンを変更するには、まず外部キー制約をすべて削除する必要があります。

SET foreign_key_checks = 0 を実行しないかぎり、FOREIGN KEY 制約によって参照されるテーブルに対して DROP TABLE を発行できません。テーブルを削除すると、そのテーブルを作成するために使用されたステートメントで定義されていた制約もすべて削除されます。

削除されたテーブルを再作成する場合は、そのテーブルに、それを参照している外部キー制約に準拠する定義が存在する必要があります。また、カラムの正しい名前と型、および前に説明した参照されるキーに関するインデックスが存在する必要があります。これらが満たされていない場合、MySQL はエラー 1005 を返し、エラーメッセージでエラー 150 を示します。これは、外部キー制約が正しく形成されなかったことを示します。同様に、ALTER TABLE がエラー 150 で失敗した場合、これは、変更されたテーブルのために外部キー定義が誤って形成されることを示します。

InnoDB テーブルの場合は、SHOW ENGINE INNODB STATUS の出力をチェックすることによって、MySQL Server で最新の InnoDB 外部キーエラーの詳細な説明を取得できます。

重要

ANSI/ISO SQL 標準に精通しているユーザーの場合は、参照整合性の制約定義で使用される MATCH 句を認識または適用するストレージエンジンは (InnoDB を含め) 存在しません。明示的な MATCH 句を使用しても、指定された効果が得られないだけでなく、ON DELETE および ON UPDATE 句が無視される原因にもなります。これらの理由により、MATCH の指定は避けるようにしてください。

SQL 標準での MATCH 句は、複合 (マルチカラム) 外部キー内の NULL 値が、主キーとの比較時にどのように処理されるかを制御します。MySQL は基本的に、外部キーをすべてまたは部分的に NULL にすることが許可される、MATCH SIMPLE で定義されるセマンティクスを実装しています。その場合は、このような外部キーを含む (子テーブルの) 行の挿入が許可され、その行は参照される (親) テーブル内のどの行にも一致しません。トリガーを使用して、ほかのセマンティクスを実装できます。

さらに、MySQL ではパフォーマンス上の理由から、参照されるカラムにインデックスを設定する必要があります。ただし、システムでは、参照されるカラムを UNIQUE にするか、または NOT NULL として宣言するという要件は適用されません。一意でないキーまたは NULL 値を含むキーへの外部キー参照の処理は、UPDATEDELETE CASCADE などの操作に対して適切に定義されていません。UNIQUE (PRIMARY を含む) および NOT NULL キーのみを参照する外部キーを使用することをお勧めします。

さらに、MySQL は、参照がカラム指定の一部として定義されている (SQL 標準で定義された) インラインの REFERENCES 指定を認識せず、またサポートもしていません。MySQL は、個別の FOREIGN KEY 指定の一部として指定されている場合にのみ REFERENCES 句を受け入れます。外部キーをサポートしていない (MyISAM などの) ストレージエンジンの場合、MySQL Server は、外部キーの指定を解析して無視します。

13.1.17.3 暗黙のカラム指定の変更

MySQL は場合によって、カラム指定を CREATE TABLE または ALTER TABLE ステートメントで指定されたものから暗黙のうちに変更することがあります。これらの変更は、データ型、データ型に関連付けられた属性、またはインデックス指定に対して行われる可能性があります。

すべての変更は 65,535 バイトの内部の行サイズ制限に従うため、データ型を変更しようとする一部の試みが失敗する可能性があります。セクションD.10.4「テーブルカラム数と行サイズの制限」を参照してください。

  • PRIMARY KEY の一部であるカラムは、そのように宣言されていない場合でも、NOT NULL にされます。

  • テーブルが作成されたとき、ENUM および SET メンバー値から末尾のスペースが自動的に削除されます。

  • MySQL は、ほかの SQL データベースベンダーによって使用されている特定のデータ型を MySQL 型にマップします。セクション11.9「その他のデータベースエンジンのデータ型の使用」を参照してください。

  • 特定のストレージエンジンには許可されないインデックスタイプを指定するために USING 句を含めたが、そのエンジンがクエリー結果に影響を与えることなく使用できる使用可能な別のインデックスタイプが存在する場合、エンジンはその使用可能なタイプを使用します。

  • 厳密な SQL モードが有効になっていない場合、長さ指定が 65535 より大きい VARCHAR カラムは TEXT に変換され、長さ指定が 65535 より大きい VARBINARY カラムは BLOB に変換されます。そうでない場合は、これらのいずれの場合にもエラーが発生します。

  • 文字データ型に CHARACTER SET binary 属性を指定すると、カラムは対応するバイナリデータ型として作成されます。つまり、CHARBINARY になり、VARCHARVARBINARY になり、TEXTBLOB になります。ENUM および SET データ型では、これは行われず、宣言されたとおりに作成されます。この定義を使用して、テーブルを指定したとします。

    CREATE TABLE t
    ( c1 VARCHAR(10) CHARACTER SET binary, c2 TEXT CHARACTER SET binary, c3 ENUM('a','b','c') CHARACTER SET binary
    );

    結果のテーブルには、この定義が含まれています。

    CREATE TABLE t
    ( c1 VARBINARY(10), c2 BLOB, c3 ENUM('a','b','c') CHARACTER SET binary
    );

MySQL が、指定したもの以外のデータ型を使用したかどうかを確認するには、テーブルを作成または変更したあとに、DESCRIBE または SHOW CREATE TABLE ステートメントを発行します。

myisampack を使用してテーブルを圧縮する場合は、その他の特定のデータ型の変更が発生する場合があります。セクション15.2.3.3「圧縮テーブルの特徴」を参照してください。

13.1.18 CREATE TABLESPACE 構文

CREATE TABLESPACE tablespace_name ADD DATAFILE 'file_name' USE LOGFILE GROUP logfile_group [EXTENT_SIZE [=] extent_size] [INITIAL_SIZE [=] initial_size] [AUTOEXTEND_SIZE [=] autoextend_size] [MAX_SIZE [=] max_size] [NODEGROUP [=] nodegroup_id] [WAIT] [COMMENT [=] comment_text] ENGINE [=] engine_name

このステートメントは、テーブルスペースを作成するために使用されます。テーブルスペースは 1 つ以上のデータファイルを含むことができ、テーブルのストレージ領域を提供します。このステートメントを使用して 1 つのデータファイルが作成され、テーブルスペースに追加されます。ALTER TABLESPACE ステートメントを使用して、テーブルスペースにデータファイルを追加できます (セクション13.1.8「ALTER TABLESPACE 構文」を参照してください)。テーブルスペースの命名を管理するルールについては、セクション9.2「スキーマオブジェクト名」を参照してください。

注記

すべての MySQL Cluster ディスクデータオブジェクトが同じ名前空間を共有します。つまり、各ディスクデータオブジェクトは (単に、特定の型の各ディスクデータオブジェクトというだけでなく)、一意の名前が付けられている必要があります。たとえば、テーブルスペースとログファイルグループを同じ名前にしたり、テーブルスペースとデータファイルを同じ名前にしたりすることはできません。

作成されるテーブルスペースには、USE LOGFILE GROUP 句を使用して、1 つ以上の UNDO ログファイルのログファイルグループを割り当てる必要があります。logfile_group は、CREATE LOGFILE GROUP で作成された既存のログファイルグループである必要があります (セクション13.1.14「CREATE LOGFILE GROUP 構文」を参照してください)。複数のテーブルスペースが UNDO ロギングのために同じログファイルグループを使用できます。

EXTENT_SIZE は、そのテーブルスペースに属するすべてのファイルによって使用されるエクステントのサイズ (バイト単位) を設定します。デフォルト値は 1M です。最小サイズは 32K であり、理論的な最大サイズは 2G です。ただし、実際的な最大サイズはいくつかの要因によって異なります。ほとんどの場合は、エクステントサイズを変更してもパフォーマンスに測定可能な影響を与えることはないため、特別な状況を除き、常にデフォルト値を使用することをお勧めします。

エクステントは、ディスク領域の割り当ての単位です。1 つのエクステントが、そのエクステントに収容できる量のデータでいっぱいになってから、別のエクステントが使用されます。理論上は、データファイルあたり最大 65,535 (64K) 個のエクステントを使用できます。ただし、推奨される最大数は 32,768 (32K) です。1 つのデータファイルの推奨される最大サイズは 32G (つまり、32K 個のエクステント × エクステントあたり 1M バイト) です。さらに、エクステントを特定のパーティションに割り当てたあと、そのエクステントを使用して別のパーティションのデータを格納することはできません。エクステントには、複数のパーティションのデータを格納できません。つまり、たとえば、INITIAL_SIZE が 256M バイトで、EXTENT_SIZE が 128M である 1 つのデータファイルを含むテーブルスペースにはエクステントが 2 つしか存在しないため、このテーブルスペースを使用して最大 2 つの異なるディスクデータテーブルパーティションのデータを格納できます。

INFORMATION_SCHEMA.FILES テーブルをクエリーすることによって、特定のデータファイルに未使用のまま残っているエクステントの数を確認できるため、ファイル内の空き容量の概算値を導き出すことができます。それ以上の説明および例については、セクション21.30.1「INFORMATION_SCHEMA FILES テーブル」を参照してください。

INITIAL_SIZE パラメータは、データファイルの合計サイズをバイト単位で設定します。ファイルが作成されたあと、そのサイズを変更することはできません。ただし、ALTER TABLESPACE ... ADD DATAFILE を使用して、テーブルスペースにさらに多くのデータファイルを追加できます。セクション13.1.8「ALTER TABLESPACE 構文」を参照してください。

INITIAL_SIZE はオプションです。そのデフォルト値は 134217728 (128M バイト) です。

32 ビットシステム上では、INITIAL_SIZE のサポートされる最大値は 4294967296 (4G バイト) です。(Bug #29186)

EXTENT_SIZE を設定する場合は、数値のあとにオプションで、my.cnf で使用されるのと同様の、桁を示す 1 文字の略語を指定できます。一般に、これは M (M バイト) または G (G バイト) のどちらかの文字です。MySQL Cluster NDB 7.3.2 以降では、これらの略語は INITIAL_SIZE を指定する場合もサポートされます。(Bug #13116514、Bug #16104705、Bug #62858)

INITIAL_SIZEEXTENT_SIZE、および UNDO_BUFFER_SIZE は、次のような丸めに従います。

  • EXTENT_SIZEUNDO_BUFFER_SIZE はそれぞれ、32K のもっとも近い整数倍に切り上げられます。

  • INITIAL_SIZE は、32K のもっとも近い整数倍に切り下げられます。

    データファイルの場合は、INITIAL_SIZE に対してさらに丸め処理が行われます。今得られた結果が (すべての丸めのあと) EXTENT_SIZE のもっとも近い整数倍に切り上げられます。

今説明した丸めは明示的に実行され、このような丸めのいずれかが実行された場合は MySQL Server によって警告が発行されます。丸められた値はまた、INFORMATION_SCHEMA.FILES カラム値の計算やその他の目的のために、NDB カーネルでも使用されます。ただし、予期しない結果が発生しないようにするために、これらのオプションの指定では常に 32K の整数倍を使用することをお勧めします。

AUTOEXTEND_SIZEMAX_SIZENODEGROUPWAIT、および COMMENT は解析されますが、無視されるため、現在は何の効果もありません。これらのオプションは、将来の拡張のために用意されています。

ENGINE パラメータは、このテーブルスペースが使用するストレージエンジンを決定します。ここで、engine_name はそのストレージエンジンの名前です。現在、engine_name は、値 NDB または NDBCLUSTER のいずれかである必要があります。

CREATE TABLESPACEENGINE = NDB とともに使用された場合は、テーブルスペースとそれに関連付けられたデータファイルが各クラスタデータノード上に作成されます。INFORMATION_SCHEMA.FILES テーブルをクエリーすることによって、データファイルが作成されたことを確認したり、それらに関する情報を取得したりできます。例:

mysql> SELECT LOGFILE_GROUP_NAME, FILE_NAME, EXTRA -> FROM INFORMATION_SCHEMA.FILES -> WHERE TABLESPACE_NAME = 'newts' AND FILE_TYPE = 'DATAFILE';+--------------------+-------------+----------------+
| LOGFILE_GROUP_NAME | FILE_NAME | EXTRA |
+--------------------+-------------+----------------+
| lg_3 | newdata.dat | CLUSTER_NODE=3 |
| lg_3 | newdata.dat | CLUSTER_NODE=4 |
+--------------------+-------------+----------------+
2 rows in set (0.01 sec)

(セクション21.30.1「INFORMATION_SCHEMA FILES テーブル」を参照してください。)

CREATE TABLESPACE は、MySQL Cluster のディスクデータストレージでのみ有効です。セクション18.5.12「MySQL Cluster ディスクデータテーブル」を参照してください。

13.1.19 CREATE TRIGGER 構文

CREATE [DEFINER = { user | CURRENT_USER }] TRIGGER trigger_nametrigger_timetrigger_event ON tbl_name FOR EACH ROW trigger_bodytrigger_time: { BEFORE | AFTER }trigger_event: { INSERT | UPDATE | DELETE }

このステートメントは、新しいトリガーを作成します。トリガーとは、テーブルに関連付けられ、そのテーブルに対して特定のイベントが発生するとアクティブ化される名前付きデータベースオブジェクトのことです。トリガーは、tbl_name という名前のテーブルに関連付けられます。これは、永続的なテーブルを指す必要があります。トリガーを TEMPORARY テーブルまたはビューに関連付けることはできません。

トリガー名はスキーマの名前空間内に存在します。つまり、すべてのトリガーがスキーマ内で一意の名前を持つ必要があります。異なるスキーマ内のトリガーは同じ名前を持つことができます。

このセクションでは、CREATE TRIGGER 構文について説明します。詳細は、セクション20.3.1「トリガーの構文と例」を参照してください。

CREATE TRIGGER には、このトリガーに関連付けられたテーブルに対する TRIGGER 権限が必要です。このセクションのあとの方で説明されているように、DEFINER 値によっては、このステートメントに SUPER 権限も必要になる可能性があります。バイナリロギングが有効になっている場合は、セクション20.7「ストアドプログラムのバイナリロギング」で説明されているように、CREATE TRIGGERSUPER 権限が必要になることがあります。

DEFINER 句は、このセクションのあとの方で説明されているように、トリガーのアクティブ化時にアクセス権限を確認するときに使用されるセキュリティーコンテキストを決定します。

trigger_time は、このトリガーのアクション時間です。これは、トリガーが各行の変更の前またはあとにアクティブ化されることを示す BEFORE または AFTER にすることができます。

trigger_event は、このトリガーをアクティブ化する操作の種類を示します。次の trigger_event 値が許可されます。

  • INSERT: このトリガーは (たとえば、INSERTLOAD DATA、および REPLACE ステートメントを使用して) 新しい行がテーブルに挿入されると常にアクティブ化されます。

  • UPDATE: このトリガーは (たとえば、UPDATE ステートメントを使用して) 行が変更されると常にアクティブ化されます。

  • DELETE: このトリガーは (たとえば、DELETE および REPLACE ステートメントを使用して) 行がテーブルから削除されると常にアクティブ化されます。テーブルに対する DROP TABLE および TRUNCATE TABLE ステートメントは、DELETE を使用しないため、このトリガーをアクティブ化しません。また、パーティションを削除しても DELETE トリガーはアクティブ化されません。

trigger_event は、トリガーをアクティブ化する SQL ステートメントのリテラル型を表しているのではなく、テーブル操作の種類を表しています。たとえば、INSERT トリガーは、INSERT ステートメントだけでなく、LOAD DATA ステートメントでもアクティブ化されます。それは、どちらのステートメントもテーブルに行を挿入するためです。

この混乱を招く可能性がある例として、INSERT INTO ... ON DUPLICATE KEY UPDATE ... 構文があります。すべての行で BEFORE INSERT トリガーがアクティブ化されたあと、その行に重複キーが存在したかどうかに応じて、AFTER INSERT トリガーだけか、または BEFORE UPDATE トリガーと AFTER UPDATE トリガーの両方がアクティブ化されます。

注記

カスケードされた外部キーアクションはトリガーをアクティブ化しません。

特定のテーブルに対して、トリガーイベントとアクション時間が同じ複数のトリガーが存在していてはいけません。たとえば、1 つのテーブルに対して 2 つの BEFORE UPDATE トリガーを定義することはできません。ただし、BEFORE UPDATE および BEFORE INSERT トリガー、または BEFORE UPDATE および AFTER UPDATE トリガーは設定できます。

trigger_body は、トリガーがアクティブ化されるときに実行されるステートメントです。複数のステートメントを実行するには、BEGIN ... END 複合ステートメント構造構文を使用します。また、これにより、ストアドルーチン内で許可されるのと同じステートメントを使用することもできます。セクション13.6.1「BEGIN ... END 複合ステートメント構文」を参照してください。一部のステートメントは、トリガー内では許可されません。セクションD.1「ストアドプログラムの制約」を参照してください。

トリガー本体内では、エイリアス OLDNEW を使用して、対象テーブル (そのトリガーに関連付けられたテーブル) 内のカラムを参照できます。OLD.col_name は、更新または削除される前の既存の行のカラムを示します。NEW.col_name は、挿入された新しい行、または更新されたあとの既存の行のカラムを示します。

MySQL は、トリガーが作成されたときの有効な sql_mode システム変数の設定を格納し、トリガーが実行を開始したときの現在のサーバー SQL モードには関係なく、常にそのトリガー本体を強制的にこの設定で実行します。

DEFINER 句は、トリガーのアクティブ化時にアクセス権限を確認するときに使用される MySQL アカウントを指定します。user 値を指定する場合は、'user_name'@'host_name' (GRANT ステートメントで使用されるのと同じ形式)、CURRENT_USER、または CURRENT_USER() として指定された MySQL アカウントにしてください。DEFINER のデフォルト値は、CREATE TRIGGER ステートメントを実行するユーザーです。これは、明示的に DEFINER = CURRENT_USER を指定するのと同じです。

DEFINER 句を指定した場合は、次のルールによって有効な DEFINER ユーザーの値が決定されます。

  • SUPER 権限がない場合、許可される唯一の user 値は、リテラルで指定するか、または CURRENT_USER を使用して指定した自分のアカウントです。定義者をほかのアカウントに設定することはできません。

  • SUPER 権限がある場合は、構文として有効な任意のアカウント名を指定できます。そのアカウントが実際に存在しない場合は、警告が生成されます。

  • 存在しない DEFINER アカウントでトリガーを作成することはできますが、そのアカウントが実際に存在するようになるまで、このようなトリガーをアクティブ化することはお勧めできません。それ以外の権限確認に関する動作は定義されていません。

MySQL は、トリガー権限を確認するときに、DEFINER ユーザーを次のように考慮します。

  • CREATE TRIGGER の時点で、このステートメントを発行するユーザーには TRIGGER 権限が必要です。

  • トリガーのアクティブ化時、権限は DEFINER ユーザーに対して確認されます。このユーザーには、次の権限が必要です。

    • 対象テーブルに対する TRIGGER 権限。

    • テーブルカラムへの参照がトリガー本体内の OLD.col_name または NEW.col_name を使用して発生した場合は、対象テーブルに対する SELECT 権限。

    • テーブルカラムがトリガー本体内の SET NEW.col_name = value 割り当てのターゲットである場合は、対象テーブルに対する UPDATE 権限。

    • その他のどのような権限も、通常、そのトリガーによって実行されるステートメントに必要です。

トリガーのセキュリティーの詳細は、セクション20.6「ストアドプログラムおよびビューのアクセスコントロール」を参照してください。

トリガー本体内で、CURRENT_USER() 関数は、トリガーのアクティブ化時に権限を確認するために使用されるアカウントを返します。これは、そのトリガーがアクティブ化される原因となるアクションを実行したユーザーではなく、DEFINER ユーザーです。トリガー内のユーザー監査については、セクション6.3.13「SQL ベースの MySQL アカウントアクティビティーの監査」を参照してください。

LOCK TABLES を使用してトリガーを含むテーブルをロックした場合は、セクション13.3.5.2「LOCK TABLES とトリガー」で説明されているように、そのトリガー内で使用されているテーブルもロックされます。

トリガーの使用の詳細は、セクション20.3.1「トリガーの構文と例」を参照してください。

13.1.20 CREATE VIEW 構文

CREATE [OR REPLACE] [ALGORITHM = {UNDEFINED | MERGE | TEMPTABLE}] [DEFINER = { user | CURRENT_USER }] [SQL SECURITY { DEFINER | INVOKER }] VIEW view_name [(column_list)] AS select_statement [WITH [CASCADED | LOCAL] CHECK OPTION]

CREATE VIEW ステートメントは、新しいビューを作成するか、または OR REPLACE 句が指定されている場合は既存のビューを置き換えます。そのビューが存在しない場合、CREATE OR REPLACE VIEWCREATE VIEW と同じです。そのビューが存在する場合、CREATE OR REPLACE VIEWALTER VIEW と同じです。

select_statement は、そのビューの定義を提供する SELECT ステートメントです。(ビューから選択すると、事実上、SELECT ステートメントを使用して選択したことになります。) select_statement は、ベーステーブルまたはほかのビューから選択できます。

ビュー定義は作成時に固定されるため、ベースとなるテーブルへのそれ以降の変更はビュー定義に影響を与えません。たとえば、ビューがテーブル上で SELECT * として定義されている場合、あとでテーブルに追加された新しいカラムはそのビューの一部になりません。

ALGORITHM 句は、MySQL によるビューの処理方法に影響を与えます。DEFINER および SQL SECURITY 句は、ビューの呼び出し時にアクセス権限を確認するときに使用されるセキュリティーコンテキストを指定します。WITH CHECK OPTION 句を指定すると、ビューによって参照されているテーブル内の行への挿入または更新を制約できます。これらの句については、このセクションのあとの方で説明されています。

CREATE VIEW ステートメントには、このビューに対する CREATE VIEW 権限と、SELECT ステートメントによって選択される各カラムに対する何らかの権限が必要です。SELECT ステートメント内の別の場所で使用されているカラムに対しては、SELECT 権限が必要です。OR REPLACE 句が存在する場合は、このビューに対する DROP 権限も必要です。このセクションのあとの方で説明されているように、DEFINER 値によっては、CREATE VIEWSUPER 権限も必要になる可能性があります。

ビューが参照されると、このセクションのあとの方で説明されている権限確認が発生します。

ビューはデータベースに属します。デフォルトでは、新しいビューはデフォルトデータベース内に作成されます。ビューを明示的に特定のデータベース内に作成するには、そのビューの作成時に、その名前を db_name.view_name として指定します。

mysql> CREATE VIEW test.v AS SELECT * FROM t;

データベース内で、ベーステーブルとビューは同じ名前空間を共有するため、ベーステーブルとビューが同じ名前を持つことはできません。

SELECT ステートメントによって取得されるカラムは、テーブルカラムへの単純な参照にすることができます。また、関数、定数値、演算子などを使用した式にすることもできます。

ビューは、ベーステーブルと同様に、重複のない一意のカラム名を持つ必要があります。デフォルトでは、SELECT ステートメントによって取得されるカラムの名前はビューカラム名に使用されます。ビューカラムの明示的な名前を定義するには、オプションの column_list 句をカンマで区切られた識別子のリストとして指定できます。column_list 内の名前の数は、SELECT ステートメントによって取得されるカラムの数と同じである必要があります。

SELECT ステートメント内の修飾されていないテーブルまたはビュー名は、デフォルトデータベースを基準にして解釈されます。ビューは、テーブルまたはビュー名を適切なデータベース名で修飾することによって、ほかのデータベース内のテーブルまたはビューを参照できます。

ビューは、多くの種類の SELECT ステートメントから作成できできます。ベーステーブルまたはほかのビューを参照できます。結合、UNION、およびサブクエリーを使用できます。SELECT がテーブルをまったく参照しなくてもかまいません。次の例では、別のテーブルからの 2 つのカラムに加え、それらのカラムから計算される式を選択するビューを定義しています。

mysql> CREATE TABLE t (qty INT, price INT);mysql> INSERT INTO t VALUES(3, 50);mysql> CREATE VIEW v AS SELECT qty, price, qty*price AS value FROM t;mysql> SELECT * FROM v;+------+-------+-------+
| qty | price | value |
+------+-------+-------+
| 3 | 50 | 150 |
+------+-------+-------+

ビュー定義は、次の制限に従います。

  • SELECT ステートメントに FROM 句内のサブクエリーを含めることはできません。

  • SELECT ステートメントは、システムまたはユーザー変数を参照できません。

  • ストアドプログラム内で、この定義は、プログラムパラメータまたはローカル変数を参照できません。

  • SELECT ステートメントは、準備済みステートメントのパラメータを参照できません。

  • この定義で参照されているテーブルまたはビューは、すべて存在する必要があります。ただし、ビューが作成されたあとは、この定義で参照されているテーブルまたはビューを削除できます。この場合は、このビューを使用すると、エラーが発生します。この種類の問題に関してビュー定義を確認するには、CHECK TABLE ステートメントを使用します。

  • この定義は TEMPORARY テーブルを参照できないため、TEMPORARY ビューは作成できません。

  • ビュー定義で指定されているテーブルは、すべて定義時に存在する必要があります。

  • トリガーをビューに関連付けることはできません。

  • SELECT ステートメント内のカラム名のエイリアスは (256 文字の別名の最大の長さではなく) 64 文字のカラムの最大の長さに対してチェックされます。

ORDER BY はビュー定義内で許可されていますが、独自の ORDER BY を含むステートメントを使用しているビューから選択した場合は無視されます。

この定義内のその他のオプションまたは句の場合は、そのビューを参照しているステートメントのオプションまたは句に追加されますが、その効果は定義されていません。たとえば、ビュー定義に LIMIT 句が含まれているときに、独自の LIMIT 句を含むステートメントを使用しているビューから選択した場合、どの制限が適用されるかは未定義です。この同じ原則は、SELECT キーワードに続く ALLDISTINCTSQL_SMALL_RESULT などのオプションや、INTOFOR UPDATELOCK IN SHARE MODEPROCEDURE などの句にも適用されます。

ビューを作成したあとに、システム変数の変更によってクエリー処理環境を変更すると、そのビューから得られる結果に影響を与える可能性があります。

mysql> CREATE VIEW v (mycol) AS SELECT 'abc';Query OK, 0 rows affected (0.01 sec)
mysql> SET sql_mode = '';Query OK, 0 rows affected (0.00 sec)
mysql> SELECT "mycol" FROM v;+-------+
| mycol |
+-------+
| mycol |
+-------+
1 row in set (0.01 sec)
mysql> SET sql_mode = 'ANSI_QUOTES';Query OK, 0 rows affected (0.00 sec)
mysql> SELECT "mycol" FROM v;+-------+
| mycol |
+-------+
| abc |
+-------+
1 row in set (0.00 sec)

DEFINER および SQL SECURITY 句は、そのビューを参照しているステートメントの実行時に、そのビューに対するアクセス権限を確認するときにどの MySQL アカウントを使用するかを決定します。SQL SECURITY 特性の有効な値は、DEFINERINVOKER です。これらは、それぞれ、そのビューを定義したユーザーまたは呼び出したユーザーが必要な権限を持っている必要があることを示します。SQL SECURITY のデフォルト値は DEFINER です。

DEFINER 句に user 値を指定する場合は、'user_name'@'host_name' (GRANT ステートメントで使用されるのと同じ形式)、CURRENT_USER、または CURRENT_USER() として指定された MySQL アカウントにするようにしてください。DEFINER のデフォルト値は、CREATE VIEW ステートメントを実行するユーザーです。これは、明示的に DEFINER = CURRENT_USER を指定するのと同じです。

DEFINER 句を指定した場合は、次のルールによって有効な DEFINER ユーザーの値が決定されます。

  • SUPER 権限がない場合、有効な唯一の user 値は、リテラルで指定するか、または CURRENT_USER を使用して指定した自分のアカウントです。定義者をほかのアカウントに設定することはできません。

  • SUPER 権限がある場合は、構文として有効な任意のアカウント名を指定できます。そのアカウントが実際に存在しない場合は、警告が生成されます。

  • 存在しない DEFINER アカウントでビューを作成することはできますが、SQL SECURITY 値が DEFINER であるが、定義者アカウントが存在しない場合は、そのビューが参照されたときにエラーが発生します。

ビューのセキュリティーの詳細は、セクション20.6「ストアドプログラムおよびビューのアクセスコントロール」を参照してください。

ビュー定義内で、CURRENT_USER は、デフォルトではそのビューの DEFINER 値を返します。SQL SECURITY INVOKER 特性を使用して定義されたビューの場合、CURRENT_USER は、そのビューの呼び出し元のアカウントを返します。ビュー内のユーザー監査については、セクション6.3.13「SQL ベースの MySQL アカウントアクティビティーの監査」を参照してください。

SQL SECURITY DEFINER 特性を使用して定義されたストアドルーチン内で、CURRENT_USER は、そのルーチンの DEFINER 値を返します。ビュー定義に CURRENT_USERDEFINER 値が含まれている場合は、これにより、このようなルーチン内で定義されたビューも影響を受けます。

ビューの権限は、次のように確認されます。

  • ビューの定義時に、ビュー作成者は、そのビューによってアクセスされるトップレベルのオブジェクトを使用するために必要な権限を持っている必要があります。たとえば、ビュー定義がテーブルカラムを参照している場合、作成者は、その定義の選択リスト内の各カラムに対する何らかの権限と、その定義内の別の場所で使用されている各カラムに対する SELECT 権限を持っている必要があります。この定義がストアドファンクションを参照している場合は、その関数を呼び出すために必要な権限のみを確認できます。関数呼び出し時に必要な権限は、その関数が実行されるときにしか確認できません。別の呼び出しでは、その関数内の別の実行パスが選択される可能性があります。

  • ビューを参照するユーザーは、そのビューにアクセスするための適切な権限 (そのビューから選択するための SELECT や、そのビューに挿入するための INSERT など) を持っている必要があります。

  • ビューが参照されると、そのビューによってアクセスされるオブジェクトに対する権限が、SQL SECURITY 特性が DEFINER または INVOKER のどちらであるかに応じて、それぞれ、そのビューの DEFINER アカウントによって保持されている権限または呼び出し元に対して確認されます。

  • ビューへの参照によってストアドファンクションが実行される場合、その関数内で実行されるステートメントの権限確認は、その関数の SQL SECURITY 特性が DEFINER または INVOKER のどちらであるかによって異なります。セキュリティー特性が DEFINER である場合、その関数は DEFINER アカウントの権限で実行されます。この特性が INVOKER である場合、その関数は、そのビューの SQL SECURITY 特性によって決定される権限で実行されます。

例: あるビューがストアドファンクションに依存する可能性があり、さらにその関数がほかのストアドルーチンを呼び出す可能性があります。たとえば、次のビューはストアドファンクション f() を呼び出します。

CREATE VIEW v AS SELECT * FROM t WHERE t.id = f(t.name);

f() に次のようなステートメントが含まれているとします。

IF name IS NULL then CALL p1();
ELSE CALL p2();
END IF;

f() が実行されるとき、f() 内のステートメントを実行するために必要な権限を確認する必要があります。これは、f() 内の実行パスに応じて、p1() または p2() に対する権限が必要であることを示します。これらの権限は実行時に確認する必要があり、それらの権限を持っている必要のあるユーザーは、ビュー v と関数 f()SQL SECURITY 値によって決定されます。

ビューの DEFINER および SQL SECURITY 句は、標準 SQL への拡張です。標準 SQL では、ビューは SQL SECURITY DEFINER のルールを使用して処理されます。標準には、ビューの定義者 (これは、ビューのスキーマの所有者と同じです) はそのビューに対する該当する権限 (SELECT など) を取得し、またそれらを付与することができると記載されています。MySQL にはスキーマの所有者という概念がないため、MySQL では定義者を識別するための句が追加されています。DEFINER 句は、標準が備えている機能、つまり、だれがそのビューを定義したかについての永続的なレコードを備えることを目的とした拡張です。DEFINER のデフォルト値がビュー作成者のアカウントになっているのはそのためです。

オプションの ALGORITHM 句は、標準 SQL への MySQL 拡張です。これは、MySQL によるビューの処理方法に影響を与えます。ALGORITHM は、MERGETEMPTABLE、または UNDEFINED の 3 つの値を受け取ります。ALGORITHM 句が存在しない場合、デフォルトのアルゴリズムは UNDEFINED です。詳細は、セクション20.5.2「ビュー処理アルゴリズム」を参照してください。

いくつかのビューは更新可能です。つまり、これらのビューを UPDATEDELETEINSERT などのステートメントで使用して、ベースとなるテーブルの内容を更新できます。ビューが更新可能であるためには、そのビュー内の行とベースとなるテーブル内の行の間に 1 対 1 の関係が存在する必要があります。また、ビューを更新不可能にするその他の特定の構造構文も存在します。

更新可能なビューに対して WITH CHECK OPTION 句を指定すると、select_statement 内の WHERE 句が true である行を除く行への挿入または更新を回避できます。

更新可能なビューに対する WITH CHECK OPTION 句では、そのビューが別のビューとの関連で定義されている場合、LOCAL および CASCADED キーワードによってチェックテストのスコープが決定されます。LOCAL キーワードは、CHECK OPTION を、定義されているビューのみに制限します。CASCADED を指定すると、ベースとなるビューに対するチェックも評価されます。どちらのキーワードも指定されていない場合、デフォルトは CASCADED になります。

更新可能なビューおよび WITH CHECK OPTION 句の詳細は、セクション20.5.3「更新可能および挿入可能なビュー」を参照してください。

13.1.21 DROP DATABASE 構文

DROP {DATABASE | SCHEMA} [IF EXISTS] db_name

DROP DATABASE は、データベース内のすべてのテーブルを削除したあと、そのデータベースを削除します。このステートメントには十分に注意してください。DROP DATABASE を使用するには、そのデータベースに対する DROP 権限が必要です。DROP SCHEMADROP DATABASE のシノニムです。

重要

データベースが削除されても、そのデータベースに対するユーザー権限が自動的に削除されることはありませんセクション13.7.1.4「GRANT 構文」を参照してください。

IF EXISTS は、データベースが存在しない場合にエラーが発生しないようにするために使用されます。

デフォルトデータベースが削除されると、そのデフォルトデータベースは設定解除されます (DATABASE() 関数が NULL を返します)。

シンボリックリンクされたデータベースに対して DROP DATABASE を使用した場合は、そのリンクと元のデータベースの両方が削除されます。

DROP DATABASE は、削除されたテーブルの数を返します。これは、削除された .frm ファイルの数に対応します。

DROP DATABASE ステートメントは、MySQL 自体が通常の動作中に作成する可能性のあるファイルとディレクトリを特定のデータベースディレクトリから削除します。

  • 次の拡張子を持つすべてのファイル。

    .BAK.DAT.HSH.MRG
    .MYD.MYI.TRG.TRN
    .db.frm.ibd.ndb
    .par   
  • db.opt ファイル (存在する場合)。

今一覧表示されたファイルを MySQL が削除したあとに、このデータベースディレクトリ内にほかのファイルやディレクトリが残っている場合は、そのデータベースディレクトリを削除できません。この場合は、残っているすべてのファイルまたはディレクトリを手動で削除してから、再度 DROP DATABASE ステートメントを発行する必要があります。

データベースを削除しても、そのデータベース内に作成されたどの TEMPORARY テーブルも削除されません。TEMPORARY テーブルは、それらを作成したセッションが終了すると自動的に削除されます。一時テーブルを参照してください。

データベースは mysqladmin でも削除できます。セクション4.5.2「mysqladmin — MySQL サーバーの管理を行うクライアント」を参照してください。

13.1.22 DROP EVENT 構文

DROP EVENT [IF EXISTS] event_name

このステートメントは、event_name という名前のイベントを削除します。このイベントはただちにアクティブな状態を停止し、サーバーから完全に削除されます。

このイベントが存在しない場合は、エラー ERROR 1517 (HY000): Unknown event 'event_name' が発生します。これをオーバーライドし、代わりに IF EXISTS を使用して、このステートメントで存在しないイベントに対する警告が生成されるようにできます。

このステートメントには、削除されるイベントが属するスキーマに対する EVENT 権限が必要です。

13.1.23 DROP FUNCTION 構文

DROP FUNCTION ステートメントは、ストアドファンクションやユーザー定義関数 (UDF) を削除するために使用されます。

13.1.24 DROP INDEX 構文

DROP INDEX [ONLINE|OFFLINE] index_name ON tbl_name [algorithm_option | lock_option] ...algorithm_option: ALGORITHM [=] {DEFAULT|INPLACE|COPY}lock_option: LOCK [=] {DEFAULT|NONE|SHARED|EXCLUSIVE}

DROP INDEX は、テーブル tbl_name から index_name という名前のインデックスを削除します。このステートメントは、このインデックスを削除するために ALTER TABLE ステートメントにマップされます。セクション13.1.7「ALTER TABLE 構文」を参照してください。

主キーを削除するには、インデックス名は常に PRIMARY です。これは、PRIMARY が予約語であるため、引用符で囲まれた識別子として指定する必要があります。

DROP INDEX `PRIMARY` ON t;

NDB テーブルの可変幅カラム上のインデックスはオンラインで、つまり、テーブルコピーを行うことなく削除されます。このテーブルは、この操作の期間中、同じ API ノードに対するほかの操作に対してロックされますが、ほかの MySQL Cluster API ノードからのアクセスに対してはロックされません。これは、サーバーが実行できると判断した場合は常に、そのサーバーによって自動的に実行されます。これを実行するために、特殊な SQL 構文やサーバーオプションを使用する必要はありません。

MySQL Cluster では、OFFLINE キーワードを使用してインデックスをオフラインで削除できます (これにより、そのテーブルはクラスタ内のすべての API ノードに対してロックされます)。DROP OFFLINE INDEX および DROP ONLINE INDEX を管理するルールや制限は、ALTER OFFLINE TABLE ... DROP INDEX および ALTER ONLINE TABLE ... DROP INDEX の場合と同じです。ONLINE キーワードを使用して、通常はオフラインで削除されるインデックスのコピーなし削除が実行されるようにすることはできません。DROP 操作をテーブルコピーなしで実行できない場合、サーバーは ONLINE キーワードを無視します。詳細は、セクション13.1.7.2「MySQL Cluster での ALTER TABLE オンライン操作」を参照してください。

ONLINE および OFFLINE キーワードは、MySQL Cluster でのみ使用できます。これらのキーワードを標準の MySQL Server 5.6 リリースで使用しようとすると、構文エラーが発生します。ONLINE および OFFLINE キーワードは、MySQL Cluster NDB 7.3 では非推奨です。MySQL Cluster NDB 7.4 では引き続きサポートされますが、将来の MySQL Cluster リリースでは削除対象としてスケジュールされています。

MySQL 5.6.6 の時点では、ALGORITHM および LOCK 句を指定できます。これらは、テーブルコピーの方法や、インデックスが変更されている間のテーブルの読み取りと書き込みの並列性のレベルに影響を与えます。これらには、ALTER TABLE ステートメントの場合と同じ意味があります。詳細は、セクション13.1.7「ALTER TABLE 構文」を参照してください。

13.1.25 DROP LOGFILE GROUP 構文

DROP LOGFILE GROUP logfile_group ENGINE [=] engine_name

このステートメントは、logfile_group という名前のログファイルグループを削除します。このログファイルグループがすでに存在する必要があります。そうしないと、エラー結果が発生します。(ログファイルグループの作成については、セクション13.1.14「CREATE LOGFILE GROUP 構文」を参照してください。)

重要

ログファイルグループを削除する前に、そのログファイルグループを UNDO ロギングのために使用しているすべてのテーブルスペースを削除する必要があります。

必須の ENGINE 句は、削除されるログファイルグループによって使用されるストレージエンジンの名前を指定します。現在、engine_name に許可される値は NDBNDBCLUSTER だけです。

DROP LOGFILE GROUP は、MySQL Cluster のディスクデータストレージでのみ有効です。セクション18.5.12「MySQL Cluster ディスクデータテーブル」を参照してください。

13.1.26 DROP PROCEDURE および DROP FUNCTION 構文

DROP {PROCEDURE | FUNCTION} [IF EXISTS] sp_name

このステートメントは、ストアドプロシージャーまたはストアドファンクションを削除するために使用されます。つまり、指定されたルーチンがサーバーから削除されます。このルーチンに対する ALTER ROUTINE 権限が必要です。(automatic_sp_privileges システム変数が有効になっている場合は、その権限と EXECUTE が自動的に、そのルーチンが作成されるときはルーチン作成者に付与され、そのルーチンが削除されるときは作成者から削除されます。セクション20.2.2「ストアドルーチンと MySQL 権限」を参照してください。)

IF EXISTS 句は MySQL 拡張です。これは、プロシージャーまたは関数が存在しない場合にエラーが発生しないようにします。SHOW WARNINGS で表示できる警告が生成されます。

DROP FUNCTION はまた、ユーザー定義関数を削除するためにも使用されます (セクション13.7.3.2「DROP FUNCTION 構文」を参照してください)。

13.1.27 DROP SERVER 構文

DROP SERVER [ IF EXISTS ] server_name

server_name という名前のサーバーのサーバー定義を削除します。mysql.servers テーブル内の対応する行が削除されます。このステートメントには、SUPER 権限が必要です。

テーブルのサーバーを削除しても、作成されるときにこの接続情報を使用したどの FEDERATED テーブルにも影響を与えません。セクション13.1.16「CREATE SERVER 構文」を参照してください。

DROP SERVER では、自動コミットは実行されません。

MySQL 5.6 では、使用されているロギング形式には関係なく、DROP SERVER はバイナリログに書き込まれません。

MySQL 5.6.11 でのみ、このステートメントを発行する前に、gtid_nextAUTOMATIC に設定する必要があります。(Bug #16062608、Bug #16715809、Bug #69045)

13.1.28 DROP TABLE 構文

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

DROP TABLE は、1 つ以上のテーブルを削除します。各テーブルに対する DROP 権限が必要です。すべてのテーブルデータとテーブル定義が削除されるため、このステートメントには注意してください。引数リストで指定されているいずれかのテーブルが存在しない場合、MySQL は削除できなかった存在しないテーブルを名前で示すエラーを返しますが、リスト内の存在しているすべてのテーブルの削除も行います。

重要

テーブルが削除されても、そのテーブルに対するユーザー権限は自動的には削除されませんセクション13.7.1.4「GRANT 構文」を参照してください。

パーティション化されたテーブルの場合は、DROP TABLE によってテーブル定義、そのすべてのパーティション、およびそれらのパーティションに格納されていたすべてのデータが永続的に削除されることに注意してください。また、削除されたテーブルに関連付けられているパーティション化定義 (.par) ファイルも削除されます。

存在しないテーブルに対してエラーが発生しないようにするには、IF EXISTS を使用します。IF EXISTS を使用している場合は、存在しないテーブルごとに NOTE が生成されます。セクション13.7.5.41「SHOW WARNINGS 構文」を参照してください。

RESTRICTCASCADE は、移植を容易にするために許可されています。MySQL 5.6 では、これらは何も行いません。

注記

DROP TABLE は、TEMPORARY キーワードが使用されていないかぎり、現在のアクティブなトランザクションを自動的にコミットします。

TEMPORARY キーワードには、次の効果があります。

  • このステートメントは、TEMPORARY テーブルのみを削除します。

  • このステートメントは、進行中のトランザクションを終了しません。

  • アクセス権は確認されません。(TEMPORARY テーブルは、それを作成したセッションにのみ表示されるため、確認は必要ありません。)

TEMPORARY の使用は、TEMPORARY 以外のテーブルを誤って削除してしまわないようにするための適切な方法です。

13.1.29 DROP TABLESPACE 構文

DROP TABLESPACE tablespace_name ENGINE [=] engine_name

このステートメントは、以前に CREATE TABLESPACE を使用して作成されたテーブルスペースを削除します (セクション13.1.18「CREATE TABLESPACE 構文」を参照してください)。

重要

削除されるテーブルスペースにデータファイルが含まれていてはいけません。つまり、テーブルスペースを削除できるようにするには、まず ALTER TABLESPACE ... DROP DATAFILE を使用してその各データファイルを削除する必要があります (セクション13.1.8「ALTER TABLESPACE 構文」を参照してください)。

ENGINE 句 (必須) は、このテーブルスペースによって使用されるストレージエンジンを指定します。現在、engine_name として受け入れられる値は NDBNDBCLUSTER だけです。

DROP TABLESPACE は、MySQL Cluster のディスクデータストレージでのみ有効です。セクション18.5.12「MySQL Cluster ディスクデータテーブル」を参照してください。

13.1.30 DROP TRIGGER 構文

DROP TRIGGER [IF EXISTS] [schema_name.]trigger_name

このステートメントは、トリガーを削除します。スキーマ (データベース) 名はオプションです。スキーマが省略されている場合、このトリガーはデフォルトスキーマから削除されます。DROP TRIGGER には、このトリガーに関連付けられたテーブルに対する TRIGGER 権限が必要です。

存在しないトリガーに対してエラーが発生しないようにするには、IF EXISTS を使用します。IF EXISTS を使用している場合は、存在しないトリガーに対して NOTE が生成されます。セクション13.7.5.41「SHOW WARNINGS 構文」を参照してください。

テーブルを削除すると、そのテーブルのトリガーも削除されます。

13.1.31 DROP VIEW 構文

DROP VIEW [IF EXISTS] view_name [, view_name] ... [RESTRICT | CASCADE]

DROP VIEW は、1 つ以上のビューを削除します。各ビューに対する DROP 権限が必要です。引数リストで指定されているいずれかのビューが存在しない場合、MySQL は削除できなかった存在しないビューを名前で示すエラーを返しますが、リスト内の存在しているすべてのビューの削除も行います。

IF EXISTS 句は、存在しないビューに対してエラーが発生しないようにします。この句が指定されている場合は、存在しないビューごとに NOTE が生成されます。セクション13.7.5.41「SHOW WARNINGS 構文」を参照してください。

RESTRICTCASCADE (指定されている場合) は解析されますが、無視されます。

13.1.32 RENAME TABLE 構文

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

このステートメントは、1 つ以上のテーブルの名前を変更します。

名前変更の操作は原子的に実行されます。つまり、名前の変更が実行されている間、ほかのセッションはどのテーブルにもアクセスできません。たとえば、既存のテーブル old_table が存在する場合は、次のように、同じ構造を持っているが空である別のテーブル new_table を作成してから、既存のテーブルをその空のテーブルに置き換えることができます (backup_table はまだ存在していないと仮定します)。

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

このステートメントで複数のテーブルの名前を変更する場合、名前の変更操作は左から右に実行されます。2 つのテーブル名をスワップする場合は、次のように実行できます (tmp_table はまだ存在していないと仮定します)。

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

2 つのデータベースが同じファイルシステム上に存在するかぎり、RENAME TABLE を使用して、あるデータベースから別のデータベースにテーブルを移動できます。

RENAME TABLE current_db.tbl_name TO other_db.tbl_name;

RENAME TABLE を使用して別のデータベースに移動されたテーブルに関連付けられたトリガーが存在する場合は、ステートメントがエラー Trigger in wrong schema で失敗します。

ビューの名前を変更して別のデータベースに移動しようとしないかぎり、RENAME TABLE はビューに対しても機能します。

名前変更されたテーブルまたはビュー専用に付与された権限は、どれも新しい名前には移行されません。それらは、手動で変更する必要があります。

RENAME を実行する場合は、ロックされたテーブルやアクティブなトランザクションが存在していてはいけません。また、元のテーブルに対する ALTER および DROP 権限と、新しいテーブルに対する CREATE および INSERT 権限も必要です。

複数テーブルの名前変更で何らかのエラーが発生した場合、MySQL はすべてをその元の状態に戻すために、名前変更されたすべてのテーブルに対して逆方向の名前変更を実行します。

RENAME を使用して TEMPORARY テーブルの名前を変更することはできません。ただし、代わりに ALTER TABLE を使用できます。

mysql> ALTER TABLE orig_name RENAME new_name;

この名前変更操作によってテーブルが別のファイルシステム上にあるデータベースに移動される場合、結果の成功はプラットフォーム固有であり、テーブルファイルを移動するために使用されるベースとなるオペレーティングシステムコールに依存します。

13.1.33 TRUNCATE TABLE 構文

TRUNCATE [TABLE] tbl_name

TRUNCATE TABLE は、テーブルを完全に空にします。これには DROP 権限が必要です。

TRUNCATE TABLE は論理的に、すべての行を削除する DELETE ステートメントや、DROP TABLE および CREATE TABLE ステートメントのシーケンスに似ています。高性能を実現するために、データを削除するための DML の方法をバイパスします。そのため、ロールバックすることができず、ON DELETE トリガーが起動されることはなく、さらに親子の外部キー関係を持つ InnoDB テーブルに対して実行することもできません。

TRUNCATE TABLEDELETE に似ているにもかかわらず、DML ステートメントではなく DDL ステートメントとして分類されます。MySQL 5.6 では、DELETE とは次の点で異なります。

  • 切り捨て操作はテーブルを削除して再作成するため、特に大きなテーブルの場合は、行を 1 つずつ削除するよりはるかに高速です。

  • 切り捨て操作は暗黙的なコミットを発生させるため、ロールバックできません。

  • セッションがアクティブなテーブルロックを保持している場合は、切り詰め操作を実行できません。

  • TRUNCATE TABLE は、InnoDB テーブルに対して、このテーブルを参照するほかのテーブルからの何らかの FOREIGN KEY 制約が存在する場合は失敗します。同じテーブルのカラム間の外部キー制約が許可されます。

  • 切り詰め操作は、削除された行数に対して、意味のある値を返しません。通常の結果は0 rows affectedですが、これは情報がないものとして解釈してください。

  • テーブル形式ファイル tbl_name.frm が有効であるかぎり、データまたはインデックスファイルが破損した場合でも、TRUNCATE TABLE を使用してテーブルを空のテーブルとして再作成できます。

  • AUTO_INCREMENT 値はすべて、その開始値にリセットされます。これは、通常はシーケンス値を再利用しない MyISAMInnoDB にも当てはまります。

  • パーティション化されたテーブルで使用された場合、TRUNCATE TABLE はそのパーティション化を保持します。つまり、データおよびインデックスファイルが削除されて再作成されるのに対して、パーティション定義 (.par) ファイルは影響を受けません。

  • TRUNCATE TABLE ステートメントは、ON DELETE トリガーを起動しません。

テーブルに対する TRUNCATE TABLE は、HANDLER OPEN で開かれたそのテーブルのすべてのハンドラを閉じます。

TRUNCATE TABLE は、バイナリロギングおよびレプリケーション目的のときは、DROP TABLE とそれに続く CREATE TABLE として、つまり、DML ではなく DDL として扱われます。これは、InnoDB またはほかのトランザクションストレージエンジン (そのトランザクション分離レベルがステートメントベースロギングを許可しない (READ COMMITTED または READ UNCOMMITTED)) を使用するときは、STATEMENT または MIXED ロギングモード使用時にステートメントがログに記録されず複製されなかった事実によります。(Bug #36763) ただし、InnoDB を使用するレプリケーションスレーブには依然としてすでに説明した方法で適用されます。

TRUNCATE TABLE はパフォーマンススキーマのサマリーテーブルで使用できますが、その効果は行の削除ではなく、サマリーカラムを 0 または NULL にリセットすることです。セクション22.9.9「パフォーマンススキーマサマリーテーブル」を参照してください。

13.2 データ操作ステートメント

13.2.1 CALL 構文

CALL sp_name([parameter[,...]])
CALL sp_name[()]

CALL ステートメントは、以前に CREATE PROCEDURE を使用して定義されたストアドプロシージャーを呼び出します。

引数を取らないストアドプロシージャーは、括弧なしで呼び出すことができます。つまり、CALL p()CALL p は同等です。

CALL は、OUT または INOUT パラメータとして宣言されたパラメータを使用して、その呼び出し元に値を返すことができます。そのプロシージャーから戻るとき、クライアントプログラムは、ルーチン内で実行された最後のステートメントで影響を受けた行数を取得することもできます。SQL レベルでは、ROW_COUNT() 関数を呼び出します。C API からは、mysql_affected_rows() 関数を呼び出します。

OUT または INOUT パラメータを使用してプロシージャーから値を取得するには、ユーザー変数を使用してこのパラメータを渡し、そのプロシージャーから戻ったあとに変数の値をチェックします。(そのプロシージャーを別のストアドプロシージャーまたはストアドファンクション内から呼び出している場合は、IN または INOUT パラメータとしてルーチンパラメータまたはローカルルーチン変数を渡すこともできます。)INOUT パラメータの場合は、プロシージャーに渡す前にその値を初期化してください。次のプロシージャーには、このプロシージャーが現在のサーバーバージョンに設定する OUT パラメータと、このプロシージャーがその現在の値から 1 増分する INOUT 値が含まれています。

CREATE PROCEDURE p (OUT ver_param VARCHAR(25), INOUT incr_param INT)
BEGIN # Set value of OUT parameter SELECT VERSION() INTO ver_param; # Increment value of INOUT parameter SET incr_param = incr_param + 1;
END;

このプロシージャーを呼び出す前に、INOUT パラメータとして渡される変数を初期化します。このプロシージャーを呼び出したあと、これらの 2 つの変数の値は設定または変更されています。

mysql> SET @increment = 10;mysql> CALL p(@version, @increment);mysql> SELECT @version, @increment;+--------------+------------+
| @version | @increment |
+--------------+------------+
| 5.5.3-m3-log | 11 |
+--------------+------------+

PREPARE および EXECUTE で使用される準備済み CALL ステートメントでは、IN パラメータにプレースホルダを使用できます。OUT および INOUT パラメータの場合、プレースホルダのサポートは MySQL 5.5.3 以降で使用できます。これらの種類のパラメータは、次のように使用できます。

mysql> SET @increment = 10;mysql> PREPARE s FROM 'CALL p(?, ?)';mysql> EXECUTE s USING @version, @increment;mysql> SELECT @version, @increment;+--------------+------------+
| @version | @increment |
+--------------+------------+
| 5.5.3-m3-log | 11 |
+--------------+------------+

MySQL 5.5.3 より前は、OUT または INOUT パラメータにプレースホルダのサポートは使用できません。OUT および INOUT パラメータに対するこの制限を回避するために、プレースホルダの使用は避けてください。代わりに、ユーザー変数を CALL ステートメント自体で参照し、EXECUTE ステートメントでは指定しないでください。

mysql> SET @increment = 10;mysql> PREPARE s FROM 'CALL p(@version, @increment)';mysql> EXECUTE s;mysql> SELECT @version, @increment;+--------------+------------+
| @version | @increment |
+--------------+------------+
| 5.5.0-m2-log | 11 |
+--------------+------------+

CALL SQL ステートメントを使用して、結果セットを生成するストアドプロシージャーを実行する C プログラムを記述するには、CLIENT_MULTI_RESULTS フラグが有効になっている必要があります。これは、各 CALL によって、プロシージャー内で実行されるステートメントによって返される可能性のある結果セットに加えて、呼び出しステータスを示すための結果が返されるためです。CLIENT_MULTI_RESULTS は、CALL が、準備済みステートメントを含むストアドプロシージャーを実行するために使用される場合にも有効になっている必要があります。このようなプロシージャーがいつロードされるかや、これらのステートメントによって結果セットが生成されるかどうかを特定することはできないため、これらを想定する必要があります。

CLIENT_MULTI_RESULTS は、mysql_real_connect() を呼び出すときに、CLIENT_MULTI_RESULTS フラグ自体を渡すことによって明示的に、または CLIENT_MULTI_STATEMENTS を渡すことによって暗黙的に有効にする (これによって CLIENT_MULTI_RESULTS も有効になります) ことができます。MySQL 5.6 では、CLIENT_MULTI_RESULTS はデフォルトで有効にされています。

mysql_query() または mysql_real_query() を使用して実行された CALL ステートメントの結果を処理するには、それ以上結果が存在するかどうかを判定するために mysql_next_result() を呼び出すループを使用してください。例については、セクション23.7.17「複数ステートメント実行の C API サポート」を参照してください。

MySQL インタフェースを備える言語で記述されたプログラムの場合は、CALL ステートメントからの OUT または INOUT パラメータの結果を直接取得するためのネイティブメソッドが MySQL 5.5.3 より前には存在しません。これらのパラメータ値を取得するには、CALL ステートメントでプロシージャーにユーザー定義変数を渡したあと、SELECT ステートメントを実行して変数値を含む結果セットを生成してください。INOUT パラメータを処理するには、CALL の前に、対応するユーザー変数を、プロシージャーに渡される値に設定するステートメントを実行してください。

次の例は、先に説明した、OUT パラメータと INOUT パラメータを含むストアドプロシージャー p の手法 (エラーチェックはなし) を示しています。

mysql_query(mysql, "SET @increment = 10");
mysql_query(mysql, "CALL p(@version, @increment)");
mysql_query(mysql, "SELECT @version, @increment");
result = mysql_store_result(mysql);
row = mysql_fetch_row(result);
mysql_free_result(result);

前のコードが実行されたあと、row[0]row[1] にはそれぞれ、@version@increment の値が含まれています。

MySQL 5.6 では、C プログラムは準備済みステートメントインタフェースを使用して CALL ステートメントを実行し、OUT および INOUT パラメータにアクセスできます。これは、それ以上結果が存在するかどうかを判定するために mysql_stmt_next_result() を呼び出すループを使用して CALL ステートメントの結果を処理することにより行われます。例については、セクション23.7.20「C API のプリペアド CALL ステートメントのサポート」を参照してください。MySQL インタフェースを備える言語は、準備済み CALL ステートメントを使用して、OUT および INOUT プロシージャーパラメータを直接取得できます。

MySQL 5.6.6 以降では、ストアドプログラムによって参照されるオブジェクトへのメタデータ変更が検出され、そのプログラムが次に実行されときに、影響を受けるステートメントの自動再解析が行われるようになります。詳細については、セクション8.9.4「プリペアドステートメントおよびストアドプログラムのキャッシュ」を参照してください。

13.2.2 DELETE 構文

DELETE は、テーブルの行を削除する DML ステートメントです。

単一テーブル構文

DELETE [LOW_PRIORITY] [QUICK] [IGNORE] FROM tbl_name [PARTITION (partition_name,...)] [WHERE where_condition] [ORDER BY ...] [LIMIT row_count]

DELETE ステートメントは、tbl_name の行を削除し、削除された行数を返します。削除された行数をチェックするには、セクション12.14「情報関数」で説明されているROW_COUNT() 関数を呼び出します。

メインの句

オプションの WHERE 句内の条件は、どの行を削除するかを識別します。WHERE 句がない場合は、すべての行が削除されます。

where_condition は、削除される各行に対して true に評価される式です。これは、セクション13.2.9「SELECT 構文」で説明されているように指定されます。

ORDER BY 句が指定されている場合は、指定されている順序で行が削除されます。LIMIT 句は、削除できる行数に制限を設定します。これらの句は単一テーブルの削除に適用されますが、複数テーブルの削除には適用されません。

複数テーブル構文

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

または:

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

権限

テーブルから行を削除するには、そのテーブルに対する DELETE 権限が必要です。WHERE 句で指定されているカラムなどの、読み取られるだけのカラムに対しては、SELECT 権限のみが必要です。

パフォーマンス

削除された行数を知る必要がない場合、テーブルを空にするには、WHERE 句のない DELETE ステートメントより TRUNCATE TABLE ステートメントの方が高速です。DELETE とは異なり、TRUNCATE TABLE はトランザクション内で、またはそのテーブルがロックされている場合は使用できません。セクション13.1.33「TRUNCATE TABLE 構文」およびセクション13.3.5「LOCK TABLES および UNLOCK TABLES 構文」を参照してください。

削除操作の速度はまた、セクション8.2.2.3「DELETE ステートメントの速度」で説明されている要因によって影響を受ける可能性もあります。

特定の DELETE ステートメントに時間がかかりすぎないようにするために、DELETE の MySQL 固有の LIMIT row_count 句は、削除される行の最大数を指定します。削除する行数がこの制限を超えている場合は、影響を受ける行数が LIMIT 値を下回るまで DELETE ステートメントを繰り返します。

サブクエリー

現在、テーブルから削除し、さらにサブクエリーで同じテーブルから選択することはできません。

パーティション化されたテーブル

MySQL 5.6.2 から、DELETE は、削除される行を選択する 1 つ以上のパーティションまたはサブパーティション (またはその両方) の名前のカンマ区切りリストを含む PARTITION オプションを使用した明示的なパーティション選択をサポートしています。このリストに含まれていないパーティションは無視されます。p0 という名前のパーティションを含むパーティション化されたテーブル t がある場合、ステートメント DELETE FROM t PARTITION (p0) の実行には、このテーブルに対して ALTER TABLE t TRUNCATE PARTITION (p0) を実行するのと同じ効果があります。どちらの場合も、パーティション p0 内のすべての行が削除されます。

PARTITION は、WHERE 条件とともに使用できます。その場合、この条件は、リストされているパーティション内の行に対してのみテストされます。たとえば、DELETE FROM t PARTITION (p0) WHERE c < 5 は、条件 c < 5 が true であるパーティション p0 の行のみを削除します。ほかのパーティション内の行はチェックされないため、DELETE によって影響を受けません。

PARTITION オプションはまた、複数テーブルの DELETE ステートメントでも使用できます。このようなオプションを、FROM オプションで指定されているテーブルごとに最大 1 つ使用できます。

詳細および例については、セクション19.5「パーティション選択」を参照してください。

自動インクリメントカラム

AUTO_INCREMENT カラムに最大値を含む行を削除した場合、その値は、MyISAM または InnoDB テーブルには再利用されません。autocommit モードで DELETE FROM tbl_name (WHERE 句はなし) を使用してテーブル内のすべての行を削除した場合、そのシーケンスは、InnoDBMyISAM を除くすべてのストレージエンジンに対して開始されます。セクション14.6.5「InnoDB での AUTO_INCREMENT 処理」で説明されているように、InnoDB テーブルに対しては、この動作の例外がいくつかあります。

MyISAM テーブルの場合は、マルチカラムキー内の AUTO_INCREMENT セカンダリカラムを指定できます。この場合は、シーケンスの先頭から削除された値の再利用が MyISAM テーブルに対しても実行されます。セクション3.6.9「AUTO_INCREMENT の使用」を参照してください。

修飾子

DELETE ステートメントは、次の修飾子をサポートします。

  • LOW_PRIORITY を指定した場合、サーバーは、ほかのどのクライアントもそのテーブルから読み取らなくなるまで DELETE の実行を遅延させます。これは、テーブルレベルロックのみを使用するストレージエンジン (MyISAMMEMORY、および MERGE) にのみ影響を与えます。

  • MyISAM テーブルでは、QUICK キーワードを使用した場合、ストレージエンジンは削除中にインデックスリーフをマージしません。これにより、一部の種類の削除操作が高速化される可能性があります。

  • IGNORE キーワードを指定すると、MySQL は行削除プロセス中のエラーを無視します。(解析の段階で検出されたエラーは、通常の方法で処理されます。)IGNORE の使用のために無視されたエラーは、警告として返されます。

削除の順序

DELETE ステートメントに ORDER BY 句が含まれている場合は、この句で指定されている順序で行が削除されます。これは、主に LIMIT と組み合わせて使用した場合に有効です。たとえば、次のステートメントは WHERE 句に一致する行を見つけ、それらを timestamp_column でソートしたあと、最初の (もっとも古い) 行を削除します。

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

ORDER BY はまた、参照整合性の違反を回避するために必要な順序で行を削除する場合も役立ちます。

InnoDB テーブル

大きなテーブルから多数の行を削除する場合は、InnoDB テーブルに対するロックテーブルのサイズを超える可能性があります。この問題を回避するために、または単にテーブルがロックされたままになる時間を最小限に抑えるために、DELETE をまったく使用しない次の方法が有効な場合があります。

  1. 削除されない行を選択して、元のテーブルと同じ構造を持つ空のテーブルに格納します。

    INSERT INTO t_copy SELECT * FROM t WHERE ... ;
  2. RENAME TABLE を使用して元のテーブルを原子的に移動したあと、コピーの名前を元の名前に変更します。

    RENAME TABLE t TO t_old, t_copy TO t;
  3. 元のテーブルを削除します。

    DROP TABLE t_old;

RENAME TABLE が実行されている間、関連するテーブルにはほかのどのセッションからもアクセスできないため、名前変更の操作は並列性の問題に制約されません。セクション13.1.32「RENAME TABLE 構文」を参照してください。

MyISAM テーブル

MyISAM テーブルでは、削除された行はリンクリスト内に保持され、以降の INSERT 操作は古い行の位置を再利用します。未使用領域を再利用し、ファイルサイズを減らすには、OPTIMIZE TABLE ステートメントまたは myisamchk ユーティリティーを使用してテーブルを再編成します。OPTIMIZE TABLE の方が使い方は簡単ですが、myisamchk の方が高速です。セクション13.7.2.4「OPTIMIZE TABLE 構文」およびセクション4.6.3「myisamchk — MyISAM テーブルメンテナンスユーティリティー」を参照してください。

QUICK 修飾子は、削除操作でインデックスリーフがマージされるかどうかに影響を与えます。DELETE QUICK は、削除された行のインデックス値が、あとで挿入された行の同様のインデックス値に置き換えられるアプリケーションで、特に役立ちます。この場合、削除された値によって残された穴は再利用されます。

DELETE QUICK は、削除された値によって、新しい挿入が再度発生するインデックス値の範囲全体にわたって空きのあるインデックスブロックが残される場合には役立ちません。この場合は、QUICK を使用すると、再利用されないままのインデックスで領域が浪費される可能性があります。このようなシナリオの例を次に示します。

  1. インデックス付き AUTO_INCREMENT カラムを含むテーブルを作成します。

  2. このテーブルに多数の行を挿入します。各挿入によって、インデックスの先頭に追加されるインデックス値が生成されます。

  3. DELETE QUICK を使用して、カラムの範囲の最後にある行のブロックを削除します。

このシナリオでは、削除されたインデックス値に関連付けられたインデックスブロックに空きができますが、QUICK が使用されているため、ほかのインデックスブロックにはマージされません。新しい挿入が発生したとき、新しい行には削除された範囲内のインデックス値が含まれていないため、これらのインデックスブロックは空きがあるままになります。さらに、削除された一部のインデックス値が偶然に空きのあるブロック内か、またはその隣のインデックスブロックに含まれていないかぎり、あとで QUICK なしで DELETE を使用した場合でも空きがあるままになります。これらの状況で未使用のインデックス領域を再利用するには、OPTIMIZE TABLE を使用します。

テーブルから多数の行を削除しようとしている場合は、DELETE QUICK に続けて OPTIMIZE TABLE を使用した方が高速になることがあります。これにより、インデックスブロックの多数のマージ操作が実行されるのではなく、インデックスが再構築されます。

複数テーブルの削除

WHERE 句内の条件に応じて 1 つ以上のテーブルから行を削除するには、DELETE ステートメントで複数のテーブルを指定できます。複数テーブルの DELETE では、ORDER BY または LIMIT を使用できません。セクション13.2.9.2「JOIN 構文」で説明されているように、table_references 句は、結合に含まれるテーブルをリストします。

最初の複数テーブル構文では、FROM 句の前にリストされているテーブルの一致する行のみが削除されます。2 番目の複数テーブル構文では、USING 句の前にある FROM 句にリストされているテーブルの一致する行のみが削除されます。その効果は、多数のテーブルの行を同時に削除し、さらに検索にのみ使用される追加のテーブルを指定できることです。

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

または:

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

これらのステートメントは、削除する行を検索するときに 3 つのすべてのテーブルを使用しますが、テーブル t1t2 の一致する行のみを削除します。

前の例では INNER JOIN を使用していますが、複数テーブルの DELETE ステートメントは、SELECT ステートメント内で許可されているほかの型の結合 (LEFT JOIN など) を使用できます。たとえば、t1 内に存在する行で t2 内に一致するものがない行を削除するには、LEFT JOIN を使用します。

DELETE t1 FROM t1 LEFT JOIN t2 ON t1.id=t2.id WHERE t2.id IS NULL;

この構文では、Access との互換性のために、各 tbl_name のあとに .* が許可されます。

外部キー制約が存在する InnoDB テーブルを含む、複数テーブルの DELETE ステートメントを使用した場合は、MySQL オプティマイザが、それらの親子関係の順序とは異なる順序でテーブルを処理する可能性があります。この場合、このステートメントは失敗し、ロールバックされます。代わりに、1 つのテーブルから削除したあと、InnoDB が提供する ON DELETE 機能を使用して、ほかのテーブルがそれに応じて変更されるようにしてください。

注記

テーブルのエイリアスを宣言した場合は、テーブルを参照するときにそのエイリアスを使用する必要があります。

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

複数テーブルの DELETE 内のテーブルエイリアスは、そのステートメントの table_references 部分でのみ宣言するようにしてください。それ以外の場所では、エイリアス参照が許可されますが、エイリアス宣言は許可されません。

正しい:

DELETE a1, a2 FROM t1 AS a1 INNER JOIN t2 AS a2
WHERE a1.id=a2.id;
DELETE FROM a1, a2 USING t1 AS a1 INNER JOIN t2 AS a2
WHERE a1.id=a2.id;

正しくない:

DELETE t1 AS a1, t2 AS a2 FROM t1 INNER JOIN t2
WHERE a1.id=a2.id;
DELETE FROM t1 AS a1, t2 AS a2 USING t1 INNER JOIN t2
WHERE a1.id=a2.id;

13.2.3 DO 構文

DO expr [, expr] ...

DO は式を実行しますが、結果は何も返しません。ほとんどの点で、DOSELECT expr, ... の短縮形ですが、その結果に関心がない場合は少し高速であるという利点があります。

DO は主に、副作用がある関数 (RELEASE_LOCK() など) で役立ちます。

例: この SELECT ステートメントは一時停止しますが、結果セットの生成も行います。

mysql> SELECT SLEEP(5);+----------+
| SLEEP(5) |
+----------+
| 0 |
+----------+
1 row in set (5.02 sec)

それに対して、DO は、結果セットを生成することなく一時停止します。

mysql> DO SLEEP(5);Query OK, 0 rows affected (4.99 sec)

これは、たとえば、結果セットを生成するステートメントを禁止しているストアドファンクションまたはトリガーで役立つ場合があります。

DO は式を実行するだけです。SELECT を使用できるすべての場合に使用できるわけではありません。たとえば、DO id FROM t1 は、テーブルを参照するため無効です。

13.2.4 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

HANDLER ステートメントは、テーブルストレージエンジンインタフェースへの直接アクセスを提供します。これは、InnoDB および MyISAM テーブルに使用できます。

HANDLER ... OPEN ステートメントはテーブルを開き、それを以降の HANDLER ... READ ステートメントを使用してアクセス可能にします。このテーブルオブジェクトはほかのセッションによって共有されておらず、このセッションが HANDLER ... CLOSE を呼び出すか、またはこのセッションが終了するまでクローズされません。エイリアスを使用してテーブルを開いた場合は、その開かれたテーブルへのほかの HANDLER ステートメントによるそれ以降の参照は、テーブル名ではなくエイリアスを使用する必要があります。

最初の HANDLER ... READ 構文は、指定されたインデックスが特定の値を満たし、かつ WHERE 条件が満たされている行をフェッチします。マルチカラムインデックスがある場合は、インデックスカラム値をカンマ区切りリストとして指定します。インデックス内のすべてのカラムの値を指定するか、またはインデックスカラムの左端のプリフィクスの値を指定します。インデックス my_idx に、col_acol_b、および col_c という名前の 3 つのカラムがその順序で含まれているとします。HANDLER ステートメントは、そのインデックス内の 3 つのすべてのカラム、または左端のプリフィクス内のカラムの値を指定できます。例:

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) ...

HANDLER インタフェースを使用してテーブルの PRIMARY KEY を参照するには、引用符で囲まれた識別子 `PRIMARY` を使用します。

HANDLER tbl_name READ `PRIMARY` ...

2 番目の HANDLER ... READ 構文は、WHERE 条件に一致するインデックス順序でテーブルの行をフェッチします。

3 番目の HANDLER ... READ 構文は、WHERE 条件に一致する自然な行順序でテーブルの行をフェッチします。これは、フルテーブルスキャンが望ましい場合は、HANDLER tbl_name READ index_name より高速です。自然な行順序とは、行が MyISAM テーブルデータファイル内に格納されている順序のことです。このステートメントは InnoDB テーブルに対しても機能しますが、個別のデータファイルが存在しないため、このような概念はありません。

LIMIT 句を使用しない場合は、すべての形式の HANDLER ... READ が単一行 (使用可能な場合) をフェッチします。特定の行数を返すには、LIMIT 句を含めます。その構文は、SELECT ステートメントの場合と同じです。セクション13.2.9「SELECT 構文」を参照してください。

HANDLER ... CLOSE は、HANDLER ... OPEN でオープンされたテーブルをクローズします。

通常の SELECT ステートメントの代わりに HANDLER インタフェースを使用する理由として、次のいくつかがあります。

  • HANDLERSELECT より高速です。

    • HANDLER ... OPEN に対して、指定されたストレージエンジンハンドラオブジェクトが割り当てられます。このオブジェクトは、そのテーブルに対する以降の HANDLER ステートメントに再利用されます。ステートメントごとに再初期化する必要はありません。

    • 関連する解析が少なくなります。

    • オプティマイザまたはクエリーチェックのオーバーヘッドがありません。

    • ハンドラインタフェースは (たとえば、ダーティー読み取りが許可されるような) データの整合性のある外観を提供する必要がないため、ストレージエンジンは、SELECT が通常は許可しない最適化を使用できます。

  • HANDLER によって、ISAM に似た低レベルのインタフェースを使用する MySQL アプリケーションへの移植が容易になります。(キー値格納パラダイムを使用するアプリケーションを適応させるための代替手段については、セクション14.18「InnoDB と memcached の統合」を参照してください。)

  • HANDLER を使用すると、SELECT では実現が困難な (または、不可能でさえある) 方法でデータベースをたどることができます。HANDLER インタフェースは、データベースに対話型ユーザーインタフェースを提供するアプリケーションの操作時にデータを調べるためのより自然な方法です。

HANDLER は、やや低レベルのステートメントです。たとえば、一貫性が提供されません。つまり、HANDLER ... OPEN はテーブルのスナップショットを作成せず、テーブルのロックも行いません。これは、HANDLER ... OPEN ステートメントが発行されたあと、テーブルデータを (現在のセッションまたはその他のセッションで) 変更することができ、これらの変更が HANDLER ... NEXT または HANDLER ... PREV スキャンに部分的にしか表示されない可能性があることを示します。

開かれたハンドラを閉じ、再度開くようにマークすることができます。その場合、このハンドラはテーブル内の位置を失います。これは、次の両方の状況が当てはまる場合に発生します。

  • このハンドラのテーブルに対して、いずれかのセッションが FLUSH TABLES または DDL ステートメントを実行している。

  • このハンドラを開いているセッションが、テーブルを使用する HANDLER 以外のステートメントを実行している。

テーブルに対する TRUNCATE TABLE は、HANDLER OPEN で開かれたそのテーブルのすべてのハンドラを閉じます。

FLUSH TABLES tbl_name WITH READ LOCK でフラッシュされたテーブルが HANDLER で開かれた場合、そのハンドラは暗黙的にフラッシュされ、その位置を失います。

HANDLER は、パーティション化されたテーブルではサポートされません。

13.2.5 INSERT 構文

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

または:

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

または:

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

INSERT は、既存のテーブルに新しい行を挿入します。このステートメントの INSERT ... VALUES および INSERT ... SET 形式は、明示的に指定された値に基づいて行を挿入します。INSERT ... SELECT 形式は、別の 1 つまたは複数のテーブルから選択された行を挿入します。INSERT ... SELECT については、セクション13.2.5.1「INSERT ... SELECT 構文」でさらに詳細に説明されています。

MySQL 5.6.2 以降では、パーティション化されたテーブルに挿入する場合、どのパーティションおよびサブパーティションが新しい行を受け入れるかを制御できます。PARTITION オプションは、テーブルの 1 つ以上のパーティションまたはサブパーティション (またはその両方) の名前のカンマ区切りリストを受け取ります。特定の INSERT ステートメントによって挿入される行がリストされているいずれかのパーティションに一致しない場合、INSERT ステートメントは Found a row not matching the given partition set エラーで失敗します。詳細および例については、セクション19.5「パーティション選択」を参照してください。

古い行を上書きするには、INSERT の代わりに REPLACE を使用できます。REPLACE は、古い行を複製する一意のキー値を含む新しい行の処理において INSERT IGNORE に相当するものです。新しい行は、破棄されるのではなく、古い行を置き換えるために使用されます。セクション13.2.8「REPLACE 構文」を参照してください。

tbl_name は、行が挿入されるテーブルです。このステートメントによって値が提供されるカラムは、次のように指定できます。

  • テーブル名のあとにカラム名のカンマ区切りリストを指定できます。この場合は、指定された各カラムの値を VALUES リストまたは SELECT ステートメントで指定する必要があります。

  • INSERT ... VALUES または INSERT ... SELECT にカラム名のリストを指定しない場合は、テーブル内のすべてのカラムの値を VALUES リストまたは SELECT ステートメントで指定する必要があります。テーブル内のカラムの順序がわからない場合は、DESCRIBE tbl_name を使用して見つけます。

  • SET 句は、カラム名を明示的に示します。

カラム値は、次のいくつかの方法で指定できます。

  • 厳密な SQL モードで実行していない場合、値が明示的に指定されていないカラムはすべて、デフォルトの (明示的または暗黙的な) 値に設定されます。たとえば、テーブル内のすべてのカラムを指定していないカラムリストを指定した場合、指定されていないカラムはそのデフォルト値に設定されます。デフォルト値の割り当てについては、セクション11.6「データ型デフォルト値」で説明されています。セクション1.7.3.3「無効データの制約」も参照してください。

    デフォルト値が含まれていないすべてのカラムの値を明示的に指定しないかぎり、INSERT ステートメントでエラーが生成されるようにする場合は、厳密モードを使用するようにしてください。セクション5.1.7「サーバー SQL モード」を参照してください。

  • カラムを明示的にそのデフォルト値に設定するには、キーワード DEFAULT を使用します。これにより、テーブル内の各カラムの値が含まれていない不完全な VALUES リストを書かなくても済むため、いくつかのカラムを除くすべてのカラムに値を割り当てる INSERT ステートメントの記述が容易になります。そうでない場合は、VALUES リスト内の各値に対応するカラム名のリストを書き出す必要があります。

    また、特定のカラムのデフォルト値を生成する式で使用できるより一般的な形式として DEFAULT(col_name) を使用することもできます。

  • カラムリストと VALUES リストの両方が空である場合、INSERT は、各カラムがそのデフォルト値に設定された行を作成します。

    INSERT INTO tbl_name () VALUES();

    厳密モードでは、いずれかのカラムにデフォルト値が含まれていない場合、エラーが発生します。それ以外の場合、MySQL は、明示的に定義されたデフォルト値が含まれていないすべてのカラムに対して暗黙のデフォルト値を使用します。

  • expr を指定して、カラム値を指定できます。これには、式の型がカラムの型に一致しない場合は型変換が行われる可能性があり、特定の値の変換によって、データ型に応じて異なる値が挿入されることがあります。たとえば、文字列 '1999.0e-2'INTFLOATDECIMAL(10,6)、または YEAR カラムに挿入すると、それぞれ、値 199919.992119.992100、および 1999 が挿入されます。INT および YEAR カラムに格納される値が 1999 である理由は、文字列から整数への変換では、その文字列の最初の、有効な整数または年と見なすことができる部分だけが調べられるためです。浮動小数点および固定小数点数カラムの場合、文字列から浮動小数点への変換では、文字列全体を有効な浮動小数点値と見なします。

    expr は、以前に値リスト内に設定された任意のカラムを参照できます。たとえば、次のステートメントは、col2 の値が、前に割り当てられている col1 を参照しているため実行可能です。

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

    ただし、次のステートメントは、col1 の値が、col1 のあとに割り当てられている col2 を参照しているため正当ではありません。

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

    1 つの例外として、AUTO_INCREMENT 値を含むカラムがあります。AUTO_INCREMENT 値はほかの値の割り当てのあとに生成されるため、割り当て内の AUTO_INCREMENT カラムへの参照はすべて 0 を返します。

VALUES 構文を使用する INSERT ステートメントは複数の行を挿入できます。これを行うには、それぞれが括弧で囲まれ、カンマで区切られた、カラム値の複数のリストを含めます。例:

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

各行の値リストは、括弧で囲まれている必要があります。次のステートメントは、リスト内の値の数がカラム名の数に一致しないため不正です。

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

このコンテキストでは、VALUEVALUES のシノニムです。どちらも、値リストの数については何も示しておらず、値リストが 1 つの場合でも複数の場合でも使用できます。

INSERT に関して影響を受けた行の値は、ROW_COUNT() 関数 (セクション12.14「情報関数」を参照してください) または mysql_affected_rows() C API 関数 (セクション23.7.7.1「mysql_affected_rows()」を参照してください) を使用して取得できます。

INSERT ... VALUES ステートメントを複数の値リストまたは INSERT ... SELECT とともに使用した場合、このステートメントは、次の形式の情報文字列を返します。

Records: 100 Duplicates: 0 Warnings: 0

Records は、このステートメントによって処理された行数を示します。(これは、Duplicates が 0 以外であることがあるため、必ずしも実際に挿入された行数ではありません。)Duplicates は、何らかの既存の一意のインデックス値を複製しているために挿入できなかった行数を示します。Warnings は、何らかの点で問題があったカラム値を挿入するための試行回数を示します。警告は、次のいずれかの条件で発生する場合があります。

  • NOT NULL として宣言されているカラムへの NULL の挿入。複数行の INSERT ステートメントまたは INSERT INTO ... SELECT ステートメントの場合、このカラムは、そのカラムデータ型の暗黙のデフォルト値に設定されます。これは、数値型では 0、文字列型では空の文字列 ('')、および日付と時間型では0の値です。サーバーは SELECT からの結果セットを検査して、それが単一行を返すかどうかを確認しないため、INSERT INTO ... SELECT ステートメントは複数行の挿入と同じ方法で処理されます。(単一行の INSERT の場合は、NULLNOT NULL カラムに挿入されても警告は発生しません。代わりに、このステートメントがエラーで失敗します。)

  • 数値カラムの、そのカラムの範囲外にある値への設定。この値は、その範囲のもっとも近い端点にクリップされます。

  • 数値カラムへの '10.34 a' などの値の割り当て。後続の非数値のテキストは取り除かれ、残りの数値部分が挿入されます。文字列値に先頭の数値部分が含まれていない場合、このカラムは 0 に設定されます。

  • 文字列カラム (CHARVARCHARTEXT、または BLOB) への、そのカラムの最大長を超える文字列の挿入。この値は、そのカラムの最大長に切り捨てられます。

  • 日付または時間カラムへの、そのデータ型として不正な値の挿入。このカラムは、その型の適切な 0 の値に設定されます。

C API を使用している場合は、mysql_info() 関数を呼び出すことによって情報文字列を取得できます。セクション23.7.7.35「mysql_info()」を参照してください。

INSERTAUTO_INCREMENT カラムを含むテーブルに行を挿入した場合、そのカラムに使用された値は SQL の LAST_INSERT_ID() 関数を使用して検索できます。C API 内からは、mysql_insert_id() 関数を使用します。

注記

これらの 2 つの関数が、必ずしも同じ動作を行うとは限りません。AUTO_INCREMENT カラムに関連した INSERT ステートメントの動作については、セクション12.14「情報関数」およびセクション23.7.7.37「mysql_insert_id()」でさらに詳細に説明されています。

INSERT ステートメントは、次の修飾子をサポートします。

  • DELAYED キーワードを使用した場合は、挿入される 1 つまたは複数の行をサーバーがバッファーに配置するため、INSERT DELAYED ステートメントを発行しているクライアントはただちに続行できます。そのテーブルが使用中である場合、サーバーはそれらの行を保持します。そのテーブルが未使用である場合、サーバーは行の挿入を開始する一方、そのテーブルに対する新しい読み取り要求が存在するかどうかを定期的にチェックします。存在する場合は、そのテーブルがふたたび未使用になるまで、遅延された行のキューは中断されます。セクション13.2.5.2「INSERT DELAYED 構文」を参照してください。

    DELAYED は、INSERT ... SELECT または INSERT ... ON DUPLICATE KEY UPDATE では無視されます。

    DELAYED はまた、テーブルやトリガーにアクセスする関数を使用しているか、または関数やトリガーから呼び出された INSERT でも無視されます。

    注記

    MySQL 5.6.6 現在、INSERT DELAYED は非推奨であり、将来のリリースで削除されます。代わりに INSERT (DELAYED を付けない) を使用してください。

  • LOW_PRIORITY キーワードを使用した場合、INSERT の実行は、ほかのどのクライアントもそのテーブルから読み取らなくなるまで遅延されます。これには、既存のクライアントが読み取っている間や、INSERT LOW_PRIORITY ステートメントが待機している間に読み取りを開始したほかのクライアントが含まれます。そのため、読み取り負荷の高い環境では、INSERT LOW_PRIORITY ステートメントを発行したクライアントが非常に長い時間 (場合によっては無期限に) 待機することになるおそれがあります。(これは、クライアントをただちに続行できるようにする INSERT DELAYED とは対照的です。)MyISAM テーブルで LOW_PRIORITY を使用すると、並列挿入が無効になるため、通常はこれを行わないようにしてください。セクション8.10.3「同時挿入」を参照してください。

    HIGH_PRIORITY を指定すると、サーバーが --low-priority-updates オプションで起動されている場合に、その効果がオーバーライドされます。また、同時挿入も使用されなくなります。セクション8.10.3「同時挿入」を参照してください。

    LOW_PRIORITYHIGH_PRIORITY は、テーブルレベルのロックのみを使用するストレージエンジン (MyISAMMEMORYMERGE など) にのみ影響を与えます。

  • IGNORE キーワードを使用した場合、INSERT ステートメントの実行中に発生したエラーは無視されます。たとえば、IGNORE を使用しない場合は、テーブル内の既存の UNIQUE インデックスまたは PRIMARY KEY 値を複製する行によって重複キーエラーが発生し、このステートメントは中止されます。IGNORE を指定すると、その行が破棄され、エラーは発生しません。代わりに、無視されたエラーが警告を生成する可能性がありますが、重複キーエラーは生成しません。

    IGNORE には、特定の値に一致するパーティションが見つからないパーティション化されたテーブルへの挿入でも同様の効果があります。IGNORE を指定しない場合、このような INSERT ステートメントはエラーで中止されます。ただし、INSERT IGNORE が使用されている場合は、一致しない値を含む行に対する挿入操作が暗黙のうちに失敗しますが、一致した行はすべて挿入されます。例については、セクション19.2.2「LIST パーティショニング」を参照してください。

    IGNORE が指定されていない場合は、エラーをトリガーするデータ変換によってステートメントが中止されます。IGNORE を指定すると、無効な値はもっとも近い値に調整されて挿入されます。警告は生成されますが、ステートメントは中止されません。mysql_info() C API 関数を使用すると、テーブルに実際に挿入された行数を確認できます。

  • ON DUPLICATE KEY UPDATE を指定したとき、UNIQUE インデックスまたは PRIMARY KEY に重複した値を発生させる行が挿入された場合は、古い行の UPDATE が実行されます。行ごとの影響を受けた行の値は、その行が新しい行として挿入された場合は 1、既存の行が更新された場合は 2、既存の行がその現在の値に設定された場合は 0 です。mysqld への接続時に CLIENT_FOUND_ROWS フラグを mysql_real_connect() に指定すると、既存の行がその現在の値に設定された場合の影響を受けた行の値は (0 ではなく) 1 になります。セクション13.2.5.3「INSERT ... ON DUPLICATE KEY UPDATE 構文」を参照してください。

テーブルに挿入するには、そのテーブルに対する INSERT 権限が必要です。ON DUPLICATE KEY UPDATE 句が使用されていて、重複キーのために代わりに UPDATE が実行される場合、このステートメントには、更新されるカラムに対する UPDATE 権限が必要です。読み取られるが、変更されないカラムの場合は、SELECT 権限のみが必要です (ON DUPLICATE KEY UPDATE 句にある col_name=expr 割り当ての右側でのみ参照されるカラムの場合など)。

MySQL 5.6.6 より前は、テーブルレベルのロックを採用した MyISAM などのストレージエンジンを使用しているパーティション化されたテーブルに影響を与える INSERT によって、そのテーブルのすべてのパーティションがロックされました。これは、INSERT ... PARTITION ステートメントにも当てはまりました。(これは、行レベルロックを採用した InnoDB などのストレージエンジンでは発生しておらず、現在も発生しません。)MySQL 5.6.6 以降では、MySQL はパーティションロックプルーニングを使用します。これにより、行が挿入されるパーティションだけが実際にロックされるようになります。詳細は、セクション19.6.4「パーティショニングとロック」を参照してください。

13.2.5.1 INSERT ... SELECT 構文

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

INSERT ... SELECT を使用すると、1 つまたは多数のテーブルから多数の行をテーブルにすばやく挿入できます。例:

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

INSERT ... SELECT ステートメントには、次の条件が適用されます。

  • 重複キー違反の原因になる行を無視するには、IGNORE を指定します。

  • DELAYED は、INSERT ... SELECT では無視されます。

  • INSERT ステートメントのターゲットテーブルが、クエリーの SELECT 部分の FROM 句に現れてもかまいません。(これは、一部の古いバージョンの MySQL では不可能でした。)ただし、テーブルに挿入し、さらにサブクエリーで同じテーブルから選択することはできません。

    テーブルからの選択とそのテーブルへの挿入を同時に行う場合、MySQL は SELECT からの行を保持するための一時テーブルを作成してから、それらの行をターゲットテーブルに挿入します。ただし、TEMPORARY テーブルを同じステートメント内で 2 回参照することはできないため、tTEMPORARY テーブルのときに INSERT INTO t ... SELECT ... FROM t を使用できない点は引き続き残ります (セクションB.5.7.2「TEMPORARY テーブルに関する問題」を参照してください)。

  • AUTO_INCREMENT カラムは、通常どおりに機能します。

  • バイナリログを使用して元のテーブルを確実に再作成できるようにするために、MySQL では、INSERT ... SELECT ステートメントでの並列挿入が許可されません。

  • SELECTINSERT が同じテーブルを参照している場合のあいまいなカラム参照の問題を回避するには、SELECT 部分で使用されている各テーブルの一意のエイリアスを指定し、その部分にあるカラム名を適切なエイリアスで修飾します。

MySQL 5.6.2 からは、テーブルの名前に続く PARTITION オプションでソースまたはターゲットテーブル (またはその両方) のどのパーティションまたはサブパーティション (またはその両方) を使用するかを明示的に選択できます。PARTITION がこのステートメントの SELECT 部分にあるソーステーブルの名前とともに使用されている場合は、そのパーティションリストで指定されているパーティションまたはサブパーティションの行のみが選択されます。PARTITION がこのステートメントの INSERT 部分のターゲットテーブルの名前とともに使用されている場合は、選択されたすべての行を、このオプションに続くパーティションリストで指定されているパーティションまたはサブパーティションに挿入できる必要があります。そうでない場合、INSERT ... SELECT ステートメントは失敗します。詳細および例については、セクション19.5「パーティション選択」を参照してください。

ON DUPLICATE KEY UPDATE の値の部分では、SELECT 部分で GROUP BY を使用していないかぎり、ほかのテーブル内のカラムを参照できます。1 つの副作用として、値の部分にある一意でないカラム名を修飾しなければならない点があります。

ORDER BY 句のない SELECT ステートメントが行を返す順序は特定されていません。つまり、レプリケーションを使用している場合、このような SELECT がマスターとスレーブ上で行を同じ順序で返す保証はありません。これにより、マスターとスレーブの間で不整合が発生する場合があります。これが発生しないようにするために、レプリケートされる INSERT ... SELECT ステートメントは常に INSERT ... SELECT ... ORDER BY column として記述するようにしてください。column の選択は、マスターとスレーブの両方で間違いなく行が同じ順序で返されるかぎり問題にはなりません。セクション17.4.1.16「レプリケーションと LIMIT」も参照してください。

この問題のために、MySQL 5.6.4 から、INSERT ... SELECT ON DUPLICATE KEY UPDATE および INSERT IGNORE ... SELECT ステートメントには、ステートメントベースのレプリケーションには安全でないというフラグが付けられます。この変更により、このようなステートメントは、ステートメントベースモードを使用しているときはログ内に警告を生成し、MIXED モードを使用しているときは行ベース形式を使用してログに記録されます。(Bug #11758262、Bug #50439)

セクション17.1.2.1「ステートメントベースおよび行ベースレプリケーションのメリットとデメリット」も参照してください。

MySQL 5.6.6 より前は、テーブルレベルのロックを採用した MyISAM などのストレージエンジンを使用しているパーティション化されたテーブルに対して機能した INSERT ... SELECT ステートメントによって、ソースおよびターゲットテーブルのすべてのパーティションがロックされました。(これは、行レベルロックを採用した InnoDB などのストレージエンジンを使用しているテーブルでは発生しておらず、現在も発生しません。)MySQL 5.6.6 以降では、ターゲットテーブルのすべてのパーティションがロックされますが、ソーステーブルは実際に読み取られたパーティションのみがロックされます。詳細は、セクション19.6.4「パーティショニングとロック」を参照してください。

13.2.5.2 INSERT DELAYED 構文

INSERT DELAYED ...

INSERT ステートメントの DELAYED オプションは、特定の種類のテーブル (MyISAM など) に使用できる、標準 SQL への MySQL 拡張です。クライアントが INSERT DELAYED を使用すると、サーバーからはただちに了解が得られ、行は、そのテーブルがほかのどのスレッドによっても使用されていないときに挿入されるようにキューに入れられます。

注記

INSERT DELAYED は、そのテーブルがほかで使用されていなければ、通常の INSERT より低速です。また、サーバーが、遅延された行が存在するテーブルごとに個別のスレッドを処理するための追加のオーバーヘッドもあります。つまり、INSERT DELAYED は、それが必要なことを実際に確信している場合にのみ使用するようにしてください。

MySQL 5.6.6 現在、INSERT DELAYED は非推奨であり、将来のリリースで削除されます。代わりに INSERT (DELAYED を付けない) を使用してください。

キューに入れられた行は、テーブルに挿入されるまで、メモリー内にのみ保持されます。つまり、mysqld を強制的に (たとえば、kill -9 で) 終了した場合や、mysqld が予期せず終了した場合は、まだディスクに書き込まれていないキューに入れられたすべての行が失われます

DELAYED の使用には、次のいくつかの制約があります。

  • INSERT DELAYED は、MyISAMMEMORYARCHIVE、および BLACKHOLE テーブルでのみ機能します。DELAYED をサポートしていないエンジンの場合は、エラーが発生します。

  • 挿入は、ロックを保持するセッションではなく、別のスレッドによって処理される必要があるため、LOCK TABLES を使用してロックされたテーブルで使用された場合は、INSERT DELAYED に対してエラーが発生します。

  • MyISAM テーブルでは、データファイルの途中に空きブロックが存在しない場合は、並列 SELECT および INSERT ステートメントがサポートされます。これらの状況では、MyISAMINSERT DELAYED を使用する必要はほとんどありません。

  • INSERT DELAYED は、値リストを指定する INSERT ステートメントでのみ使用するようにしてください。サーバーは、INSERT ... SELECT または INSERT ... ON DUPLICATE KEY UPDATE ステートメントでの DELAYED を無視します。

  • INSERT DELAYED ステートメントはただちに復帰するため、行が挿入される前に、LAST_INSERT_ID() を使用して、このステートメントによって生成される可能性のある AUTO_INCREMENT 値を取得することはできません。

  • DELAYED 行は、実際に挿入されるまで、SELECT ステートメントには表示されません。

  • MySQL 5.6 より前は、ステートメントが複数の行を挿入し、バイナリロギングが有効になっており、かつグローバルロギング形式がステートメントベースである (つまり、binlog_formatSTATEMENT に設定されているときは必ず) 場合、INSERT DELAYED は通常の INSERT として処理されました。MySQL 5.6 からは、binlog_format の値が STATEMENT または MIXED である場合は必ず、INSERT DELAYED は常に、単純な (つまり、DELAYED オプションのない) INSERT として処理されます。(後者の場合、このステートメントは行ベースのロギングへの切り替えをトリガーしなくなったため、そのステートメントベースの形式を使用してログに記録されます。)

    これは、行ベースのバイナリロギングモードを使用している (binlog_formatROW に設定されている) 場合は適用されません。この場合、INSERT DELAYED ステートメントは常に、指定のとおりに DELAYED オプションを使用して実行され、行更新イベントとしてログに記録されます。

  • INSERT DELAYED がスレーブ上で通常の INSERT として処理されるように、DELAYED はスレーブレプリケーションサーバー上で無視されます。これは、DELAYED のために、スレーブにマスターとは異なるデータが存在することになる場合があるためです。

  • テーブルが書き込みロックされているときに、そのテーブル構造を変更するために ALTER TABLE が使用されると、保留中の INSERT DELAYED ステートメントは失われます。

  • INSERT DELAYED は、ビューではサポートされません。

  • INSERT DELAYED は、パーティション化されたテーブルではサポートされません。

次に、INSERT または REPLACE に対して DELAYED オプションを使用したときの動作について詳細に説明します。この説明では、スレッドINSERT DELAYED ステートメントを受信したスレッドであり、ハンドラは、特定のテーブルに対するすべての INSERT DELAYED ステートメントを処理するスレッドです。

  • スレッドがあるテーブルに対する DELAYED ステートメントを実行すると、そのテーブルに対するすべての DELAYED ステートメントを処理するためのハンドラスレッドが作成されます (このようなハンドラがまだ存在しない場合)。

  • このスレッドは、そのハンドラが以前に DELAYED ロックを取得したかどうかをチェックします。取得していない場合は、それを行うようハンドラスレッドに指示します。DELAYED ロックは、ほかのスレッドがそのテーブルに対する READ または WRITE ロックを保持している場合でも取得できます。ただし、ハンドラはテーブル構造を確実に最新の状態にするために、すべての ALTER TABLE ロックまたは FLUSH TABLES ステートメントが完了するのを待機します。

  • このスレッドは INSERT ステートメントを実行しますが、行をテーブルに書き込む代わりに、最終行のコピーをそのハンドラスレッドによって管理されているキューに配置します。構文エラーはすべてスレッドによって検出され、クライアントプログラムにレポートされます。

  • INSERT は挿入操作が完了する前に復帰するため、クライアントは重複した行の数や、結果として得られる行の AUTO_INCREMENT 値をサーバーから取得できません。(C API を使用している場合も、同じ理由で、mysql_info() 関数は意味のある情報を何も返しません。)

  • バイナリログは、行がテーブルに挿入されたときにハンドラスレッドによって更新されます。複数行の挿入の場合、バイナリログは、先頭行が挿入されたときに更新されます。

  • delayed_insert_limit 行が書き込まれるたびに、ハンドラは、いずれかの SELECT ステートメントが引き続き保留中かどうかをチェックします。保留中の場合は、続行する前に、これらの実行を許可します。

  • ハンドラのキューにそれ以上行がなくなると、テーブルはロック解除されます。新しい INSERT DELAYED ステートメントが delayed_insert_timeout 秒以内に受信されなかった場合、ハンドラは終了します。

  • 特定のハンドラキュー内で delayed_queue_size を超える行が保留中である場合、INSERT DELAYED を要求しているスレッドは、そのキューに空きができるまで待機します。これは、遅延されたメモリーキューのすべてのメモリーが mysqld によって使用されてしまわないようにするために行われます。

  • このハンドラスレッドは、MySQL プロセスリストの Command カラム内に delayed_insert として現れます。これは、FLUSH TABLES ステートメントを実行するか、または KILL thread_id で強制終了すると強制終了されます。ただし、終了する前に、まずキューに入れられたすべての行をテーブルに格納します。この時間中は、ほかのスレッドからの新しいどの INSERT ステートメントも受け入れません。このあとに INSERT DELAYED ステートメントを実行すると、新しいハンドラスレッドが作成されます。

    つまり、実行中の INSERT DELAYED ハンドラが存在する場合、INSERT DELAYED ステートメントは通常の INSERT ステートメントより高い優先度を持っています。その他の更新ステートメントは、INSERT DELAYED キューが空になるか、だれかが (KILL thread_id で) このハンドラスレッドを終了するか、またはだれかが FLUSH TABLES を実行するまで待機する必要があります。

  • 次のステータス変数は、INSERT DELAYED ステートメントに関する情報を提供します。

    ステータス変数意味
    Delayed_insert_threadsハンドラスレッドの数
    Delayed_writesINSERT DELAYED で書き込まれた行数
    Not_flushed_delayed_rows書き込みを待機している行数

    これらの変数は、SHOW STATUS ステートメントを発行するか、または mysqladmin extended-status コマンドを実行することによって表示できます。

13.2.5.3 INSERT ... ON DUPLICATE KEY UPDATE 構文

ON DUPLICATE KEY UPDATE を指定したとき、UNIQUE インデックスまたは PRIMARY KEY に重複した値を発生させる行が挿入された場合は、MySQL によって古い行の UPDATE が実行されます。たとえば、カラム aUNIQUE として宣言され、値 1 を含んでいる場合、次の 2 つのステートメントには同様の効果があります。

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;

(これらの効果は、a が自動インクリメントカラムである InnoDB テーブルに対して同じではありません。自動インクリメントカラムを使用した場合、INSERT ステートメントは自動インクリメント値を増やしますが、UPDATE は増やしません。)

ON DUPLICATE KEY UPDATE 句には、カンマで区切られた、複数のカラム割り当てを含めることができます。

ON DUPLICATE KEY UPDATE を使用した場合、行ごとの影響を受けた行の値は、その行が新しい行として挿入された場合は 1、既存の行が更新された場合は 2、既存の行がその現在の値に設定された場合は 0 です。mysqld への接続時に CLIENT_FOUND_ROWS フラグを mysql_real_connect() に指定すると、既存の行がその現在の値に設定された場合の影響を受けた行の値は (0 ではなく) 1 になります。

カラム b も一意である場合、INSERT は、代わりに次の UPDATE ステートメントと同等です。

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

a=1 OR b=2 が複数の行に一致する場合は、1 つの行だけが更新されます。一般に、一意のインデックスが複数含まれているテーブルに対して ON DUPLICATE KEY UPDATE 句を使用することは避けるようにしてください。

UPDATE 句で VALUES(col_name) 関数を使用して、INSERT ... ON DUPLICATE KEY UPDATE ステートメントの INSERT 部分からカラム値を参照できます。つまり、ON DUPLICATE KEY UPDATE 句にある VALUES(col_name) は、重複キーの競合が発生していない場合に挿入される col_name の値を参照します。この関数は、複数の行を挿入する際に特に役立ちます。VALUES() 関数は、INSERT ... UPDATE ステートメントの中でだけ意味を持ち、そうでなければ NULL を返します。例:

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

そのステートメントは、次の 2 つのステートメントと同一です。

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;

テーブルに AUTO_INCREMENT カラムが含まれているときに、INSERT ... ON DUPLICATE KEY UPDATE で行を挿入または更新した場合、LAST_INSERT_ID() 関数は AUTO_INCREMENT 値を返します。

ON DUPLICATE KEY UPDATE を使用している場合、DELAYED オプションは無視されます。

INSERT ... SELECT ステートメントの結果は SELECT からの行の順序に依存し、またこの順序を常に保証することはできないため、ロギング時に、INSERT ... SELECT ON DUPLICATE KEY UPDATE ステートメントがマスターとスレーブで異なる可能性があります。そのため、MySQL 5.6.4 以降では、INSERT ... SELECT ON DUPLICATE KEY UPDATE ステートメントには、ステートメントベースのレプリケーションには安全でないというフラグが付けられます。この変更により、このようなステートメントは、ステートメントベースモードを使用しているときはログ内に警告を生成し、MIXED モードを使用しているときは行ベース形式を使用してログに記録されます。さらに、MySQL 5.6.6 からは、一意のキーまたは主キーが複数含まれているテーブルに対する INSERT ... ON DUPLICATE KEY UPDATE ステートメントも安全ではないとしてマークされます。(Bug #11765650、Bug #58637) セクション17.1.2.1「ステートメントベースおよび行ベースレプリケーションのメリットとデメリット」も参照してください。

MySQL 5.6.6 より前は、テーブルレベルのロックを採用した MyISAM などのストレージエンジンを使用しているパーティション化されたテーブルに対する INSERT ... ON DUPLICATE KEY UPDATE によって、そのテーブルのすべてのパーティションがロックされました。(これは、行レベルロックを採用した InnoDB などのストレージエンジンを使用しているテーブルでは発生しておらず、現在も発生しません。)MySQL 5.6.6 以降では、このようなステートメントでは、パーティション化キーカラムが更新されたパーティションのみがロックされます。詳細は、セクション19.6.4「パーティショニングとロック」を参照してください。

13.2.6 LOAD DATA INFILE 構文

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

LOAD DATA INFILE ステートメントは、非常に高速にテキストファイルからテーブルに行を読み取ります。LOAD DATA INFILE は、SELECT ... INTO OUTFILE を補完するものです。(セクション13.2.9.1「SELECT ... INTO 構文」を参照してください。)テーブルからファイルにデータを書き込むには、SELECT ... INTO OUTFILE を使用します。そのファイルをテーブルに読み戻すには、LOAD DATA INFILE を使用します。FIELDS および LINES 句の構文は、両方のステートメントで同じです。どちらの句もオプションですが、両方が指定される場合は、FIELDSLINES の前に指定する必要があります。

mysqlimport ユーティリティーを使用してデータファイルをロードすることもできます。これは、LOAD DATA INFILE ステートメントをサーバーに送信することによって動作します。--local オプションを指定すると、mysqlimport は、クライアントホストからデータファイルを読み取ります。クライアントとサーバーが圧縮されたプロトコルをサポートしている場合は、--compress オプションを指定すると、低速ネットワーク経由のパフォーマンスを向上させることができます。セクション4.5.5「mysqlimport — データインポートプログラム」を参照してください。

INSERTLOAD DATA INFILE の効率の比較、および LOAD DATA INFILE の高速化の詳細は、セクション8.2.2.1「INSERT ステートメントの速度」を参照してください。

ファイル名は、リテラル文字列として指定する必要があります。Windows では、パス名内のバックスラッシュをスラッシュまたは二重のバックスラッシュとして指定します。character_set_filesystem システム変数は、ファイル名の解釈を制御します。

MySQL 5.6.2 以降では、LOAD DATA は、パーティション、サブパーティション、またはその両方の 1 つ以上の名前のカンマ区切りリストを含む PARTITION オプションを使用した明示的なパーティション選択をサポートしています。このオプションが使用されているとき、リストで指定されているいずれかのパーティションまたはサブパーティションにファイルからの行を挿入できない場合、このステートメントは Found a row not matching the given partition set エラーで失敗します。詳細は、セクション19.5「パーティション選択」を参照してください。

テーブルロックを採用したストレージエンジン (MyISAM など) を使用しているパーティション化されたテーブルの場合、LOAD DATA はどのパーティションロックも削除できません。これは、行レベルロックを採用したストレージエンジン (InnoDB など) を使用しているテーブルには適用されません。詳細は、セクション19.6.4「パーティショニングとロック」を参照してください。

サーバーは、character_set_database システム変数によって示されている文字セットを使用してファイル内の情報を解釈します。SET NAMES や、character_set_client の設定は入力の解釈に影響を与えません。入力ファイルの内容にデフォルトとは異なる文字セットが使用されている場合は、通常、CHARACTER SET 句を使用してそのファイルの文字セットを指定することをお勧めします。binary の文字セットは、変換なしを指定します。

LOAD DATA INFILE は、フィールド値がロードされるカラムのデータ型には関係なく、ファイル内のすべてのフィールドに同じ文字セットが割り当てられていると解釈します。ファイルの内容が正しく解釈されるように、そのファイルが正しい文字セットで書き込まれていることを確認する必要があります。たとえば、mysqldump -T を使用して、または mysqlSELECT ... INTO OUTFILE ステートメントを発行することによってデータファイルを書き込む場合は、そのファイルが LOAD DATA INFILE でロードされるときに使用される文字セットで出力が書き込まれるように、必ず --default-character-set オプションを使用してください。

注記

ucs2utf16utf16le、または utf32 文字セットを使用するデータファイルはロードできません。

LOW_PRIORITY を使用した場合、LOAD DATA ステートメントの実行は、ほかのどのクライアントもそのテーブルから読み取らなくなるまで遅延されます。これは、テーブルレベルロックのみを使用するストレージエンジン (MyISAMMEMORY、および MERGE) にのみ影響を与えます。

並列挿入の条件を満たす (つまり、途中に空きブロックが含まれていない) MyISAM テーブルで CONCURRENT を指定すると、ほかのスレッドは LOAD DATA の実行中にそのテーブルからデータを取得できます。このオプションは、そのテーブルがほかのスレッドから同時に使用されていない場合でも、LOAD DATA のパフォーマンスに少し影響を与えます。

行ベースのレプリケーションでは、CONCURRENT は MySQL バージョンにかかわらずレプリケートされます。ステートメントベースのレプリケーションでは、CONCURRENT は MySQL 5.5.1 より前ではレプリケートされません (Bug #34628 を参照してください)。詳細は、セクション17.4.1.17「レプリケーションと LOAD DATA INFILE」を参照してください。

LOCAL キーワードは、あとで説明されているように、ファイルの予測される場所やエラー処理に影響を与えます。LOCAL は、サーバーとクライアントの両方がそれを許可するように構成されている場合にのみ機能します。たとえば、mysqld--local-infile=0 で起動された場合、LOCAL は機能しません。セクション6.1.6「LOAD DATA LOCAL のセキュリティーの問題」を参照してください。

LOCAL キーワードは、ファイルが見つかることが予測される場所に影響を与えます。

  • LOCAL が指定されている場合、ファイルはクライアントホスト上のクライアントプログラムによって読み取られ、サーバーに送信されます。このファイルは、その正確な場所を指定するためにフルパス名として指定できます。相対パス名として指定されている場合、その名前は、クライアントプログラムが起動されたディレクトリを基準にして解釈されます。

    LOCALLOAD DATA とともに使用している場合は、そのファイルのコピーがサーバーの一時ディレクトリ内に作成されます。これは tmpdir または slave_load_tmpdir の値によって決定されるディレクトリではなく、オペレーティングシステムの一時ディレクトリであり、MySQL Server では構成できません。(システムの一時ディレクトリは通常、Linux システムでは /tmp、Windows では C:\WINDOWS\TEMP です。)このディレクトリ内にコピーのための十分な領域がないと、LOAD DATA LOCAL ステートメントが失敗する場合があります。

  • LOCAL が指定されていない場合、ファイルはサーバーホスト上にある必要があり、直接サーバーによって読み取られます。サーバーは、次のルールを使用してファイルを見つけます。

    • ファイル名が絶対パス名である場合、サーバーはそれを指定されたとおりに使用します。

    • ファイル名が 1 つ以上の先行コンポーネントを含む相対パス名である場合、サーバーは、サーバーのデータディレクトリを基準にしてファイルを検索します。

    • 先行コンポーネントを含まないファイル名が指定されている場合、サーバーは、デフォルトデータベースのデータベースディレクトリ内でそのファイルを探します。

LOCAL 以外のケースでは、これらのルールは、./myfile.txt という名前のファイルがサーバーのデータディレクトリから読み取られるのに対して、myfile.txt として指定されたファイルはデフォルトデータベースのデータベースディレクトリから読み取られることを示します。たとえば、db1 がデフォルトデータベースである場合、次の LOAD DATA ステートメントは、このステートメントが明示的に db2 データベース内のテーブルにファイルをロードしているにもかかわらず、db1 のデータベースディレクトリからファイル data.txt を読み取ります。

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

セキュリティー上の理由から、サーバー上にあるテキストファイルを読み取る場合、そのファイルはデータベースディレクトリ内に存在するか、またはすべてのユーザーから読み取り可能のどちらかである必要があります。また、サーバーファイルに対して LOAD DATA INFILE を使用するには、FILE 権限が必要です。セクション6.2.1「MySQL で提供される権限」を参照してください。LOCAL 以外のロード操作では、secure_file_priv システム変数が空以外のディレクトリ名に設定されている場合、ロードされるファイルはそのディレクトリ内に存在する必要があります。

LOCAL を使用すると、クライアントが接続を経由してファイルの内容をサーバーに送信する必要があるため、サーバーが直接ファイルにアクセスできるようにした場合より少し遅くなります。その一方で、ローカルファイルをロードするために FILE 権限は必要ありません。

LOCAL はまた、エラー処理にも影響を与えます。

  • LOAD DATA INFILE では、データ解釈や重複キーのエラーによって操作が終了します。

  • LOAD DATA LOCAL INFILE では、操作の最中にファイルの転送を停止する方法がサーバーにはないため、データ解釈や重複キーのエラーは警告になり、操作は続行されます。重複キーエラーについては、これは IGNORE が指定されている場合と同じです。IGNORE については、このセクションのあとの方でさらに詳細に説明されています。

REPLACE および IGNORE キーワードは、一意のキー値に関して既存の行を複製する入力行の処理を制御します。

  • REPLACE を指定した場合は、入力行によって既存の行が置き換えられます。つまり、主キーまたは一意のインデックスに関して既存の行と同じ値を持つ行のことです。セクション13.2.8「REPLACE 構文」を参照してください。

  • IGNORE を指定した場合は、一意のキー値に関して既存の行を複製する行は破棄されます。

  • どちらのオプションも指定しない場合、その動作は LOCAL キーワードが指定されているかどうかによって異なります。LOCAL が指定されていない場合は、重複キー値が見つかるとエラーが発生し、テキストファイルの残りは無視されます。LOCAL が指定されている場合、デフォルトの動作は IGNORE が指定されている場合と同じです。これは、操作の最中にファイルの転送を停止する方法がサーバーにはないためです。

ロード操作中に外部キー制約を無視するには、LOAD DATA を実行する前に SET foreign_key_checks = 0 ステートメントを発行します。

空の MyISAM テーブルに対して LOAD DATA INFILE を使用した場合、一意でないインデックスはすべて (REPAIR TABLE として) 別のバッチに作成されます。通常、多くのインデックスがあるときは、この方法で LOAD DATA INFILE がはるかに早くなります。一部の極端なケースでは、ファイルをテーブルにロードする前に ALTER TABLE ... DISABLE KEYS でインデックスを無効にし、ファイルをロードしたあとに ALTER TABLE ... ENABLE KEYS を使用してインデックスを再作成することによって、インデックスをさらに高速に作成できます。セクション8.2.2.1「INSERT ステートメントの速度」を参照してください。

FIELDS および LINES 句の構文は、LOAD DATA INFILESELECT ... INTO OUTFILE の両方のステートメントで同じです。どちらの句もオプションですが、両方が指定される場合は、FIELDSLINES の前に指定する必要があります。

FIELDS 句を指定する場合は、その各サブ句 (TERMINATED BY[OPTIONALLY] ENCLOSED BY、および ESCAPED BY) もオプションです。ただし、そのうちの少なくとも 1 つを指定する必要があります。

FIELDS または LINES 句を指定しない場合、そのデフォルトは、次を記述した場合と同じです。

FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\'
LINES TERMINATED BY '\n' STARTING BY ''

(バックスラッシュは SQL ステートメントの文字列内の MySQL のエスケープ文字であるため、リテラルバックスラッシュを指定するには、1 つのバックスラッシュとして解釈される値に対して 2 つのバックスラッシュを指定する必要があります。エスケープシーケンス '\t''\n' は、それぞれタブと改行文字を指定します。)

つまり、デフォルトでは、入力を読み取るとき LOAD DATA INFILE は次のように機能します。

  • 改行の位置にある行の境界を探します。

  • どの行プリフィクスもスキップしません。

  • タブの位置で行をフィールドに分割します。

  • フィールドが引用文字で囲まれていることを期待しません。

  • 前にエスケープ文字\がある文字をエスケープシーケンスとして解釈します。たとえば、\t\n、および\\はそれぞれ、タブ、改行、およびバックスラッシュを示します。エスケープシーケンスの完全なリストについては、あとの FIELDS ESCAPED BY の説明を参照してください。

逆に、デフォルトでは、出力を書き込むとき SELECT ... INTO OUTFILE は次のように機能します。

  • フィールド間にタブを書き込みます。

  • フィールドを引用文字で囲みません。

  • \を使用して、フィールド値の中に現れるタブ、改行、または\のインスタンスをエスケープします。

  • 行の最後に改行を書き込みます。

注記

Windows システム上でテキストファイルを生成した場合、Windows プログラムは通常、行ターミネータとして 2 文字を使用するため、そのファイルを正しく読み取るには LINES TERMINATED BY '\r\n' の使用が必要になることがあります。WordPad などの一部のプログラムは、ファイルを書き込むときに行ターミネータとして \r を使用する可能性があります。このようなファイルを読み取るには、LINES TERMINATED BY '\r' を使用します。

読み取るすべての行に、無視したい共通のプリフィクスが含まれている場合は、LINES STARTING BY 'prefix_string' を使用して、プリフィクスとその前にあるすべてのものをスキップできます。行にプリフィクスが含まれていない場合は、行全体がスキップされます。たとえば、次のステートメントを発行するとします。

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

データファイルは次のようになっています。

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

結果として得られる行は、("abc",1) および ("def",2) になります。ファイル内の 3 行目は、プリフィクスが含まれていないためスキップされます。

IGNORE number LINES オプションを使用すると、ファイルの先頭にある行を無視できます。たとえば、IGNORE 1 LINES を使用すると、カラム名を含む開始ヘッダー行をスキップできます。

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

SELECT ... INTO OUTFILELOAD DATA INFILE を連携して使用してデータベースからファイルにデータを書き込み、あとでそのファイルを元のデータベースに読み取る場合は、両方のステートメントのフィールド処理と行処理のオプションが一致している必要があります。そうしないと、LOAD DATA INFILE は、そのファイルの内容を正しく解釈しません。SELECT ... INTO OUTFILE を使用して、カンマで区切られたフィールドを含むファイルを書き込むとします。

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

カンマで区切られたファイルを読み戻すための正しいステートメントは次のようになります。

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

代わりに、次に示すステートメントを使用してこのファイルを読み取ろうとしても、これはフィールド間のタブを探すよう LOAD DATA INFILE に指示するため機能しません。

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

その結果、各入力行が 1 つのフィールドとして解釈される可能性があります。

LOAD DATA INFILE を使用すると、外部ソースから取得されたファイルを読み取ることができます。たとえば、多くのプログラムは、各行にカンマで区切られ、二重引用符で囲まれた複数のフィールドが含まれており、かつ開始行がカラム名になっているようなカンマ区切り値 (CSV) 形式でデータをエクスポートできます。このようなファイル内の行が復帰改行と改行のペアで終了している場合、次に示すステートメントは、このファイルをロードするために使用するフィールド処理と行処理のオプションを示しています。

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

入力値が必ずしも引用符で囲まれていない場合は、ENCLOSED BY キーワードの前に OPTIONALLY を使用します。

フィールド処理または行処理のどのオプションにも、空の文字列 ('') を指定できます。空でない場合、FIELDS [OPTIONALLY] ENCLOSED BY および FIELDS ESCAPED BY 値は単一の文字である必要があります。FIELDS TERMINATED BYLINES STARTING BY、および LINES TERMINATED BY 値は、複数の文字にすることができます。たとえば、復帰改行と改行のペアで終了する行を書き込むか、またはこのような行を含むファイルを読み取るには、LINES TERMINATED BY '\r\n' 句を指定します。

%% から成る行で区切られたジョークを含むファイルを読み取るには、次のようにできます。

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 は、フィールドの引用符を制御します。出力 (SELECT ... INTO OUTFILE) でワード OPTIONALLY を省略した場合は、すべてのフィールドが ENCLOSED BY 文字で囲まれます。フィールド区切り文字としてカンマを使用したこのような出力の例を次に示します。

"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"

OPTIONALLY を指定した場合、ENCLOSED BY 文字は、文字列データ型 (CHARBINARYTEXTENUM など) を持つカラムの値を囲むためにのみ使用されます。

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

フィールド値の中に ENCLOSED BY 文字が現れると、その文字は、前に ESCAPED BY 文字を付けることによってエスケープされます。また、空の ESCAPED BY 値を指定した場合は、LOAD DATA INFILE で正しく読み取ることができない出力が誤って生成される可能性もあります。たとえば、エスケープ文字が空である場合、今示した前の出力は次のようになります。4 行目の 2 番目のフィールドに含まれる引用符のあとにカンマが続いていることに注目してください。これにより、このフィールドが (誤って) 終了するように見えます。

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

入力では、ENCLOSED BY 文字 (存在する場合) はフィールド値の最後から取り除かれます。(これは、OPTIONALLY が指定されているかどうかには関係しません。OPTIONALLY は、入力の解釈には影響を与えません。)ENCLOSED BY 文字が ESCAPED BY 文字のあとに現れた場合は、現在のフィールド値の一部として解釈されます。

フィールドが ENCLOSED BY 文字で始まったとき、その文字のインスタンスがフィールド値の終了として認識されるのは、そのあとにフィールドまたは行の TERMINATED BY シーケンスが続いている場合だけです。あいまいさを避けるために、フィールド値の中に ENCLOSED BY 文字が現れるときはそれを 2 文字にすることができ、それがその文字の単一インスタンスとして解釈されます。たとえば、ENCLOSED BY '"' が指定されている場合、引用符は次に示すように処理されます。

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

FIELDS ESCAPED BY は、特殊文字の読み取りまたは書き込みの方法を制御します。

  • 入力では、FIELDS ESCAPED BY 文字が空でない場合、その文字が現れると取り除かれ、それに続く文字がフィールド値の一部として文字どおりに解釈されます。最初の文字がエスケープ文字である一部の 2 文字シーケンスは例外です。これらのシーケンスを (エスケープ文字に\を使用して) 次の表に示します。NULL 処理のルールについては、このセクションのあとの方で説明されています。

    文字エスケープシーケンス
    \0ASCII NUL (0x00) 文字
    \bバックスペース文字
    \n改行 (ラインフィード) 文字
    \r復帰改行文字
    \tタブ文字。
    \ZASCII 26 (Ctrl+Z)
    \NNULL

    \でのエスケープ構文の詳細は、セクション9.1.1「文字列リテラル」を参照してください。

    FIELDS ESCAPED BY 文字が空である場合、エスケープシーケンスの解釈は実行されません。

  • 出力では、FIELDS ESCAPED BY 文字が空でない場合、その文字は、出力上で次の文字の前に付けるために使用されます。

    • FIELDS ESCAPED BY 文字

    • FIELDS [OPTIONALLY] ENCLOSED BY 文字

    • FIELDS TERMINATED BY および LINES TERMINATED BY 値の最初の文字

    • ASCII 0 (エスケープ文字のあとに実際に書き込まれる文字は 0 の値のバイトではなく、ASCII の0です)

    FIELDS ESCAPED BY 文字が空である場合は、どの文字もエスケープされず、NULL\N ではなく、NULL として出力されます。特に、データ内のフィールド値に今指定したリスト内のいずれかの文字が含まれている場合、空のエスケープ文字を指定することはおそらく適切な方法ではありません。

特定のケースでは、フィールド処理と行処理のオプションは相互に作用します。

  • LINES TERMINATED BY が空の文字列であり、かつ FIELDS TERMINATED BY が空以外である場合、行は FIELDS TERMINATED BY でも終了します。

  • FIELDS TERMINATED BYFIELDS ENCLOSED BY の値がどちらも空 ('') である場合は、固定行 (区切られていない) フォーマットが使用されます。固定行フォーマットでは、フィールド間に区切り文字は使用されません (ただし、行ターミネータは引き続き存在できます)。代わりに、カラム値は、そのフィールド内のすべての値を保持するために十分に広いフィールド幅を使用して読み取りと書き込みが行われます。TINYINTSMALLINTMEDIUMINTINT、および BIGINT では、宣言されている表示幅にかかわらず、フィールド幅はそれぞれ 4、6、8、11、および 20 です。

    LINES TERMINATED BY は引き続き、行を区切るために使用されます。ある行にすべてのフィールドが含まれていない場合、カラムの残りの部分はそのデフォルト値に設定されます。行ターミネータが存在しない場合は、これを '' に設定してください。この場合は、テキストファイルの各行にすべてのフィールドが含まれている必要があります。

    固定行フォーマットはまた、あとで説明されているように、NULL 値の処理にも影響を与えます。複数バイトの文字セットを使用している場合は、固定サイズフォーマットが機能しません。

NULL 値の処理は、使用されている FIELDS および LINES オプションによって異なります。

  • デフォルトの FIELDS および LINES 値では、NULL は出力として \N のフィールド値として書き込まれ、\N のフィールド値は入力として NULL として読み取られます (ESCAPED BY 文字は\であると仮定します)。

  • FIELDS ENCLOSED BY が空でない場合、リテラルワード NULL をその値として含むフィールドは NULL 値として読み取られます。これは、文字列 'NULL' として読み取られる、FIELDS ENCLOSED BY 文字で囲まれたワード NULL とは異なります。

  • FIELDS ESCAPED BY が空である場合、NULL はワード NULL として書き込まれます。

  • 固定行フォーマット (これは、FIELDS TERMINATED BYFIELDS ENCLOSED BY がどちらも空であるときに使用されます) では、NULL は空の文字列として書き込まれます。これにより、NULL 値と空の文字列がどちらも空の文字列として書き込まれるため、ファイルに書き込まれた場合、テーブル内でこの両方を区別できなくなります。ファイルを読み戻したときにこの 2 つを区別できることが必要な場合は、固定行フォーマットを使用すべきではありません。

NULLNOT NULL カラムにロードしようとすると、そのカラムのデータ型の暗黙のデフォルト値の割り当てが行われて警告が発生するか、または厳密な SQL モードではエラーが発生します。暗黙のデフォルト値については、セクション11.6「データ型デフォルト値」で説明されています。

次の一部のケースは、LOAD DATA INFILE ではサポートされません。

  • 固定サイズ行 (FIELDS TERMINATED BYFIELDS ENCLOSED BY がどちらも空) および BLOB または TEXT カラム。

  • 別の区切り文字と同じか、または別の区切り文字のプリフィクスである区切り文字を指定した場合、LOAD DATA INFILE は入力を正しく解釈できません。たとえば、次の FIELDS 句では問題が発生します。

    FIELDS TERMINATED BY '"' ENCLOSED BY '"'
  • FIELDS ESCAPED BY が空である場合、フィールド値の中に FIELDS ENCLOSED BY または LINES TERMINATED BY に続いて FIELDS TERMINATED BY 値が現れると、LOAD DATA INFILE はフィールドまたは行の読み取りを非常に早く停止します。これは、LOAD DATA INFILE が、フィールドまたは行の値がどこで終了するかを正しく判定できないために発生します。

次の例では、persondata テーブルのすべてのカラムをロードします。

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

デフォルトでは、LOAD DATA INFILE ステートメントの最後にカラムリストが指定されていないときは、入力行にテーブルカラムごとのフィールドが含まれていることが期待されます。テーブルのカラムの一部のみをロードする場合は、カラムリストを指定します。

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

カラムリストはまた、入力ファイル内のフィールドの順序がテーブル内のカラムの順序と異なる場合にも指定する必要があります。そうしないと、MySQL は、入力フィールドとテーブルカラムを一致させる方法がわかりません。

カラムリストには、カラム名またはユーザー変数のどちらかを含めることができます。ユーザー変数では、SET 句を使用して、各値に対して変換を実行してからその結果をカラムに代入できます。

SET 句内のユーザー変数は、いくつかの方法で使用できます。次の例では、最初の入力カラムを直接 t1.column1 の値に使用し、2 番目の入力カラムを、t1.column2 の値に使用される前に除算演算の対象になるユーザー変数に割り当てます。

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

SET 句を使用すると、入力ファイルからは取得されない値を指定できます。次のステートメントは、column3 を現在の日付と時間に設定します。

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

入力値をユーザー変数に割り当て、その変数をテーブルカラムには代入しないようにして、その値を破棄することもできます。

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

カラム/変数リストと SET 句の使用は、次の制限に従います。

  • SET 句の代入では、割り当て演算子の左側にカラム名のみを置くようにしてください。

  • SET の代入の右側では、サブクエリーを使用できます。カラムに代入される値を返すサブクエリーとして使用できるのは、スカラーサブクエリーだけです。また、サブクエリーを使用して、ロードされているテーブルから選択することはできません。

  • IGNORE 句によって無視された行は、カラム/変数リストや SET 句では処理されません。

  • ユーザー変数には表示幅がないため、固定行フォーマットのデータをロードする場合はユーザー変数を使用できません。

入力行を処理する場合、LOAD DATA はそれをフィールドに分割し、カラム/変数リストと SET 句に応じた値 (存在する場合) を使用します。そのあと、結果として得られる行がテーブルに挿入されます。そのテーブルに BEFORE INSERT または AFTER INSERT トリガーが存在する場合、これらのトリガーはそれぞれ、行挿入の前またはあとにアクティブ化されます。

入力行に含まれるフィールドが多すぎる場合は、余分なフィールドが無視され、警告数が 1 増えます。

入力行に含まれるフィールドが少なすぎる場合、入力フィールドがないテーブルカラムはそのデフォルト値に設定されます。デフォルト値の割り当てについては、セクション11.6「データ型デフォルト値」で説明されています。

空のフィールド値はフィールドがないとは見なされず、次のように解釈されます。

  • 文字列型の場合、このカラムは空の文字列に設定されます。

  • 数値型の場合、このカラムは 0 に設定されます。

  • 日付と時間型の場合、このカラムはその型の適切な0の値に設定されます。セクション11.3「日付と時間型」を参照してください。

これらは、INSERT または UPDATE ステートメントで空の文字列を文字列、数値、日付または時間の各型に明示的に割り当てた場合の結果と同じ値です。

空のフィールド値や正しくないフィールド値の処理は、SQL モードが制限的な値に設定されていると、今説明した処理とは異なってきます。たとえば、sql_mode='TRADITIONAL である場合は、空の値や 'x' などの値を数値カラムに変換すると 0 に変換されるのではなく、エラーが発生します。(LOCAL が指定されている場合は、操作の最中にファイルの転送を停止する方法がサーバーにはないため、制限的な sql_mode 値が設定されていても、エラーではなく警告が発生します。)

TIMESTAMP カラムが現在の日付と時間に設定されるのは、そのカラムに NULL 値 (つまり、\N) が存在し、かつそのカラムが NULL 値を許可するように宣言されていない場合、または TIMESTAMP カラムのデフォルト値が現在のタイムスタンプであり、かつフィールドリストが指定されたときにこのカラムがフィールドリストから省略されている場合だけです。

LOAD DATA INFILE はすべての入力を文字列と見なすため、ENUM または SET カラムの数値を INSERT ステートメントと同じように使用することはできません。ENUM および SET 値はすべて、文字列として指定する必要があります。

BIT 値を、2 進表記 (b'011010' など) を使用してロードすることはできません。これを回避するには、その値を通常の整数として指定し、SET 句を使用して変換することにより、MySQL で数値型の変換が実行され、それが BIT カラムに正しくロードされるようにします。

shell> cat /tmp/bit_test.txt2
127
shell> mysql testmysql> LOAD DATA INFILE '/tmp/bit_test.txt' -> INTO TABLE bit_test (@var1) SET b = CAST(@var1 AS UNSIGNED);Query OK, 2 rows affected (0.00 sec)
Records: 2 Deleted: 0 Skipped: 0 Warnings: 0
mysql> SELECT BIN(b+0) FROM bit_test;+----------+
| bin(b+0) |
+----------+
| 10 |
| 1111111 |
+----------+
2 rows in set (0.00 sec)

Unix では、LOAD DATA でパイプから読み取る必要がある場合は次の手法を使用できます (この例では、/ ディレクトリのリストをテーブル db1.t1 にロードします)。

mkfifo /mysql/data/db1/ls.dat
chmod 666 /mysql/data/db1/ls.dat
find / -ls > /mysql/data/db1/ls.dat &
mysql -e "LOAD DATA INFILE 'ls.dat' INTO TABLE t1" db1

ロードされるデータを生成するコマンドと mysql コマンドを別の端末で実行するか、または (前の例に示したように) バックグラウンドでデータ生成プロセスを実行する必要があります。これを行わないと、データが mysql プロセスから読み取られる準備ができるまで、パイプがブロックされます。

LOAD DATA INFILE ステートメントは、完了すると、次の形式の情報文字列を返します。

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

警告は、INSERT ステートメントを使用して値が挿入されるときと同じ状況で発生します (セクション13.2.5「INSERT 構文」を参照してください)。ただし、LOAD DATA INFILE では、入力行内のフィールドが少なすぎるか、または多すぎる場合にも警告が生成されます。

SHOW WARNINGS を使用すると、発生した問題に関する情報として最初の max_error_count 警告のリストを取得できます。セクション13.7.5.41「SHOW WARNINGS 構文」を参照してください。

C API を使用している場合は、mysql_info() 関数を呼び出すことによって、そのステートメントに関する情報を取得できます。セクション23.7.7.35「mysql_info()」を参照してください。

13.2.7 LOAD XML 構文

LOAD XML [LOW_PRIORITY | CONCURRENT] [LOCAL] INFILE 'file_name' [REPLACE | IGNORE] INTO TABLE [db_name.]tbl_name [PARTITION (partition_name,...)] [CHARACTER SET charset_name] [ROWS IDENTIFIED BY '<tagname>'] [IGNORE number {LINES | ROWS}] [(column_or_user_var,...)] [SET col_name = expr,...]

LOAD XML ステートメントは、XML ファイルからテーブルにデータを読み取ります。file_name は、リテラル文字列として指定する必要があります。オプションの ROWS IDENTIFIED BY 句内の tagname もリテラル文字列として指定し、山括弧 (< および >) で囲む必要があります。

LOAD XML は、XML 出力モードでの mysql クライアントの実行 (つまり、--xml オプションを使用したクライアントの起動) を補完するものとして機能します。テーブルから XML ファイルにデータを書き込むには、システムシェルから次のようなコマンドを使用します。

shell> mysql --xml -e 'SELECT * FROM mytable' > file.xml

そのファイルをテーブルに読み戻すには、LOAD XML INFILE を使用します。デフォルトでは、<row> 要素は、データベーステーブル行と同等であると見なされます。これは、ROWS IDENTIFIED BY 句を使用して変更できます。

このステートメントは、次の 3 つの異なる XML 形式をサポートします。

  • 属性としてのカラム名と、属性値としてのカラム値:

    <rowcolumn1="value1" column2="value2" .../>
  • タグとしてのカラム名と、これらのタグの内容としてのカラム値:

    <row> <column1>value1</column1> <column2>value2</column2>
    </row>
  • カラム名は <field> タグの name 属性で、値はこれらのタグの内容:

    <row> <field name='column1'>value1</field> <field name='column2'>value2</field>
    </row>

    これは、mysqldump などのほかの MySQL ツールによって使用される形式です。

同じ XML ファイルで 3 つのすべての形式を使用できます。インポートルーチンは各行の形式を自動的に検出し、それを正しく解釈します。タグは、タグまたは属性名とカラム名に基づいて照合されます。

次の句は、基本的に LOAD XML に対して LOAD DATA に対する場合と同じように機能します。

  • LOW_PRIORITY または CONCURRENT

  • LOCAL

  • REPLACE または IGNORE

  • PARTITION

  • CHARACTER SET

  • (column_or_user_var,...)

  • SET

これらの句の詳細は、セクション13.2.6「LOAD DATA INFILE 構文」を参照してください。

IGNORE number LINES または IGNORE number ROWS 句を指定すると、XML ファイル内の最初の number 行がスキップされます。これは、LOAD DATA ステートメントの IGNORE ... LINES 句に類似しています。

このステートメントがどのように使用されるかを示すために、次のように作成されたテーブルがあるとします。

USE test;
CREATE TABLE person ( person_id INT NOT NULL PRIMARY KEY, fname VARCHAR(40) NULL, lname VARCHAR(40) NULL, created TIMESTAMP
);

さらに、このテーブルが最初は空であるとします。

ここで、次に示すような内容を持つ単純な XML ファイル person.xml があるとします。

<?xml version="1.0"?>
<list> <person person_id="1" fname="Pekka" lname="Nousiainen"/> <person person_id="2" fname="Jonas" lname="Oreland"/> <person person_id="3"><fname>Mikael</fname><lname>Ronström</lname></person> <person person_id="4"><fname>Lars</fname><lname>Thalmann</lname></person> <person><field name="person_id">5</field><field name="fname">Tomas</field> <field name="lname">Ulin</field></person> <person><field name="person_id">6</field><field name="fname">Martin</field> <field name="lname">Sköld</field></person>
</list>

例として示したこのファイルには、前に説明した許可される各 XML 形式が表されています。

person.xml 内のデータを person テーブルにインポートするには、次のステートメントを使用できます。

mysql> LOAD XML LOCAL INFILE 'person.xml' -> INTO TABLE person -> ROWS IDENTIFIED BY '<person>';Query OK, 6 rows affected (0.00 sec)
Records: 6 Deleted: 0 Skipped: 0 Warnings: 0

ここでは、person.xml が MySQL データディレクトリ内に存在することを前提にしています。このファイルが見つからない場合は、次のエラーが発生します。

ERROR 2 (HY000): File '/person.xml' not found (Errcode: 2)

ROWS IDENTIFIED BY '<person>' 句は、XML ファイル内の各 <person> 要素が、このデータがインポートされるテーブル内の各行と同等であると見なされることを示します。この場合、これは test データベース内の person テーブルです。

サーバーからの応答でわかるように、test.person テーブルには 6 行がインポートされました。これは、単純な SELECT ステートメントで確認できます。

mysql> SELECT * FROM person;+-----------+--------+------------+---------------------+
| person_id | fname | lname | created |
+-----------+--------+------------+---------------------+
| 1 | Pekka | Nousiainen | 2007-07-13 16:18:47 |
| 2 | Jonas | Oreland | 2007-07-13 16:18:47 |
| 3 | Mikael | Ronström | 2007-07-13 16:18:47 |
| 4 | Lars | Thalmann | 2007-07-13 16:18:47 |
| 5 | Tomas | Ulin | 2007-07-13 16:18:47 |
| 6 | Martin | Sköld | 2007-07-13 16:18:47 |
+-----------+--------+------------+---------------------+
6 rows in set (0.00 sec)

このセクションの前の方で説明したように、許可される 3 つの XML 形式のいずれかまたはすべてを 1 つのファイルに含め、それを LOAD XML を使用して読み取ることができます。

上の操作の逆、つまり、MySQL テーブルデータの XML ファイルへのダンプは、次に示すように、システムシェルから mysql クライアントを使用して実現できます。

注記

--xml オプションを指定すると、mysql クライアントは、その出力として XML 形式を使用します。-e オプションを指定すると、クライアントはそのオプションの直後にある SQL ステートメントを実行します。

shell> mysql --xml -e "SELECT * FROM test.person" > person-dump.xmlshell> cat person-dump.xml<?xml version="1.0"?>
<resultset statement="SELECT * FROM test.person" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <row> <field name="person_id">1</field> <field name="fname">Pekka</field> <field name="lname">Nousiainen</field> <field name="created">2007-07-13 16:18:47</field> </row> <row> <field name="person_id">2</field> <field name="fname">Jonas</field> <field name="lname">Oreland</field> <field name="created">2007-07-13 16:18:47</field> </row> <row> <field name="person_id">3</field> <field name="fname">Mikael</field> <field name="lname">Ronström</field> <field name="created">2007-07-13 16:18:47</field> </row> <row> <field name="person_id">4</field> <field name="fname">Lars</field> <field name="lname">Thalmann</field> <field name="created">2007-07-13 16:18:47</field> </row> <row> <field name="person_id">5</field> <field name="fname">Tomas</field> <field name="lname">Ulin</field> <field name="created">2007-07-13 16:18:47</field> </row> <row> <field name="person_id">6</field> <field name="fname">Martin</field> <field name="lname">Sköld</field> <field name="created">2007-07-13 16:18:47</field> </row>
</resultset>

次のように、person のコピーを作成したあと、ダンプファイルを新しいテーブルにインポートすることによって、このダンプが有効であることを確認できます。

mysql> USE test;mysql> CREATE TABLE person2 LIKE person;Query OK, 0 rows affected (0.00 sec)
mysql> LOAD XML LOCAL INFILE 'person-dump.xml' -> INTO TABLE person2;Query OK, 6 rows affected (0.01 sec)
Records: 6 Deleted: 0 Skipped: 0 Warnings: 0
mysql> SELECT * FROM person2;+-----------+--------+------------+---------------------+
| person_id | fname | lname | created |
+-----------+--------+------------+---------------------+
| 1 | Pekka | Nousiainen | 2007-07-13 16:18:47 |
| 2 | Jonas | Oreland | 2007-07-13 16:18:47 |
| 3 | Mikael | Ronström | 2007-07-13 16:18:47 |
| 4 | Lars | Thalmann | 2007-07-13 16:18:47 |
| 5 | Tomas | Ulin | 2007-07-13 16:18:47 |
| 6 | Martin | Sköld | 2007-07-13 16:18:47 |
+-----------+--------+------------+---------------------+
6 rows in set (0.00 sec)

ROWS IDENTIFIED BY '<tagname>' 句を使用すると、同じ XML ファイルのデータを定義の異なるデータベーステーブルにインポートできます。この例では、次の XML を含む address.xml という名前のファイルがあるとします。

<?xml version="1.0"?>
<list> <person person_id="1"> <fname>Robert</fname> <lname>Jones</lname> <address address_id="1" street="Mill Creek Road" zip="45365" city="Sidney"/> <address address_id="2" street="Main Street" zip="28681" city="Taylorsville"/> </person> <person person_id="2"> <fname>Mary</fname> <lname>Smith</lname> <address address_id="3" street="River Road" zip="80239" city="Denver"/> <!-- <address address_id="4" street="North Street" zip="37920" city="Knoxville"/> --> </person>
</list>

ここでも、このセクションで前に定義された test.person テーブルを使用できます。テーブルの既存のすべてのレコードをクリアしたあと、次に示すようにその構造を表示します。

mysql< TRUNCATE person;Query OK, 0 rows affected (0.04 sec)
mysql< SHOW CREATE TABLE person\G*************************** 1. row *************************** Table: person
Create Table: CREATE TABLE `person` ( `person_id` int(11) NOT NULL, `fname` varchar(40) DEFAULT NULL, `lname` varchar(40) DEFAULT NULL, `created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`person_id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1
1 row in set (0.00 sec)

次に、次の CREATE TABLE ステートメントを使用して、test データベース内に address テーブルを作成します。

CREATE TABLE address ( address_id INT NOT NULL PRIMARY KEY, person_id INT NULL, street VARCHAR(40) NULL, zip INT NULL, city VARCHAR(40) NULL, created TIMESTAMP
);

XML ファイルのデータを person テーブルにインポートするには、次に示すように、行が <person> 要素で指定されるように指定する次の LOAD XML ステートメントを実行します。

mysql> LOAD XML LOCAL INFILE 'address.xml' -> INTO TABLE person -> ROWS IDENTIFIED BY '<person>';Query OK, 2 rows affected (0.00 sec)
Records: 2 Deleted: 0 Skipped: 0 Warnings: 0

SELECT ステートメントを使用して、レコードがインポートされたことを確認できます。

mysql> SELECT * FROM person;+-----------+--------+-------+---------------------+
| person_id | fname | lname | created |
+-----------+--------+-------+---------------------+
| 1 | Robert | Jones | 2007-07-24 17:37:06 |
| 2 | Mary | Smith | 2007-07-24 17:37:06 |
+-----------+--------+-------+---------------------+
2 rows in set (0.00 sec)

XML ファイル内の <address> 要素は、person テーブル内に対応するカラムがないためスキップされます。

<address> 要素のデータを address テーブルにインポートするには、次に示す LOAD XML ステートメントを使用します。

mysql> LOAD XML LOCAL INFILE 'address.xml' -> INTO TABLE address -> ROWS IDENTIFIED BY '<address>';Query OK, 3 rows affected (0.00 sec)
Records: 3 Deleted: 0 Skipped: 0 Warnings: 0

次のような SELECT ステートメントを使用して、データがインポートされたこと確認できます。

mysql> SELECT * FROM address;+------------+-----------+-----------------+-------+--------------+---------------------+
| address_id | person_id | street | zip | city | created |
+------------+-----------+-----------------+-------+--------------+---------------------+
| 1 | 1 | Mill Creek Road | 45365 | Sidney | 2007-07-24 17:37:37 |
| 2 | 1 | Main Street | 28681 | Taylorsville | 2007-07-24 17:37:37 |
| 3 | 2 | River Road | 80239 | Denver | 2007-07-24 17:37:37 |
+------------+-----------+-----------------+-------+--------------+---------------------+
3 rows in set (0.00 sec)

<address> 要素のデータのうち、XML コメントで囲まれているものはインポートされません。ただし、address テーブルには person_id カラムがあるため、各 <address> に対する親の <person> 要素の person_id 属性の値は address テーブルにインポートされます

セキュリティー上の考慮事項 LOAD DATA ステートメントと同様に、クライアントホストからサーバーホストへの XML ファイルの転送は MySQL サーバーによって開始されます。理論上は、LOAD XML ステートメント内でクライアントによって指定されたファイルではなく、サーバーが選択したファイルを転送するようにクライアントプログラムに指示する、パッチが適用されたサーバーを構築できます。そのようなサーバーは、クライアントユーザーが読み取りアクセス権を持つクライアントホスト上のすべてのファイルにアクセスできます。

Web 環境では、クライアントは通常、Web サーバーから MySQL に接続します。MySQL サーバーに対して任意のコマンドを実行できるユーザーは、LOAD XML LOCAL を使用して、Web サーバープロセスが読み取りアクセス権を持つどのファイルでも読み取ることができます。この環境では、そのクライアントは MySQL サーバーに対して、Web サーバーに接続するユーザーによって実行されているリモートプログラムではなく、実際に Web サーバーです。

--local-infile=0 または --local-infile=OFF を使用してサーバーを起動することによって、クライアントからの XML ファイルのロードを無効にすることができます。このオプションはまた、クライアントセッションの期間中は LOAD XML を無効にするように mysql クライアントを起動する場合にも使用できます。

クライアントがサーバーから XML ファイルをロードしないようにするために、対応する MySQL ユーザーアカウントには FILE 権限を付与しないようにするか、またはクライアントユーザーアカウントがすでにこの権限を持っている場合は取り消してください。

重要

FILE 権限を取り消した (または、最初から付与しない) 場合、そのユーザーは LOAD XML INFILE ステートメント (および LOAD_FILE() 関数) を実行できなくなるだけです。LOAD XML LOCAL INFILE の実行は妨げられません。このステートメントを禁止するには、サーバーまたはクライアントを --local-infile=OFF で起動する必要があります。

つまり、FILE 権限は、そのクライアントがサーバー上のファイルを読み取れるかどうかにのみ影響を与えます。そのクライアントがローカルファイルシステム上のファイルを読み取れるかどうかには関係しません。

テーブルロックを採用したストレージエンジン (MyISAM など) を使用しているパーティション化されたテーブルの場合、LOAD XML はどのパーティションロックもプルーニングできません。これは、行レベルロックを採用したストレージエンジン (InnoDB など) を使用しているテーブルには適用されません。詳細は、セクション19.6.4「パーティショニングとロック」を参照してください。

13.2.8 REPLACE 構文

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

または:

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

または:

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

REPLACE は、INSERT とまったく同じように機能します。ただし、テーブル内の古い行に、PRIMARY KEY または UNIQUE インデックスに関して新しい行と同じ値が含まれている場合、その古い行は新しい行が挿入される前に削除されます。セクション13.2.5「INSERT 構文」を参照してください。

REPLACE は、SQL 標準への MySQL 拡張です。これは挿入を行うか、または削除と挿入を行います。標準 SQL への別の MySQL 拡張 (挿入または更新を行います) については、セクション13.2.5.3「INSERT ... ON DUPLICATE KEY UPDATE 構文」を参照してください。

テーブルに PRIMARY KEY または UNIQUE インデックスが存在しないかぎり、REPLACE ステートメントを使用しても何も意味がありません。新しい行が別の行を複製したかどうかを判定するために使用されるインデックスが存在しないため、それは INSERT と同等になります。

すべてのカラムの値が REPLACE ステートメントで指定されている値から取得されます。カラムがない場合は、INSERT での処理と同様に、そのカラムはそのデフォルト値に設定されます。現在の行の値を参照し、それを新しい行で使用することはできません。SET col_name = col_name + 1 などの代入を使用した場合、右側にあるカラム名への参照は DEFAULT(col_name) として処理されるため、この代入は SET col_name = DEFAULT(col_name) + 1 と同等です。

REPLACE を使用するには、このテーブルに対する INSERT 権限と DELETE 権限の両方が必要です。

MySQL 5.6.2 から、REPLACE は、パーティション、サブパーティション、またはその両方の名前のカンマ区切りリストを含む PARTITION オプションを使用した明示的なパーティション選択をサポートしています。INSERT と同様に、これらのいずれかのパーティションまたはサブパーティションに新しい行を挿入できない場合、REPLACE ステートメントは Found a row not matching the given partition set.エラーで失敗します。詳細は、セクション19.5「パーティション選択」を参照してください。

REPLACE は、影響を受けた行数を示す数を返します。これは、削除された行と挿入された行の合計です。この数が単一行の REPLACE に対して 1 である場合は、行が挿入され、削除された行はありませんでした。この数が 1 より大きい場合は、新しい行が挿入される前に 1 つ以上の古い行が削除されました。テーブルに複数の一意のインデックスが存在するときに、新しい行が異なる一意のインデックス内の別の古い行の値を複製した場合は、単一行が複数の古い行を置き換えることがあります。

影響を受けた行数により、REPLACE が行を追加しただけか、または行の置き換えも行なったかを判定することが容易になります。その数が 1 (追加した) か、またはそれより大きい (置き換えた) かをチェックします。

C API を使用している場合は、mysql_affected_rows() 関数を使用して、影響を受けた行数を取得できます。

現在、テーブルへの置き換えを行い、さらにサブクエリーで同じテーブルから選択することはできません。

MySQL は、REPLACE (および LOAD DATA ... REPLACE) に次のアルゴリズムを使用します。

  1. テーブルへの新しい行の挿入を試みます

  2. 主キーまたは一意のインデックスに関する重複キーエラーが発生したために挿入が失敗している間、次のことを行います。

    1. 重複キー値を含む競合している行をテーブルから削除します

    2. テーブルへの新しい行の挿入を再試行します

重複キーエラーが発生した場合、ストレージエンジンが削除と挿入ではなく、更新として REPLACE を実行する可能性がありますが、そのセマンティクスは同じです。ストレージエンジンが Handler_xxx ステータス変数を増分する方法が異なる可能性がある以外、ユーザーに見える影響はありません。

REPLACE ... SELECT ステートメントの結果は SELECT からの行の順序に依存し、またこの順序を常に保証することはできないため、ロギング時に、これらのステートメントがマスターとスレーブで異なる可能性があります。このため、MySQL 5.6.4 以降では、REPLACE ... SELECT ステートメントには、ステートメントベースのレプリケーションには安全でないというフラグが付けられます。この変更により、このようなステートメントは、STATEMENT バイナリロギングモードを使用しているときはログ内に警告を生成し、MIXED モードを使用しているときは行ベース形式を使用してログに記録されます。セクション17.1.2.1「ステートメントベースおよび行ベースレプリケーションのメリットとデメリット」も参照してください。

パーティション化されていない既存のテーブルをパーティション化に対応するように変更しているときや、すでにパーティション化されたテーブルのパーティション化を変更しているときに、そのテーブルの主キーの変更を検討する可能性があります (セクション19.6.1「パーティショニングキー、主キー、および一意キー」を参照してください)。これを行うと、パーティション化されていないテーブルの主キーを変更した場合と同様に、REPLACE ステートメントの結果が影響を受ける可能性があります。次の CREATE TABLE ステートメントによって作成されたテーブルを考えてみます。

CREATE TABLE test ( id INT UNSIGNED NOT NULL AUTO_INCREMENT, data VARCHAR(64) DEFAULT NULL, ts TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id)
);

このテーブルを作成し、mysql クライアントに示されているステートメントを実行すると、結果は次のようになります。

mysql> REPLACE INTO test VALUES (1, 'Old', '2014-08-20 18:47:00');Query OK, 1 row affected (0.04 sec)
mysql> REPLACE INTO test VALUES (1, 'New', '2014-08-20 18:47:42');Query OK, 2 rows affected (0.04 sec)
mysql> SELECT * FROM test;
+----+------+---------------------+
| id | data | ts |
+----+------+---------------------+
| 1 | New | 2014-08-20 18:47:42 |
+----+------+---------------------+
1 row in set (0.00 sec)

ここで、次に示すように (強調表示されたテキスト) 主キーが 2 つのカラムになっている点を除き、最初のテーブルとほぼ同一の 2 番目のテーブルを作成します。

CREATE TABLE test2 ( id INT UNSIGNED NOT NULL AUTO_INCREMENT, data VARCHAR(64) DEFAULT NULL, ts TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id, ts));

元の test テーブルに対して実行したのと同じ 2 つの REPLACE ステートメントを test2 に対して実行すると、異なる結果が得られます。

mysql> REPLACE INTO test2 VALUES (1, 'Old', '2014-08-20 18:47:00');Query OK, 1 row affected (0.05 sec)
mysql> REPLACE INTO test2 VALUES (1, 'New', '2014-08-20 18:47:42');Query OK, 1 row affected (0.06 sec)
mysql> SELECT * FROM test2;+----+------+---------------------+
| id | data | ts |
+----+------+---------------------+
| 1 | Old | 2014-08-20 18:47:00 |
| 1 | New | 2014-08-20 18:47:42 |
+----+------+---------------------+
2 rows in set (0.00 sec)

これは、test2 に対して実行した場合は id カラムと ts カラムの両方の値が、置き換えられる行に対する既存の行の値に一致している必要があり、そうでないと行が挿入されるためです。

MySQL 5.6.6 より前は、テーブルレベルのロックを採用した MyISAM などのストレージエンジンを使用しているパーティション化されたテーブルに影響を与える REPLACE によって、そのテーブルのすべてのパーティションがロックされました。これは、REPLACE ... PARTITION ステートメントにも当てはまりました。(これは、行レベルロックを採用した InnoDB などのストレージエンジンでは発生しておらず、現在も発生しません。)MySQL 5.6.6 以降では、MySQL はパーティションロックプルーニングを使用します。これにより、そのテーブルのどのパーティション化カラムも更新されないかぎり、REPLACE ステートメントの WHERE 句に一致する行を含むパーティションだけが実際にロックされるようになります。そうでなければ、テーブル全体がロックされます。詳細は、セクション19.6.4「パーティショニングとロック」を参照してください。

13.2.9 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 [, select_expr ...] [FROM table_references [PARTITION partition_list] [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' [CHARACTER SET charset_name] export_options | INTO DUMPFILE 'file_name' | INTO var_name [, var_name]] [FOR UPDATE | LOCK IN SHARE MODE]]

SELECT は、1 つ以上のテーブルから選択された行を取得するために使用され、UNION ステートメントとサブクエリーを含めることができます。セクション13.2.9.4「UNION 構文」およびセクション13.2.10「サブクエリー構文」を参照してください。

SELECT ステートメントのもっとも一般的に使用される句は次のとおりです。

  • select_expr は、取得するカラムを示します。少なくとも 1 つの select_expr が存在する必要があります。

  • table_references は、行を取得する 1 つまたは複数のテーブルを示します。その構文については、セクション13.2.9.2「JOIN 構文」で説明されています。

  • MySQL 5.6.2 から、SELECT は、table_reference 内のテーブル名のあとにパーティションまたはサブパーティション (またはその両方) のリストを含む PARTITION キーワードを使用した明示的なパーティション選択をサポートしています (セクション13.2.9.2「JOIN 構文」を参照してください)。この場合、行はリストされているパーティションからのみ選択され、テーブルのほかのパーティションはすべて無視されます。詳細および例については、セクション19.5「パーティション選択」を参照してください。

    MySQL 5.6.6 以降では、テーブルレベルのロック (つまり、パーティションロック) を実行する MyISAM などのストレージエンジンを使用しているテーブルからの SELECT ... PARTITION では、PARTITION オプションで指定されているパーティションまたはサブパーティションのみがロックされます。

    詳細は、セクション19.6.4「パーティショニングとロック」を参照してください。

  • WHERE 句 (指定されている場合) は、選択されるために行が満たす必要のある 1 つまたは複数の条件を示します。where_condition は、選択される各行に対して true に評価される式です。WHERE 句がない場合、このステートメントはすべての行を選択します。

    WHERE 式では、集約 (サマリー) 関数を除き、MySQL がサポートするすべての関数および演算子を使用できます。セクション9.5「式の構文」および第12章「関数と演算子を参照してください。

SELECT を使用して、どのテーブルも参照せずに計算された行を取得することもできます。

例:

mysql> SELECT 1 + 1; -> 2

テーブルが参照されない状況では、ダミーのテーブル名として DUAL を指定することが許可されます。

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

DUAL は純粋に、すべての SELECT ステートメントに FROM や、場合によってはその他の句が存在することを要求するユーザーの便宜のために用意されています。MySQL は、これらの句を無視する可能性があります。MySQL では、テーブルが参照されない場合でも FROM DUAL は必要ありません。

一般に、使用される句は、正確に構文の説明で示されている順序で指定する必要があります。たとえば、HAVING 句は、すべての GROUP BY 句のあとで、かつすべての ORDER BY 句の前にある必要があります。例外として、INTO 句は、構文の説明で示されている位置か、または select_expr リストの直後のどちらにも現れることができます。INTO の詳細は、セクション13.2.9.1「SELECT ... INTO 構文」を参照してください。

select_expr 項のリストは、どのカラムを取得するかを示す選択リストで構成されています。これらの項はカラムや式を指定するか、または * の短縮形を使用できます。

  • 1 つの修飾されていない * のみから成る選択リストは、すべてのテーブルのすべてのカラムを選択するための短縮形として使用できます。

    SELECT * FROM t1 INNER JOIN t2 ...
  • tbl_name.* は、指定されたテーブルのすべてのカラムを選択するための修飾された短縮形として使用できます。

    SELECT t1.*, t2.* FROM t1 INNER JOIN t2 ...
  • 修飾されていない * を選択リスト内のほかの項目とともに使用すると、解析エラーが生成される可能性があります。この問題を回避するには、修飾された tbl_name.* 参照を使用します。

    SELECT AVG(score), t1.* FROM t1 ...

次のリストは、その他の SELECT 句に関する追加情報を示しています。

  • AS alias_name を使用して、select_expr にエイリアスを指定できます。エイリアスは式のカラム名として使用され、GROUP BYORDER BY、または HAVING 句で使用できます。例:

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

    select_expr にエイリアスとして識別子を指定する場合、AS キーワードはオプションです。前の例は、次のように記述することもできました。

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

    ただし、AS はオプションであるため、2 つの select_expr 式の間のカンマを忘れると、軽微な問題が発生する可能性があります。MySQL は、2 番目の式をエイリアスとして解釈します。たとえば、次のステートメントでは、columnb はエイリアスとして処理されます。

    SELECT columna columnb FROM mytable;

    このため、カラムのエイリアスを指定するときは AS を明示的に使用するようにすることをお勧めします。

    WHERE 句が実行されるときはまだカラム値が決定されていない可能性があるため、WHERE 句内でカラムのエイリアスを参照することは許可されません。セクションB.5.5.4「カラムエイリアスに関する問題」を参照してください。

  • FROM table_references 句は、行を取得する 1 つまたは複数のテーブルを示します。複数のテーブルを指定すると、結合が実行されます。結合構文については、セクション13.2.9.2「JOIN 構文」を参照してください。指定されたテーブルごとに、オプションでエイリアスを指定できます。

    tbl_name [[AS] alias] [index_hint]

    インデックスヒントを使用すると、クエリー処理中にインデックスを選択する方法に関する情報がオプティマイザに提供されます。これらのヒントを指定するための構文については、セクション13.2.9.3「インデックスヒントの構文」を参照してください。

    代わりの方法として SET max_seeks_for_key=value を使用して、MySQL にテーブルスキャンの代わりにキースキャンを強制的に実行させることができます。セクション5.1.4「サーバーシステム変数」を参照してください。

  • データベースを明示的に指定するために、デフォルトデータベース内でテーブルを tbl_name または db_name.tbl_name として参照できます。カラムを col_nametbl_name.col_name または db_name.tbl_name.col_name として参照できます。参照があいまいにならないかぎり、カラム参照のために tbl_name または db_name.tbl_name プリフィクスを指定する必要はありません。より明示的なカラム参照形式を必要とするあいまいさの例については、セクション9.2.1「識別子の修飾子」を参照してください。

  • tbl_name AS alias_name または tbl_name alias_name を使用して、テーブル参照にエイリアスを指定できます。

    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;
  • カラム名、カラムのエイリアス、またはカラム位置を使用して、出力のために選択されたカラムを ORDER BY および GROUP BY 句で参照できます。カラム位置は整数であり、1 から始まります。

    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;

    逆の順序でソートするには、ソートに使用する ORDER BY 句内のカラムの名前に DESC (降順) キーワードを追加します。デフォルトは昇順です。これは、ASC キーワードを使用して明示的に指定できます。

    ORDER BY がサブクエリー内で発生し、外側のクエリー内でも適用される場合は、もっとも外側の ORDER BY が優先されます。たとえば、次のステートメントの結果は昇順ではなく、降順でソートされます。

    (SELECT ... ORDER BY a) ORDER BY a DESC;

    カラム位置の使用は、この構文が SQL 標準から削除されたため非推奨です。

  • GROUP BY を使用すると、出力行は、同じカラムに対して ORDER BY を指定したかのように GROUP BY カラムに従ってソートされます。GROUP BY によって生成されるソートのオーバーヘッドを回避するには、ORDER BY NULL を追加します。

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

    MySQL 5.6 における暗黙の GROUP BY ソートへの依存は、非推奨になっています。グループ化された結果の特定のソート順序を実現するには、明示的な ORDER BY 句を使用することをお勧めします。GROUP BY ソートは、たとえば、オプティマイザがもっとも効率的であると考えるどのような方法でも、グループ化を指示できるようにしたり、ソートオーバーヘッドを回避したりするためなどに、今後のリリースで変更される可能性のある MySQL 拡張機能です。

  • MySQL では GROUP BY 句が拡張され、この句で指定されているカラムのあとに ASCDESC も指定できるようになっています。

    SELECT a, COUNT(b) FROM test_table GROUP BY a DESC;
  • MySQL では、GROUP BY の使用が、GROUP BY 句で指定されていないフィールドの選択を許可するように拡張されています。クエリーから期待する結果が得られない場合は、セクション12.19「GROUP BY 句で使用される関数と修飾子」にある GROUP BY の説明を参照してください。

  • GROUP BY では、WITH ROLLUP 修飾子が許可されます。セクション12.19.2「GROUP BY 修飾子」を参照してください。

  • HAVING 句は、ほぼ最後 (項目がクライアントに送信される直前) に最適化なしで適用されます。(LIMITHAVING のあとに適用されます。)

    SQL 標準では、HAVINGGROUP BY 句内のカラムか、または集約関数で使用されるカラムしか参照できません。ただし、MySQL ではこの動作への拡張がサポートされており、HAVINGSELECT リスト内のカラムや外側サブクエリー内のカラムを参照することも許可されます。

    HAVING 句があいまいなカラムを参照している場合は、警告が発生します。次のステートメントにある col2 は、エイリアスとカラム名の両方として使用されているため、あいまいです。

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

    標準 SQL の動作の方が優先されるため、HAVING のカラム名が GROUP BY で使用されると同時に、出力カラムリスト内のエイリアスが指定されたカラムとしても使用されている場合は、GROUP BY カラム内のカラムが優先されます。

  • WHERE 句に含めるべき項目には HAVING を使用しないでください。たとえば、次のように記述しないでください。

    SELECT col_name FROM tbl_name HAVING col_name > 0;

    代わりに、次のように記述してください。

    SELECT col_name FROM tbl_name WHERE col_name > 0;
  • HAVING 句は、WHERE 句が参照できない集約関数を参照できます。

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

    (これは、一部の古いバージョンの MySQL では機能しませんでした。)

  • MySQL では、重複したカラム名が許可されます。つまり、同じ名前を持つ複数の select_expr が存在できます。これは、標準 SQL の拡張です。MySQL では GROUP BYHAVINGselect_expr 値を参照することも許可されるため、これにより、あいまいさが発生する場合があります。

    SELECT 12 AS a, a FROM t GROUP BY a;

    このステートメントでは、どちらのカラムの名前も a です。グループ化のために正しいカラムが使用されるようにするために、select_expr ごとに異なる名前を使用してください。

  • MySQL は、ORDER BY 句内の修飾されていないカラムまたはエイリアス参照を、まず select_expr 値、次に FROM 句内のテーブルのカラム内を検索することによって解決します。GROUP BY または HAVING 句の場合は、select_expr 値内を検索する前に FROM 句を検索します。(GROUP BYHAVING について、これは、ORDER BY) の場合と同じルールを使用していた MySQL 5.0 より前の動作とは異なります。

  • LIMIT 句を使用すると、SELECT ステートメントによって返される行数を制約できます。LIMIT は 1 つまたは 2 つの数値引数を受け取ります。これは、どちらも負ではない整定数である必要があります。ただし、次の例外があります。

    • 準備済みステートメント内では、? プレースホルダマーカーを使用して LIMIT パラメータを指定できます。

    • ストアドプログラム内では、整数値のルーチンパラメータまたはローカル変数を使用して LIMIT パラメータを指定できます。

    引数が 2 つの場合、最初の引数は返す先頭行のオフセットを指定し、2 番目の引数は返す行の最大数を指定します。最初の行のオフセットは (1 ではなく) 0 です。

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

    特定のオフセットから結果セットの最後までのすべての行を取得するために、2 番目のパラメータにある程度大きい数字を使用できます。次のステートメントは、96 行目から最後の行までのすべての行を取得します。

    SELECT * FROM tbl LIMIT 95,18446744073709551615;

    引数が 1 つの場合、この値は、結果セットの先頭から返す行数を指定します。

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

    つまり、LIMIT row_countLIMIT 0, row_count と同等です。

    準備済みステートメントでは、プレースホルダを使用できます。次のステートメントは、tbl テーブルの 1 行を返します。

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

    次のステートメントは、tbl テーブルの 2 行目から 6 行目までを返します。

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

    PostgreSQL との互換性のために、MySQL は LIMIT row_count OFFSET offset 構文もサポートしています。

    LIMIT がサブクエリー内に現れ、また外部クエリーでも適用される場合は、もっとも外側の LIMIT が優先されます。たとえば、次のステートメントは、1 行ではなく 2 行を生成します。

    (SELECT ... LIMIT 1) LIMIT 2;
  • PROCEDURE 句は、結果セット内のデータを処理するプロシージャーを指定します。例については、セクション8.4.2.4「PROCEDURE ANALYSE の使用」を参照してください。ここでは、テーブルサイズの削減に役立つ可能性のある最適なカラムデータ型に関する提案を得るために使用できるプロシージャーである ANALYSE について説明しています。

  • SELECTSELECT ... INTO 形式を使用すると、クエリー結果をファイルに書き込んだり、変数に格納したりできます。詳細は、セクション13.2.9.1「SELECT ... INTO 構文」を参照してください。

  • ページまたは行ロックを使用するストレージエンジンで FOR UPDATE を使用した場合、クエリーによって検査される行は、現在のトランザクションの最後まで書き込みがロックされます。LOCK IN SHARE MODE を使用すると、その検査される行のほかのトランザクションによる読み取りは許可するが、その更新または削除を許可しない共有ロックが設定されます。セクション14.2.5「ロック読み取り (SELECT ... FOR UPDATE および SELECT ... LOCK IN SHARE MODE)」を参照してください。

    さらに、CREATE TABLE new_table SELECT ... FROM old_table ... などのステートメントで SELECT の一部として FOR UPDATE を使用することはできません。(それを行おうとすると、このステートメントはエラー Can't update table 'old_table' while 'new_table' is being created で拒否されます。)これは、CREATE TABLE ... SELECT ステートメントが作成されているテーブル以外のテーブルで変更を行うことを許可していた、MySQL 5.5 およびそれ以前からの動作の変更です。

SELECT キーワードのあとに、このステートメントの操作に影響を与えるいくつかのオプションを使用できます。HIGH_PRIORITYSTRAIGHT_JOIN、および SQL_ で始まるオプションは、標準 SQL への MySQL 拡張です。

  • ALL および DISTINCT オプションは、重複した行を返すかどうかを指定します。ALL (デフォルト) は、重複を含め、一致するすべての行を返すように指定します。DISTINCT は、重複した行の結果セットからの削除を指定します。両方のオプションを指定するとエラーになります。DISTINCTROWDISTINCT のシノニムです。

  • HIGH_PRIORITYSELECT に、テーブルを更新するステートメントより高い優先度を与えます。これは、非常に高速であり、かつただちに実行する必要のあるクエリーにのみ使用するようにしてください。テーブルが読み取りに対してロックされている間に発行された SELECT HIGH_PRIORITY クエリーは、そのテーブルが未使用になるのを待機している更新ステートメントが存在する場合でも実行されます。これは、テーブルレベルロックのみを使用するストレージエンジン (MyISAMMEMORY、および MERGE) にのみ影響を与えます。

    HIGH_PRIORITY を、UNION の一部である SELECT ステートメントで使用することはできません。

  • STRAIGHT_JOIN は、オプティマイザに、テーブルを FROM 句にリストされている順序で強制的に結合させます。オプティマイザがテーブルを最適でない順序で結合する場合は、これを使用してクエリーを高速化できます。STRAIGHT_JOIN はまた、table_references リストでも使用できます。セクション13.2.9.2「JOIN 構文」を参照してください。

    STRAIGHT_JOIN は、オプティマイザが const テーブルまたは system テーブルとして処理するテーブルには適用されません。このようなテーブルは単一行を生成し、クエリー実行の最適化フェーズ中に読み取られます。また、そのカラムへの参照は、クエリー実行が続行される前に適切なカラム値で置き換えられます。これらのテーブルは、EXPLAIN によって表示されるクエリー計画に最初に表示されます。「セクション8.8.1「EXPLAIN によるクエリーの最適化」」を参照してください。この例外は、外部結合の NULL で補完された側で使用されている const テーブルまたは system テーブル (つまり、LEFT JOIN の右側のテーブルまたは RIGHT JOIN の左側のテーブル) には適用されない可能性があります。

  • SQL_BIG_RESULT または SQL_SMALL_RESULT は、結果セットの行数がそれぞれ多いこと、または少ないことをオプティマイザに通知するために GROUP BY または DISTINCT とともに使用できます。SQL_BIG_RESULT の場合、MySQL は、必要に応じてディスクベースの一時テーブルを直接使用し、ソートでは GROUP BY 要素に関するキーで一時テーブルを使用することを優先します。SQL_SMALL_RESULT の場合、MySQL はソートを使用する代わりに、高速な一時テーブルを使用して結果のテーブルを格納します。これは、通常は必要ないはずです。

  • SQL_BUFFER_RESULT は、結果を強制的に一時テーブルに配置します。これは、MySQL がテーブルロックを早期に解放する場合や、結果セットをクライアントに送信するのに長い時間がかかる場合に役立ちます。このオプションは、サブクエリーまたは後続の UNION ではなく、トップレベルの SELECT ステートメントでのみ使用できます。

  • SQL_CALC_FOUND_ROWS は MySQL に、LIMIT 句をすべて無視して、結果セットに含まれる行数を計算するよう指示します。そのあと、行数は SELECT FOUND_ROWS() を使用して取得できます。セクション12.14「情報関数」を参照してください。

  • SQL_CACHE および SQL_NO_CACHE オプションは、クエリーキャッシュ内のクエリー結果のキャッシュに影響を与えます (セクション8.9.3「MySQL クエリーキャッシュ」を参照してください)。SQL_CACHE は MySQL に、結果がキャッシュ可能であり、query_cache_type システム変数の値が 2 または DEMAND である場合は、結果をクエリーキャッシュに格納するよう指示します。SQL_NO_CACHE を指定すると、サーバーはクエリーキャッシュを使用しません。それは、結果がすでにキャッシュされているかどうかを確認するためにクエリーキャッシュをチェックせず、クエリー結果もキャッシュしません。(パーサーの制限のため、スペース文字の前後に SQL_NO_CACHE キーワードを付ける必要があります。改行などのスペース以外では、結果がすでにキャッシュされているかどうかを確認するために、サーバーにクエリーキャッシュをチェックさせます。)

    ビューの場合、SQL_NO_CACHE は、クエリー内のいずれかの SELECT に現れた場合に適用されます。キャッシュ可能なクエリーでは、SQL_CACHE は、そのクエリーによって参照されるビューの最初の SELECT に現れた場合に適用されます。

    MySQL 5.6 では、これらの 2 つのオプションは相互に排他的であり、両方が指定された場合はエラーが発生します。また、これらのオプションは、サブクエリー (FROM 句内のサブクエリーを含む) や、最初の SELECT を除く和集合内の SELECT ステートメント内では許可されません。

MySQL 5.6.6 より前は、テーブルレベルのロックを採用した MyISAM などのストレージエンジンを使用しているパーティション化されたテーブルからの SELECT によって、そのテーブルのすべてのパーティションがロックされました。これは、SELECT ... PARTITION クエリーにも当てはまりました。(これは、行レベルロックを採用した InnoDB などのストレージエンジンでは発生しておらず、現在も発生しません。)MySQL 5.6.6 以降では、MySQL はパーティションロックプルーニングを使用します。これにより、SELECT ステートメントの WHERE 句に一致する行を含むパーティションだけが実際にロックされるようになります。詳細は、セクション19.6.4「パーティショニングとロック」を参照してください。

13.2.9.1 SELECT ... INTO 構文

SELECTSELECT ... INTO 形式を使用すると、クエリー結果を変数に格納したり、ファイルに書き込んだりできます。

  • SELECT ... INTO var_list はカラム値を選択し、それらを変数に格納します。

  • SELECT ... INTO OUTFILE は、選択された行をファイルに書き込みます。カラムおよび行ターミネータを指定すると、特定の出力形式を生成できます。

  • SELECT ... INTO DUMPFILE は、単一行をファイルに形式設定なしで書き込みます。

SELECT の構文の説明 (セクション13.2.9「SELECT 構文」を参照してください) では、INTO 句がステートメントの最後の近くに示されています。INTO はまた、select_expr リストの直後に使用することもできます。

ネストされた SELECT はその結果を外側のコンテキストに返す必要があるため、このような SELECT では INTO 句を使用してはいけません。

INTO 句は、1 つ以上の変数のリストを指定できます。この変数には、ユーザー定義変数、ストアドプロシージャーやストアドファンクションのパラメータ、またはストアドプログラムのローカル変数を指定できます。(準備済み SELECT ... INTO OUTFILE ステートメント内では、ユーザー定義変数のみが許可されます。セクション13.6.4.2「ローカル変数のスコープと解決」を参照してください。)

選択された値は変数に割り当てられます。変数の数がカラム数に一致している必要があります。クエリーは、単一行を返すようにしてください。クエリーが行を返さない場合は、エラーコード 1329 で警告が発生し (No data)、変数値は変更されないままになります。クエリーが複数の行を返す場合は、エラー 1172 が発生します (結果が 2 行以上です)。このステートメントが複数の行を取得する可能性がある場合は、LIMIT 1 を使用して結果セットを単一行に制限できます。

SELECT id, data INTO @x, @y FROM test.t1 LIMIT 1;

ユーザー変数名では大文字と小文字を区別しません。セクション9.4「ユーザー定義変数」を参照してください。

SELECTSELECT ... INTO OUTFILE 'file_name' 形式は、選択された行をファイルに書き込みます。このファイルはサーバーホスト上で作成されるため、この構文を使用するには FILE 権限が必要です。file_name を既存のファイルにすることはできません。これにより、特に /etc/passwd などのファイルやデータベーステーブルが破棄されることが回避されます。character_set_filesystem システム変数は、ファイル名の解釈を制御します。

SELECT ... INTO OUTFILE ステートメントは、主に、テーブルをサーバーマシン上のテキストファイルに非常にすばやくダンプできるようにすることを目的にしています。結果として得られるファイルをサーバーホスト以外のホスト上で作成する場合は通常、そのサーバーホストのファイルシステムを基準にしたファイルへのパスを記述する方法が存在しないため、SELECT ... INTO OUTFILE は使用できません。

ただし、MySQL クライアントソフトウェアがリモートマシンにインストールされている場合は、代わりに mysql -e "SELECT ..." > file_name などのクライアントコマンドを使用してクライアントホスト上にファイルを生成できます。

また、サーバーのファイルシステム上でネットワークにマップされたパスを使用してリモートホスト上のファイルの場所にアクセスできる場合も、結果として得られるファイルをサーバーホストとは異なるホスト上に作成できます。この場合は、ターゲットホスト上に mysql (または、その他の何らかの MySQL クライアントプログラム) が存在する必要はありません。

SELECT ... INTO OUTFILE は、LOAD DATA INFILE を補完するものです。カラム値は、CHARACTER SET 句で指定されている文字セットに変換されて書き込まれます。このような句が存在しない場合、値は binary 文字セットを使用してダンプされます。事実上、文字セットの変換は実行されません。結果セットにカラムが複数の文字セットで含まれている場合は、出力データファイルにもそのまま含まれるため、そのファイルを正しくリロードできない可能性があります。

このステートメントの export_options 部分の構文は、LOAD DATA INFILE ステートメントで使用されるのと同じ FIELDS および LINES 句で構成されています。FIELDS および LINES 句 (それぞれのデフォルト値と許可される値を含む) については、セクション13.2.6「LOAD DATA INFILE 構文」を参照してください。

FIELDS ESCAPED BY は、特殊文字を書き込む方法を制御します。FIELDS ESCAPED BY 文字が空でない場合、その文字は、出力上で次の文字の前に付けられるプリフィクスとして、あいまいさを避けるために必要な場合に使用されます。

  • FIELDS ESCAPED BY 文字

  • FIELDS [OPTIONALLY] ENCLOSED BY 文字

  • FIELDS TERMINATED BY および LINES TERMINATED BY 値の最初の文字

  • ASCII NUL (0 の値のバイト。エスケープ文字のあとに実際に書き込まれる文字は 0 の値のバイトではなく、ASCII の0です)

FIELDS TERMINATED BYENCLOSED BYESCAPED BY、または LINES TERMINATED BY 文字は、そのファイルを確実に読み戻すことができるように、エスケープする必要があります。ASCII NUL は、一部のページャーで見やすくなるようにエスケープされます。

結果として得られるファイルは SQL 構文に準拠する必要はないため、ほかは何もエスケープする必要がありません。

FIELDS ESCAPED BY 文字が空である場合は、どの文字もエスケープされず、NULL\N ではなく、NULL として出力されます。特に、データ内のフィールド値に今指定したリスト内のいずれかの文字が含まれている場合、空のエスケープ文字を指定することはおそらく適切な方法ではありません。

多くのプログラムで使用されているカンマ区切り値 (CSV) 形式のファイルを生成する例を次に示します。

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

INTO OUTFILE の代わりに INTO DUMPFILE を使用した場合、MySQL はエスケープ処理を実行することなく、カラムや行の終了のない 1 行のみをファイルに書き込みます。これは、ファイルに BLOB 値を格納する場合に役立ちます。

注記

INTO OUTFILE または INTO DUMPFILE によって作成されたファイルはすべて、サーバーホスト上のすべてのユーザーから書き込み可能です。これは、MySQL サーバーが、それを実行しているアカウントを持つユーザー以外のどのユーザーによって所有されるファイルも作成できないためです。(これらの理由のために、mysqldroot としては決して実行しないでください。) したがって、このファイルは、その内容を操作できるようにすべてのユーザーから書き込み可能である必要があります。

secure_file_priv システム変数が空以外のディレクトリ名に設定されている場合、書き込まれるファイルはそのディレクトリ内に存在する必要があります。

イベントスケジューラによって実行されるイベントの一部として実行された SELECT ... INTO ステートメントのコンテキストでは、診断メッセージ (エラーだけでなく、警告も含みます) がエラーログに (Windows ではアプリケーションイベントログにも) 書き込まれます。詳細は、セクション20.4.5「イベントスケジューラのステータス」を参照してください。

13.2.9.2 JOIN 構文

MySQL は、SELECT ステートメントと複数テーブルの DELETE および UPDATE ステートメントの table_references 部分に対して次の JOIN 構文をサポートします。

table_references:escaped_table_reference [, escaped_table_reference] ...escaped_table_reference: table_reference | { OJ table_reference }table_reference: table_factor | join_tabletable_factor: tbl_name [PARTITION (partition_names)] [[AS] alias] [index_hint_list] | table_subquery [AS] alias | ( table_references )join_table: table_reference [INNER | CROSS] JOIN table_factor [join_condition] | table_reference STRAIGHT_JOIN table_factor | table_reference STRAIGHT_JOIN table_factor ON conditional_expr | table_reference {LEFT|RIGHT} [OUTER] JOIN table_referencejoin_condition | table_reference NATURAL [{LEFT|RIGHT} [OUTER]] JOIN table_factorjoin_condition: ON conditional_expr | USING (column_list)index_hint_list: index_hint [, index_hint] ...index_hint: USE {INDEX|KEY} [FOR {JOIN|ORDER BY|GROUP BY}] ([index_list]) | IGNORE {INDEX|KEY} [FOR {JOIN|ORDER BY|GROUP BY}] (index_list) | FORCE {INDEX|KEY} [FOR {JOIN|ORDER BY|GROUP BY}] (index_list)index_list: index_name [, index_name] ...

テーブル参照は、結合式とも呼ばれます。

MySQL 5.6.2 以降では、テーブル参照 (パーティション化されたテーブルを参照する場合) には、パーティション、サブパーティション、またはその両方のカンマ区切りリストを含む PARTITION オプションを含めることができます。このオプションはテーブルの名前のあとで、かつエイリアス宣言 (存在する場合) の前に指定されます。このオプションの効果は、リストされているパーティションまたはサブパーティションからのみ行が選択されることです。つまり、そのリストで指定されていないパーティションまたはサブパーティションはすべて無視されます。詳細は、セクション19.5「パーティション選択」を参照してください。

table_factor の構文は SQL 標準と比較して拡張されています。後者は table_reference のみを受け付け、かっこ内のそれらのリストは受け付けません。

これは、table_reference 項目のリストの各カンマを内部結合と同等とみなす場合、保守的な拡張です。例:

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

次と同等です。

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)

MySQL では、JOINCROSS JOIN、および INNER JOIN は構文上同等です (互いに置き換えることができます)。標準 SQL では、それらは同等ではありません。INNER JOINON 句とともに使用され、CROSS JOIN はそれ以外のときに使用されます。

一般に、内部結合操作のみを含む結合式内のかっこは無視できます。MySQL はまた、ネストされた結合もサポートしています (セクション8.2.1.11「ネストした結合の最適化」を参照してください)。

インデックスヒントを指定すると、MySQL オプティマイザによるインデックスの使用方法に影響を与えることができます。詳細は、セクション13.2.9.3「インデックスヒントの構文」を参照してください。

次のリストは、結合を記述するときに考慮に入れるべき一般的な要因について説明しています。

  • テーブル参照には、tbl_name AS alias_name または tbl_name alias_name を使用してエイリアスを指定できます。

    SELECT t1.name, t2.salary FROM employee AS t1 INNER JOIN info AS t2 ON t1.name = t2.name;
    SELECT t1.name, t2.salary FROM employee t1 INNER JOIN info t2 ON t1.name = t2.name;
  • table_subquery は、FROM 句内のサブクエリーとも呼ばれます。サブクエリー結果にテーブル名を付けるには、このようなサブクエリーにエイリアスを含める必要があります。簡単な例を次に示します。セクション13.2.10.8「FROM 句内のサブクエリー」も参照してください。

    SELECT * FROM (SELECT 1, 2, 3) AS t1;
  • 結合条件が存在しない場合、INNER JOIN, (カンマ) は意味的に同等です。どちらも、指定されたテーブル間のデカルト積を生成します (つまり、最初のテーブル内のすべての各行が 2 番目のテーブル内のすべての各行に結合されます)。

    ただし、カンマ演算子の優先順位は、INNER JOINCROSS JOINLEFT JOIN などの優先順位より低くなります。結合条件が存在するときにカンマ結合をほかの結合型と混在させた場合は、「カラム 'col_name' は 'on clause' にはありません」という形式のエラーが発生する可能性があります。この問題への対処に関する情報は、このセクションのあとの方で提供します。

  • ON とともに使用される conditional_expr は、WHERE 句で使用できる形式の任意の条件式です。一般に、テーブルの結合方法を指定する条件には ON 句を、また結果セット内に必要な行を制限するには WHERE 句を使用してください。

  • LEFT JOIN 内の ON または USING 部分にある右側のテーブルに一致する行が存在しない場合は、すべてのカラムが NULL に設定された行が右側のテーブルに使用されます。このことを使用して、別のテーブルに対応する行が存在しないテーブル内の行を検索できます。

    SELECT left_tbl.* FROM left_tbl LEFT JOIN right_tbl ON left_tbl.id = right_tbl.id WHERE right_tbl.id IS NULL;

    この例では、right_tbl に存在しない id 値を持つ left_tbl 内のすべての行 (つまり、right_tbl 内に対応する行のない left_tbl 内のすべての行) を検索します。これは、right_tbl.idNOT NULL として宣言されていることを前提にしています。セクション8.2.1.9「LEFT JOIN および RIGHT JOIN の最適化」を参照してください。

  • USING(column_list) 句は、両方のテーブル内に存在する必要のあるカラムのリストを指定します。テーブル ab の両方にカラム c1c2、および c3 が含まれている場合、次の結合は、この 2 つのテーブルの対応するカラムを比較します。

    a LEFT JOIN b USING (c1,c2,c3)
  • 2 つのテーブルの NATURAL [LEFT] JOIN は、両方のテーブル内に存在するすべてのカラムを指定する USING 句を含む INNER JOIN または LEFT JOIN と意味的に同等であるとして定義されます。

  • RIGHT JOIN は、LEFT JOIN と同じように機能します。コードをデータベース間で移植可能な状態に維持するため、RIGHT JOIN の代わりに LEFT JOIN を使用することをお勧めします。

  • 結合構文の説明に示されている { OJ ... } 構文は、ODBC との互換性のためにのみ存在します。構文内のカールした中括弧は文字どおりに書き込まれる必要があります。それらは構文説明の別の部分で利用されているようなメタ構文ではありません。

    SELECT left_tbl.* FROM { OJ left_tbl LEFT OUTER JOIN right_tbl ON left_tbl.id = right_tbl.id } WHERE right_tbl.id IS NULL;

    { OJ ... } 内では、INNER JOINRIGHT OUTER JOIN などのほかの型の結合を使用できます。これは、一部のサードパーティー製アプリケーションとの互換性に役立ちますが、正式な ODBC 構文ではありません。

  • STRAIGHT_JOIN は、左側のテーブルが常に右側のテーブルの前に読み取られる点を除き、JOIN と同じです。これは、結合オプティマイザがテーブルを間違った順序で配置する (数少ない) 場合に使用できます。

結合のいくつかの例:

SELECT * FROM table1, table2;
SELECT * FROM table1 INNER JOIN table2 ON 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;

MySQL 5.0.12 での結合処理の変更

注記

自然結合や USING を使用した結合 (外部結合のバリアントを含む) は、SQL:2003 標準に従って処理されます。その目標は、NATURAL JOINJOIN ... USING に関連した MySQL の構文とセマンティクスを SQL:2003 に合わせることでした。ただし、結合処理でのこれらの変更によって、一部の結合で異なる出力カラムが生成される可能性があります。また、古いバージョン (5.0.12 より前) では正しく機能するように見えた一部のクエリーを、この標準に準拠するように書き換える必要があります。

これらの変更の主要な側面として、次の 5 つがあります。

  • MySQL が NATURAL または USING 結合操作の結果カラム (したがって、FROM 句全体の結果) を決定する方法。

  • SELECT * および SELECT tbl_name.* の選択されたカラムのリストへの展開。

  • NATURAL または USING 結合でのカラム名の解決。

  • NATURAL または USING 結合の JOIN ... ON への変換。

  • JOIN ... ONON 条件でのカラム名の解決。

次のリストは、現在の結合処理のいくつかの効果を古いバージョンでの結合処理と比較した場合のさらに詳細な情報を示しています。以前という用語は、MySQL 5.0.12 より前を示しています。

  • NATURAL 結合または USING 結合のカラムが以前とは異なる可能性があります。具体的には、冗長な出力カラムが表示されなくなっており、また SELECT * の展開でのカラムの順序が以前とは異なる可能性があります。

    次の一連のステートメントを考えてみます。

    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);

    以前は、これらのステートメントによって次の出力が生成されました。

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

    最初の SELECT ステートメントでは、カラム j は両方のテーブルに現れるため、結合カラムになります。そのため、標準 SQL に従って、出力には 2 回ではなく 1 回だけ表示されるべきです。同様に、2 番目の SELECT ステートメントでは、カラム jUSING 句で指定されているため、出力には 2 回ではなく 1 回だけ表示されるべきです。ただし、どちらの場合も、冗長なカラムは削除されていません。また、標準 SQL に従うとカラムの順序も正しくありません。

    現在は、このステートメントによって次の出力が生成されます。

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

    冗長なカラムは削除され、カラムの順序も標準 SQL に従って正しくなっています。

    • 最初に、結合された 2 つのテーブルの合体した共通カラムが、最初のテーブルに現れた順序で

    • 2 番目に、最初のテーブルに一意のカラムが、そのテーブルに現れた順序で

    • 3 番目に、2 番目のテーブルに一意のカラムが、そのテーブルに現れた順序で

    2 つの共通カラムを置き換える 1 つの結果カラムは、合体操作を使用して定義されます。つまり、t1.at2.a の 2 つに対して、結果として得られる 1 つの結合カラム aa = COALESCE(t1.a, t2.a) として定義されます。ここでは:

    COALESCE(x, y) = (CASE WHEN V1 IS NOT NULL THEN V1 ELSE V2 END)

    この結合操作がほかのいずれかの結合である場合、その結合の結果カラムは、結合されたテーブルのすべてのカラムの連結で構成されます。これは以前と同じです。

    合体したカラムの定義の結果として、外部結合では、2 つのカラムのいずれかが常に NULL である場合、合体したカラムには NULL 以外のカラムの値が含まれます。どちらのカラムも NULL でないか、または両方のカラムがこの値である場合、両方の共通カラムに同じ値が含まれているため、合体したカラムの値としてどちらが選択されるかは問題にはなりません。これを解釈するための簡単な方法として、外部結合の合体したカラムが JOIN の内部テーブルの共通カラムによって表されると考えてみます。テーブル t1(a,b)t2(a,c) に次の内容が含まれているとします。

    t1 t2
    ---- ----
    1 x 2 z
    2 y 3 w

    このとき、次のようになります。

    mysql> SELECT * FROM t1 NATURAL LEFT JOIN t2;+------+------+------+
    | a | b | c |
    +------+------+------+
    | 1 | x | NULL |
    | 2 | y | z |
    +------+------+------+

    ここでは、カラム at1.a の値が含まれています。

    mysql> SELECT * FROM t1 NATURAL RIGHT JOIN t2;+------+------+------+
    | a | c | b |
    +------+------+------+
    | 2 | z | y |
    | 3 | w | NULL |
    +------+------+------+

    ここでは、カラム at2.a の値が含まれています。

    これらの結果を、JOIN ... ON を使用した、それ以外では同等のクエリーと比較してください。

    mysql> SELECT * FROM t1 LEFT JOIN t2 ON (t1.a = t2.a);+------+------+------+------+
    | a | b | a | c |
    +------+------+------+------+
    | 1 | x | NULL | NULL |
    | 2 | y | 2 | z |
    +------+------+------+------+
    mysql> SELECT * FROM t1 RIGHT JOIN t2 ON (t1.a = t2.a);+------+------+------+------+
    | a | b | a | c |
    +------+------+------+------+
    | 2 | y | 2 | z |
    | NULL | NULL | 3 | w |
    +------+------+------+------+
  • 以前は、USING 句を、対応するカラムを比較する ON 句として書き換えることができました。たとえば、次の 2 つの句は意味的に同一でした。

    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

    現在、この 2 つの句はまったく同じではなくなっています。

    • どの行が結合条件を満たすかの判定に関しては、どちらの結合も意味的に同一のままです。

    • SELECT * の展開に対してどのカラムを表示するかの判定に関しては、この 2 つの結合は意味的に同一ではありません。USING 結合が対応するカラムの合体した値を選択するのに対して、ON 結合は、すべてのテーブルのすべてのカラムを選択します。前の USING 結合の場合、SELECT * は次の値を選択します。

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

      ON 結合の場合、SELECT * は次の値を選択します。

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

      内部結合では、a.c1b.c1 の両方のカラムに同じ値が含まれるため、COALESCE(a.c1,b.c1) はどちらのカラムとも同じです。外部結合 (LEFT JOIN など) では、2 つのカラムのどちらかが NULL になる場合があります。そのカラムは結果から省略されます。

  • 多方向自然結合の評価は、NATURAL または USING 結合の結果に影響を与え、さらにはクエリーの書き換えが必要になる場合もある非常に重要な点で異なります。3 つのテーブル t1(a,b)t2(c,b)、および t3(a,c) があり、各テーブルに t1(1,2)t2(10,2)、および t3(7,10) の 1 行が含まれているとします。また、これらの 3 つのテーブルに対して次の NATURAL JOIN を実行するとします。

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

    以前は、2 番目の結合の左のオペランドが t2 であると見なされたのに対して、現在はネストされた結合 (t1 NATURAL JOIN t2) であると見なされます。その結果、t3 のカラムは t2 でのみ共通カラムに対してチェックされ、さらに t3t1 との共通カラムが含まれている場合、これらのカラムは等価結合カラムとして使用されません。そのため、以前は、前のクエリーは次の等価結合に変換されました。

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

    その結合には、もう 1 つの等価結合述語 (t1.a = t3.a) がありません。その結果、本来生成すべき空の結果ではなく、1 行が生成されます。正しい同等のクエリーは次のとおりです。

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

    現在のバージョンの MySQL で古いバージョンと同じクエリー結果が必要な場合は、自然結合を最初の等価結合として書き換えてください。

  • 以前は、カンマ演算子 (,) と JOIN はどちらも同じ優先順位を持っていたため、結合式 t1, t2 JOIN t3((t1, t2) JOIN t3) として解釈されました。現在は、JOIN の優先順位の方が高いため、この式は (t1, (t2 JOIN t3)) として解釈されます。ON 句は結合のオペランド内のカラムしか参照できず、また優先順位の変更によってそれらのオペランドが示す内容の解釈が変更されるため、この変更はその句を使用するステートメントに影響を与えます。

    例:

    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);

    以前は、この SELECT は、(t1,t2) として t1,t2 の暗黙的なグループ化のために正当でした。現在は、JOIN が優先されるため、ON 句のオペランドは t2t3 になります。t1.i1 はどのオペランドのカラムでもないため、その結果は「カラム 't1.i1' は 'on clause' にはありません」というエラーになります。この結合の処理を可能にするには、ON 句のオペランドが (t1,t2)t3 になるように、最初の 2 つのテーブルを明示的に括弧でグループ化します。

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

    あるいは、カンマ演算子の使用を避け、代わりに JOIN を使用します。

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

    この変更はまた、カンマ演算子を INNER JOINCROSS JOINLEFT JOIN、および RIGHT JOIN (これらはすべて現在、カンマ演算子より高い優先順位を持っています) と混在させているステートメントにも適用されます。

  • 以前は、ON 句は、その右側で指定されているテーブル内のカラムを参照することができました。現在は、ON 句は自身のオペランドしか参照できません。

    例:

    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;

    以前は、この SELECT ステートメントは正当でした。現在は、i3ON 句のオペランドではない t3 内のカラムであるため、このステートメントは「カラム 'i3' は 'on clause' にはありません」というエラーで失敗します。このステートメントを次のように書き換えるようにしてください。

    SELECT * FROM t1 JOIN t2 JOIN t3 ON (i1 = i3);
  • NATURAL または USING 結合でのカラム名の解決が以前とは異なります。FROM 句の外部にあるカラム名の場合、MySQL は現在、以前と比較してクエリーのスーパーセットを処理します。つまり、MySQL が以前、一部のカラムがあいまいであるというエラーを発行したケースでも、そのクエリーは現在、正しく処理されます。これは、MySQL が現在、NATURAL または USING 結合の共通カラムを単一カラムとして処理するため、クエリーがこのようなカラムを参照しても、クエリーコンパイラがそのカラムをあいまいであるとは見なさないことによります。

    例:

    SELECT * FROM t1 NATURAL JOIN t2 WHERE b > 1;

    以前は、このクエリーによってエラー ERROR 1052 (23000): Column 'b' in where clause is ambiguous が生成されました。現在は、このクエリーによって正しい結果が生成されます。

    +------+------+------+
    | b | c | y |
    +------+------+------+
    | 4 | 2 | 3 |
    +------+------+------+

    SQL:2003 標準と比べた場合の MySQL の 1 つの拡張として、MySQL では、NATURAL または USING 結合の共通 (合体した) カラムを (以前と同様に) 修飾できるのに対して、標準ではそれが禁止される点があります。

13.2.9.3 インデックスヒントの構文

クエリー処理中にインデックスを選択する方法に関する情報をオプティマイザに提供するためのヒントを指定できます。セクション13.2.9.2「JOIN 構文」では、SELECT ステートメントでテーブルを指定するための一般的な構文について説明しています。個々のテーブルの構文 (インデックスヒントの構文を含む) は次のようになります。

tbl_name [[AS] alias] [index_hint_list]index_hint_list: index_hint [, index_hint] ...index_hint: USE {INDEX|KEY} [FOR {JOIN|ORDER BY|GROUP BY}] ([index_list]) | IGNORE {INDEX|KEY} [FOR {JOIN|ORDER BY|GROUP BY}] (index_list) | FORCE {INDEX|KEY} [FOR {JOIN|ORDER BY|GROUP BY}] (index_list)index_list: index_name [, index_name] ...

USE INDEX (index_list) を指定することによって、テーブル内の行を検索するために、指定されたインデックスの 1 つのみを使用するよう MySQL に指示できます。代わりの構文 IGNORE INDEX (index_list) を使用すると、いくつかの特定の (1 つまたは複数の) インデックスを使用しないよう MySQL に指示できます。これらのヒントは、EXPLAIN によって、MySQL が可能性のあるインデックスのリストから間違ったインデックスを使用していることが示された場合に役立ちます。

また、USE INDEX (index_list) と同様の機能を持つが、テーブルスキャンが非常に負荷が大きいと見なされる点が追加された FORCE INDEX を使用することもできます。つまり、テーブルスキャンは、指定されたインデックスのいずれかを使用してテーブル内の行を検索する方法がない場合にのみ使用されます。

各ヒントには、カラムの名前ではなく、インデックスの名前が必要です。PRIMARY KEY の名前は PRIMARY です。テーブルのインデックス名を表示するには、SHOW INDEX を使用します。

index_name 値は、完全なインデックス名である必要はありません。インデックス名のあいまいでないプリフィクスにすることができます。プリフィクスがあいまいな場合は、エラーが発生します。

例:

SELECT * FROM table1 USE INDEX (col1_index,col2_index) WHERE col1=1 AND col2=2 AND col3=3;
SELECT * FROM table1 IGNORE INDEX (col3_index) WHERE col1=1 AND col2=2 AND col3=3;

インデックスヒントの構文には、次の特性があります。

  • USE INDEX に空の index_list を指定する (つまり、インデックスを使用しない) ことは構文として有効です。FORCE INDEX または IGNORE INDEX に空の index_list を指定することは構文エラーです。

  • ヒントに FOR 句を追加することによって、インデックスヒントのスコープを指定できます。これにより、クエリー処理のさまざまなフェーズに対するオプティマイザの実行計画の選択をよりきめ細かく制御できるようになります。MySQL がテーブル内の行の検索方法および結合の処理方法を決定するときに使用されるインデックスにのみ影響を与えるには、FOR JOIN を使用します。行をソートまたはグループ化するためのインデックス使用に影響を与えるには、FOR ORDER BY または FOR GROUP BY を使用します。(ただし、テーブルを範囲に含むインデックスが存在し、それがテーブルへのアクセスに使用されている場合、オプティマイザは、そのインデックスを無効にする IGNORE INDEX FOR {ORDER BY|GROUP BY} ヒントを無視します。)

  • 複数のインデックスヒントを指定できます。

    SELECT * FROM t1 USE INDEX (i1) IGNORE INDEX FOR ORDER BY (i2) ORDER BY a;

    複数のヒントで同じインデックスを指定することは (同じヒント内であっても) エラーではありません。

    SELECT * FROM t1 USE INDEX (i1) USE INDEX (i1,i1);

    ただし、同じテーブルに対して USE INDEXFORCE INDEX を混在させると、エラーが発生します。

    SELECT * FROM t1 USE INDEX FOR JOIN (i1) FORCE INDEX FOR JOIN (i2);

インデックスヒントで FOR 句を指定しない場合、デフォルトでは、そのヒントはステートメントのすべての部分に適用されます。たとえば、次のヒント

IGNORE INDEX (i1)

は次のヒントの組み合わせと同等です。

IGNORE INDEX FOR JOIN (i1)
IGNORE INDEX FOR ORDER BY (i1)
IGNORE INDEX FOR GROUP BY (i1)

サーバーで、FOR 句が存在しないときに (ヒントが行の取得にのみ適用されるように) ヒントスコープに対する古い動作が使用されるようにするには、サーバーの起動時に古いシステム変数を有効にします。レプリケーションセットアップでこの変数を有効にする場合は注意してください。ステートメントベースのバイナリロギングで、マスターとスレーブに異なるモードを指定するとレプリケーションエラーが発生する場合があります。

インデックスヒントが処理されるとき、これらのインデックスヒントは、型 (USEFORCEIGNORE) およびスコープ (FOR JOINFOR ORDER BYFOR GROUP BY) ごとに 1 つのリストに収集されます。例:

SELECT * FROM t1 USE INDEX () IGNORE INDEX (i2) USE INDEX (i1) USE INDEX (i2);

次と同等です。

SELECT * FROM t1 USE INDEX (i1,i2) IGNORE INDEX (i2);

そのあと、インデックスヒントは、スコープごとに次の順序で適用されます。

  1. {USE|FORCE} INDEX が存在する場合は、これが適用されます。(存在しない場合は、オプティマイザによって決定されたインデックスのセットが使用されます。)

  2. 前の手順の結果に対して、IGNORE INDEX が適用されます。たとえば、次の 2 つのクエリーは同等です。

    SELECT * FROM t1 USE INDEX (i1) IGNORE INDEX (i2) USE INDEX (i2);
    SELECT * FROM t1 USE INDEX (i1);

FULLTEXT の検索の場合、インデックスヒントは次のように機能します。

  • 自然言語モードの検索の場合、インデックスヒントは暗黙のうちに無視されます。たとえば、IGNORE INDEX(i) は警告なしで無視され、インデックスが引き続き使用されます。

    ブールモードの検索の場合、FOR ORDER BY または FOR GROUP BY を含むインデックスヒントは暗黙のうちに無視されます。FOR JOIN を含むインデックスヒント、または FOR 修飾子を含まないインデックスヒントは受け付けられます。ヒントが FULLTEXT 以外の検索に適用される場合とは異なり、このヒントは、クエリー実行のすべてのフェーズ (行の検索と取得、グループ化、および順序付け) に使用されます。これは、ヒントが FULLTEXT 以外のインデックスに対して指定されている場合でも当てはまります。

たとえば、次の 2 つのクエリーは同等です。

SELECT * FROM t USE INDEX (index1) IGNORE INDEX (index1) FOR ORDER BY IGNORE INDEX (index1) FOR GROUP BY WHERE ... IN BOOLEAN MODE ... ;
SELECT * FROM t USE INDEX (index1) WHERE ... IN BOOLEAN MODE ... ;

13.2.9.4 UNION 構文

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

UNION は、複数の SELECT ステートメントからの結果を 1 つの結果セットに結合するために使用されます。

最初の SELECT ステートメントからのカラム名が、返される結果のカラム名として使用されます。各 SELECT ステートメントの対応する位置にリストされている選択されるカラムは、データ型が同じになるようにしてください。(たとえば、最初のステートメントによって選択される最初のカラムが、ほかのステートメントによって選択される最初のカラムと型が同じになるようにしてください。)

対応する SELECT カラムのデータ型が一致しない場合、UNION の結果内のカラムの型と長さは、すべての SELECT ステートメントによって取得された値を考慮に入れて決定されます。たとえば、次の例を考えてみます。

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

これらの SELECT ステートメントは通常の選択ステートメントですが、次の制限があります。

  • INTO OUTFILE を使用できるのは、最後の SELECT ステートメントだけです。(ただし、UNION の結果全体がファイルに書き込まれます。)

  • HIGH_PRIORITY を、UNION の一部である SELECT ステートメントで使用することはできません。それを最初の SELECT に対して指定しても、何の効果もありません。それを以降のいずれかの SELECT ステートメントに対して指定すると、構文エラーが発生します。

UNION のデフォルトの動作では、重複した行が結果から削除されます。オプションの DISTINCT キーワードは、これも重複した行の削除を指定するため、デフォルト以外の効果は何もありません。オプションの ALL キーワードを指定すると、重複した行の削除は実行されず、その結果には、すべての SELECT ステートメントからの一致するすべての行が含まれます。

UNION ALLUNION DISTINCT を同じクエリー内で混在させることができます。混在した UNION 型は、DISTINCT 和集合がその左側にある ALL 和集合をすべてオーバーライドするように処理されます。DISTINCT 和集合は、UNION DISTINCT を使用して明示的に、あるいはそのあとに DISTINCT または ALL キーワードのない UNION を使用して暗黙的に生成できます。

個々の SELECTORDER BY または LIMIT を適用するには、この句を SELECT を囲む括弧内に配置します。

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

ただし、個々の SELECT ステートメントに対して ORDER BY を使用しても、UNION がデフォルトでは、順序付けされていない行のセットを生成するため、最終的な結果に行が現れる順序には何も影響を与えません。そのため、このコンテキストでは通常、ORDER BYLIMIT と組み合わせて使用されます。それにより、選択された行の UNION の最終結果での順序に必ずしも影響を与えるわけではないにもかかわらず、SELECT で取得するためのこれらの行のサブセットを決定するために使用されるようになります。ORDER BYSELECT 内に LIMIT なしで現れた場合、この句はいずれにしても何も効果がないため、最適化によって削除されます。

ORDER BY または LIMIT 句を使用して UNION の結果全体をソートまたは制限するには、個々の SELECT ステートメントを括弧で囲み、最後のステートメントのあとに ORDER BY または LIMIT を配置します。次の例では、この両方の句を使用しています。

(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;

括弧のないステートメントは、今示した括弧で囲まれたステートメントと同等です。

この種の ORDER BY は、テーブル名 (つまり、tbl_name.col_name という形式の名前) を含むカラム参照を使用できません。代わりに、最初の SELECT ステートメント内にカラムのエイリアスを指定し、そのエイリアスを ORDER BY 内で参照します。(あるいは、ORDER BY 内でカラムを、そのカラム位置を使用して参照します。ただし、カラム位置の使用は非推奨です。)

また、ソートされるカラムにエイリアスが指定されている場合、ORDER BY 句はそのカラム名ではなく、エイリアスを参照する必要があります。次のうちの最初のステートメントは機能しますが、2 番目は「カラム 'a' は 'order clause' にはありません」というエラーで失敗します。

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

UNION の結果内の行が、各 SELECT によって 1 つずつ取得された行のセットで構成されるようにするには、ソートカラムとして使用する各 SELECT 内の追加のカラムを選択し、最後の SELECT のあとに ORDER BY を追加します。

(SELECT 1 AS sort_col, col1a, col1b, ... FROM t1)
UNION
(SELECT 2, col2a, col2b, ... FROM t2) ORDER BY sort_col;

さらに個々の SELECT の結果内のソート順序を維持するには、ORDER BY 句にセカンダリカラムを追加します。

(SELECT 1 AS sort_col, col1a, col1b, ... FROM t1)
UNION
(SELECT 2, col2a, col2b, ... FROM t2) ORDER BY sort_col, col1a;

また、追加のカラムを使用すると、各行がどの SELECT から取得されるかを決定することもできます。追加のカラムでは、テーブル名を示す文字列などのほかの識別情報も指定できます。

13.2.10 サブクエリー構文

サブクエリーは、別のステートメント内の SELECT ステートメントです。

MySQL 4.1 から、SQL 標準に必要なサブクエリーのすべての形式および操作だけでなく、MySQL 固有のいくつかの機能がサポートされています。

サブクエリーの例を次に示します。

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

この例では、SELECT * FROM t1 ...外部クエリー (または 外部ステートメント) であり、(SELECT column1 FROM t2)サブクエリーです。これを、このサブクエリーは外部クエリー内でネストされていると表現し、また実際、サブクエリーをほかのサブクエリー内で (かなりの深さまで) ネストできます。サブクエリーは常に、括弧内に指定する必要があります。

サブクエリーの主な利点は次のとおりです。

  • ステートメントの各部分を分離できるように、構造化されたクエリーを可能にします。

  • 通常であれば複雑な結合や和集合を必要とする操作を実行するための代替手段を提供します。

  • 多くの人びとが、サブクエリーを複雑な結合や和集合より読みやすいと感じています。実際、早期の SQL である構造化クエリー言語を呼び出すという元の考え方を人びとに提供したのは、サブクエリーの技術革新でした。

SQL 標準で指定され、MySQL でサポートされているサブクエリー構文に関する主なポイントを示すステートメントの例を次に示します。

DELETE FROM t1
WHERE s11 > ANY (SELECT COUNT(*) 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)));

サブクエリーは、スカラー (単一値)、単一行、単一カラム、またはテーブル (1 つ以上のカラムの 1 つ以上の行) を返すことができます。これらは、スカラー、カラム、行、およびテーブルサブクエリーと呼ばれます。特定の種類の結果を返すサブクエリーは多くの場合、次の各セクションで説明されているように、特定のコンテキストでのみ使用できます。

サブクエリーを使用できるステートメントのタイプに関する制限はほとんどありません。サブクエリーには、DISTINCTGROUP BYORDER BYLIMIT、結合、インデックスヒント、UNION 構造構文、コメント、関数などの、通常の SELECT に含めることのできる多くのキーワードや句を含めることができます。

サブクエリーの外部ステートメントは、SELECTINSERTUPDATEDELETESETDO のいずれでもかまいません。

MySQL では、テーブルを変更し、さらにサブクエリーで同じテーブルから選択することはできません。これは、DELETEINSERTREPLACEUPDATELOAD DATA INFILE (サブクエリーは SET 句で使用できるため) などのステートメントに適用されます。

オプティマイザによるサブクエリーの処理方法については、セクション8.2.1.18「サブクエリーの最適化」を参照してください。サブクエリーの使用に関する制限の説明 (特定の形式のサブクエリー構文でのパフォーマンスの問題を含む) については、セクションD.4「サブクエリーの制約」を参照してください。

13.2.10.1 スカラーオペランドとしてのサブクエリー

もっとも単純な形式のサブクエリーは、単一値を返すスカラーサブクエリーです。スカラーサブクエリーは単純なオペランドであるため、単一カラム値またはリテラルが正当である場所であればほぼどこでも使用できるほか、データ型、長さ、NULL にできることの表示などの、すべてのオペランドが持っている特性を持つことを期待できます。例:

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

この SELECT 内のサブクエリーは、CHAR のデータ型、5 の長さ、CREATE TABLE の時点で有効なデフォルトに等しい文字セットと照合順序、およびこのカラム内の値を NULL にできることの表示を持つ単一値 ('abcde') を返します。サブクエリー結果が空であればその結果は NULL になるため、スカラーサブクエリーによって選択された値の NULL 可能性はコピーされません。今示したサブクエリーで t1 が空であった場合は、s2NOT NULL であるにもかかわらず、その結果は NULL になります。

スカラーサブクエリーを使用できないコンテキストがいくつか存在します。ステートメントでリテラル値のみが許可されている場合は、サブクエリーを使用できません。たとえば、LIMIT にはリテラル整数の引数が必要であり、LOAD DATA INFILE にはリテラル文字列のファイル名が必要です。サブクエリーを使用してこれらの値を指定することはできません。

次の各セクションにある、やや簡素な構造構文 (SELECT column1 FROM t1) が含まれた例を参照するときは、はるかに多様で、かつ複雑な構造構文を含む独自のコードがあるものと考えてください。

次の 2 つのテーブルを作成するとします。

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

次に、SELECT を実行します。

SELECT (SELECT s1 FROM t2) FROM t1;

t2 には、2 の値を持つカラム s1 が含まれている行が存在するため、その結果は 2 になります。

スカラーサブクエリーを式の一部にすることはできますが、そのサブクエリーが関数への引数を提供するオペランドである場合でも、括弧を忘れないでください。例:

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

13.2.10.2 サブクエリーを使用した比較

サブクエリーのもっとも一般的な使用の形式は次のとおりです。

non_subquery_operandcomparison_operator (subquery)

ここで、comparison_operator は次の演算子のいずれかです。

= > < >= <= <> != <=>

例:

... WHERE 'a' = (SELECT column1 FROM t1)

MySQL では、次の構造構文も許可されます。

non_subquery_operand LIKE (subquery)

以前は、サブクエリーの唯一の正当な場所は比較の右側であり、この方法にこだわったいくつかの古い DBMS がまだ見つかることもあります。

結合では実行できない一般的な形式のサブクエリー比較の例を次に示します。これは、column1 値がテーブル t2 内の最大値に等しいテーブル t1 内のすべての行を検索します。

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

次に別の例を示します。これもまた、いずれかのテーブルに対する集約が含まれているため、結合では実行できません。これは、特定のカラムに 2 回現れる値を含むテーブル t1 内のすべての行を検索します。

SELECT * FROM t1 AS t WHERE 2 = (SELECT COUNT(*) FROM t1 WHERE t1.id = t.id);

スカラーに対するサブクエリーの比較の場合、サブクエリーはスカラーを返す必要があります。行コンストラクタに対するサブクエリーの比較の場合、サブクエリーは、その行コンストラクタと同じ数の値を含む行を返す行サブクエリーである必要があります。セクション13.2.10.5「行サブクエリー」を参照してください。

13.2.10.3 ANY、IN、または SOME を使用したサブクエリー

構文:

operandcomparison_operator ANY (subquery)operand IN (subquery)operandcomparison_operator SOME (subquery)

ここで、comparison_operator は次の演算子のいずれかです。

= > < >= <= <> !=

ANY キーワード (これは比較演算子のあとに指定する必要があります) は、このサブクエリーが返すカラム内の値の ANY (いずれか) に対して比較が TRUE である場合は TRUE を返すことを示します。例:

SELECT s1 FROM t1 WHERE s1 > ANY (SELECT s1 FROM t2);

テーブル t1 内に (10) を含む行が存在するとします。テーブル t2(21,14,7) が含まれている場合、t2 には 10 より小さい値 7 が存在するため、この式は TRUE です。テーブル t2(20,10) が含まれている場合、またはテーブル t2 が空である場合、この式は FALSE です。テーブル t2(NULL,NULL,NULL) が含まれている場合、この式は不明 (つまり、NULL) です。

サブクエリーで使用されている場合、ワード IN= ANY のエイリアスです。そのため、次の 2 つのステートメントは同じです。

SELECT s1 FROM t1 WHERE s1 = ANY (SELECT s1 FROM t2);
SELECT s1 FROM t1 WHERE s1 IN (SELECT s1 FROM t2);

式リストで使用されている場合、IN= ANY はシノニムではありません。IN は式リストを取得できますが、= ANY はできません。セクション12.3.2「比較関数と演算子」を参照してください。

NOT IN<> ANY ではなく、<> ALL のエイリアスです。セクション13.2.10.4「ALL を使用したサブクエリー」を参照してください。

ワード SOMEANY のエイリアスです。そのため、次の 2 つのステートメントは同じです。

SELECT s1 FROM t1 WHERE s1 <> ANY (SELECT s1 FROM t2);
SELECT s1 FROM t1 WHERE s1 <> SOME (SELECT s1 FROM t2);

ワード SOME はほとんど使用されませんが、この例は、これがなぜ役立つ可能性があるかを示しています。ほとんどの人びとにとって、a is not equal to any b(a はどの b にも等しくない) という英語のフレーズはthere is no b which is equal to a(a に等しい b は存在しない) を示しますが、それはこの SQL 構文が示す内容とは異なります。この構文は、there is some b to which a is not equal(a に等しくない b がいくつか存在する) を示します。代わりに <> SOME を使用すると、このクエリーの本当の意味がすべての人に理解されるようにするのに役立ちます。

13.2.10.4 ALL を使用したサブクエリー

構文:

operandcomparison_operator ALL (subquery)

ワード ALL (これは比較演算子のあとに指定する必要があります) は、このサブクエリーが返すカラム内の値の ALL (すべて) に対して比較が TRUE である場合は TRUE を返すことを示します。例:

SELECT s1 FROM t1 WHERE s1 > ALL (SELECT s1 FROM t2);

テーブル t1 内に (10) を含む行が存在するとします。テーブル t2(-5,0,+5) が含まれている場合、10t2 内の 3 つのすべての値より大きいため、この式は TRUE です。テーブル t2(12,6,NULL,-100) が含まれている場合、テーブル t2 には 10 より大きい単一値 12 が存在するため、この式は FALSE です。テーブル t2(0,NULL,1) が含まれている場合、この式は不明 (つまり、NULL) です。

最後に、テーブル t2 が空である場合、この式は TRUE です。そのため、テーブル t2 が空であるとき、次の式は TRUE です。

SELECT * FROM t1 WHERE 1 > ALL (SELECT s1 FROM t2);

ただし、テーブル t2 が空であるとき、次の式は NULL です。

SELECT * FROM t1 WHERE 1 > (SELECT s1 FROM t2);

さらに、テーブル t2 が空であるとき、次の式は NULL です。

SELECT * FROM t1 WHERE 1 > ALL (SELECT MAX(s1) FROM t2);

一般に、NULL 値を含むテーブル空のテーブルエッジケースです。サブクエリーを記述するときは、常に、これらの 2 つの可能性を考慮に入れたかどうかを考慮してください。

NOT IN<> ALL のエイリアスです。そのため、次の 2 つのステートメントは同じです。

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.10.5 行サブクエリー

ここまでの説明は、スカラーまたはカラムサブクエリー、つまり、単一値または値のカラムを返すサブクエリーについてでした。行サブクエリーは、単一行を返し、そのために複数のカラム値を返すことができるサブクエリーバリアントです。行サブクエリーの比較のための正当な演算子は次のとおりです。

= > < >= <= <> != <=>

次に、2 つの例を示します。

SELECT * FROM t1 WHERE (col1,col2) = (SELECT col3, col4 FROM t2 WHERE id = 10);
SELECT * FROM t1 WHERE ROW(col1,col2) = (SELECT col3, col4 FROM t2 WHERE id = 10);

どちらのクエリーでも、テーブル t2id = 10 を持つ単一行が含まれている場合、このサブクエリーは単一行を返します。この行に t1 内のいずれかの行の col1 および col2 値に等しい col3 および col4 値が含まれている場合、WHERE 式は TRUE であり、各クエリーはこれらの t1 行を返します。t2 行の col3 および col4 値が、いずれの t1 行の col1 および col2 値にも等しくない場合、この式は FALSE であり、このクエリーは空の結果セットを返します。サブクエリーによって行が生成されない場合、この式は不明 (つまり、NULL) です。サブクエリーによって複数の行が生成される場合は、行サブクエリーが最大で 1 行しか返すことができないため、エラーが発生します。

(1,2)ROW(1,2) は、行コンストラクタとも呼ばれます。この 2 つは同等です。行コンストラクタと、サブクエリーによって返される行には、同じ数の値が含まれている必要があります。

行コンストラクタは、2 つ以上のカラムを返すサブクエリーとの比較に使用されます。サブクエリーが単一カラムを返すと、これは行ではなく、スカラー値として見なされるため、少なくとも 2 つのカラムを返さないサブクエリーで行コンストラクタを使用することはできません。そのため、次のクエリーは構文エラーで失敗します。

SELECT * FROM t1 WHERE ROW(1) = (SELECT column1 FROM t2)

行コンストラクタは、ほかのコンテキストでも正当です。たとえば、次の 2 つのステートメントは意味的に同等です (また、オプティマイザによって同じように処理されます)。

SELECT * FROM t1 WHERE (column1,column2) = (1,1);
SELECT * FROM t1 WHERE column1 = 1 AND column2 = 1;

次のクエリーは、テーブル t2 内にも存在するテーブル t1 内のすべての行を検索するという要求にこたえます。

SELECT column1,column2,column3 FROM t1 WHERE (column1,column2,column3) IN (SELECT column1,column2,column3 FROM t2);

13.2.10.6 EXISTS または NOT EXISTS を使用したサブクエリー

サブクエリーが少なくとも 1 行を返す場合、EXISTS subqueryTRUE であり、NOT EXISTS subqueryFALSE です。例:

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

従来より、EXISTS サブクエリーは SELECT * で始まりますが、SELECT 5SELECT column1、あるいはほかの何で始まってもかまいません。MySQL はこのようなサブクエリー内の SELECT リストを無視するため、何も違いは生まれません。

前の例では、t2 に何らかの行が含まれている場合 (NULL 値以外は何も含まれていない行でも)、EXISTS 条件は TRUE です。[NOT] EXISTS サブクエリーには、ほぼ常に相互関係が含まれるため、これは実際にはありそうにもない例です。次に、より現実的な例をいくつか示します。

  • 1 つ以上の市に存在するのはどのような種類のお店ですか?

    SELECT DISTINCT store_type FROM stores WHERE EXISTS (SELECT * FROM cities_stores WHERE cities_stores.store_type = stores.store_type);
  • どの市にも存在しないのはどのような種類のお店ですか?

    SELECT DISTINCT store_type FROM stores WHERE NOT EXISTS (SELECT * FROM cities_stores WHERE cities_stores.store_type = stores.store_type);
  • すべての市に存在するのはどのような種類のお店ですか?

    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));

最後の例は、二重にネストされた NOT EXISTS クエリーです。つまり、NOT EXISTS 句の中に NOT EXISTS 句が存在します。これは正式には、Stores にないお店が含まれている市は存在しますか? という質問に答えます。ただし、ネストされた NOT EXISTS が、x はすべての y に対して TRUE ですか?という質問に答えるという方が簡単です。

13.2.10.7 相関サブクエリー

相関サブクエリーは、外部クエリーにも現れるテーブルへの参照を含むサブクエリーです。例:

SELECT * FROM t1 WHERE column1 = ANY (SELECT column1 FROM t2 WHERE t2.column2 = t1.column2);

このサブクエリーには、サブクエリーの FROM 句でテーブル t1 が指定されていない場合でも、t1 のカラムへの参照が含まれます。そのため、MySQL はこのサブクエリーの外部を探し、外部クエリー内の t1 を見つけます。

テーブル t1column1 = 5 かつ column2 = 6 である行が含まれている一方、テーブル t2column1 = 5 かつ column2 = 7 である行が含まれているとします。単純な式 ... WHERE column1 = ANY (SELECT column1 FROM t2)TRUE になりますが、この例では、サブクエリー内の WHERE 句は ((5,6)(5,7) に等しくないため) FALSE です。そのため、全体としての式は FALSE です。

スコープルール: MySQL は、内部から外部に評価します。例:

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));

このステートメントでは、SELECT column1 FROM t2 AS x ...t2 の名前を変更するため、x.column2 はテーブル t2 内のカラムである必要があります。SELECT column1 FROM t1 ...さらに外部にある外部クエリーであるため、これはテーブル t1 内のカラムではありません。

HAVING または ORDER BY 句内のサブクエリーの場合、MySQL は外部選択リスト内でもカラム名を探します。

特定のケースでは、相関サブクエリーが最適化されます。例:

val IN (SELECT key_val FROM tbl_name WHERE correlated_condition)

そうしないと、これらは非効率的であり、遅くなる可能性があります。クエリーを結合として書き換えると、パフォーマンスが向上することがあります。

相関サブクエリー内の集約関数には、その関数に外部参照以外は何も含まれておらず、かつその関数が別の関数または式に含まれていない場合、外部参照を含めることができます。

13.2.10.8 FROM 句内のサブクエリー

サブクエリーは、SELECT ステートメントの FROM 句内で正当です。その実際の構文は次のとおりです。

SELECT ... FROM (subquery) [AS] name ...

FROM 句内のどのテーブルも名前を持っている必要があるため、[AS] name 句は必須です。subquery 選択リスト内にカラムが存在する場合は、それが一意の名前を持っている必要があります。

説明のために、次のテーブルがあるとします。

CREATE TABLE t1 (s1 INT, s2 CHAR(5), s3 FLOAT);

このテーブルの例を使用して、FROM 句内のサブクエリーを使用する方法を次に示します。

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;

結果: 2, '2', 4.0

次に別の例を示します。グループ化されたテーブルに関する一連の合計の平均を知りたいとします。次のクエリーは機能しません。

SELECT AVG(SUM(column1)) FROM t1 GROUP BY column1;

ただし、次のクエリーは目的の情報を提供します。

SELECT AVG(sum_column1) FROM (SELECT SUM(column1) AS sum_column1 FROM t1 GROUP BY column1) AS t1;

サブクエリー内で使用されているカラム名 (sum_column1) は外部クエリーで認識されます。

FROM 句内のサブクエリーは、スカラー、カラム、行、またはテーブルを返すことができます。FROM 句内のサブクエリーは、JOIN 操作の ON 句内で使用されないかぎり、相関サブクエリーにすることはできません。

MySQL 5.6.3 より前は、FROM 句内のサブクエリーは EXPLAIN ステートメントに対しても実行されます (つまり、派生した一時テーブルが実体化されます)。これは、最適化フェーズ中に上位レベルのクエリーにすべてのテーブルに関する情報が必要であり、かつサブクエリーが実行されないかぎり FROM 句内のサブクエリーによって表されているテーブルを使用できないために発生します。MySQL 5.6.3 の時点では、オプティマイザは派生テーブルに関する情報を別の方法で特定するため、それらの実体化が EXPLAIN に対して発生しません。セクション8.2.1.18.3「FROM 句内のサブクエリー (派生テーブル) の最適化」を参照してください。

特定の状況では、EXPLAIN SELECT を使用してテーブルデータを変更できます。これは、外部クエリーがいずれかのテーブルにアクセスし、内部クエリーが、テーブルの 1 つ以上の行を変更するストアドファンクションを呼び出す場合に発生する可能性があります。データベース d1 内に、次に示すように作成された 2 つのテーブル t1t2 があるとします。

mysql> CREATE DATABASE d1;Query OK, 1 row affected (0.00 sec)
mysql> USE d1;Database changed
mysql> CREATE TABLE t1 (c1 INT);Query OK, 0 rows affected (0.15 sec)
mysql> CREATE TABLE t2 (c1 INT);Query OK, 0 rows affected (0.08 sec)

ここで、t2 を変更するストアドファンクション f1 を作成します。

mysql> DELIMITER //mysql> CREATE FUNCTION f1(p1 INT) RETURNS INTmysql> BEGINmysql> INSERT INTO t2 VALUES (p1);mysql> RETURN p1;mysql> END //Query OK, 0 rows affected (0.01 sec)
mysql> DELIMITER ;

次に示すように、EXPLAIN SELECT でこの関数を直接参照しても、t2 には何も影響を与えません。

mysql> SELECT * FROM t2;Empty set (0.00 sec)
mysql> EXPLAIN SELECT f1(5);+----+-------------+-------+------+---------------+------+---------+------+------+----------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+
| 1 | SIMPLE | NULL | NULL | NULL | NULL | NULL | NULL | NULL | No tables used |
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+
1 row in set (0.00 sec)
mysql> SELECT * FROM t2;Empty set (0.00 sec)

これは、出力の table および Extra カラムでわかるように、SELECT ステートメントがどのテーブルも参照しなかったためです。これはまた、次のネストされた SELECT にも当てはまります。

mysql> EXPLAIN SELECT NOW() AS a1, (SELECT f1(5)) AS a2;+----+-------------+-------+------+---------------+------+---------+------+------+----------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+
| 1 | PRIMARY | NULL | NULL | NULL | NULL | NULL | NULL | NULL | No tables used |
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+
1 row in set, 1 warning (0.00 sec)
mysql> SHOW WARNINGS;+-------+------+------------------------------------------+
| Level | Code | Message |
+-------+------+------------------------------------------+
| Note | 1249 | Select 2 was reduced during optimization |
+-------+------+------------------------------------------+
1 row in set (0.00 sec)
mysql> SELECT * FROM t2;Empty set (0.00 sec)

ただし、外部の SELECT がいずれかのテーブルを参照している場合、オプティマイザはそのサブクエリー内のステートメントも実行します。

mysql> EXPLAIN SELECT * FROM t1 AS a1, (SELECT f1(5)) AS a2;+----+-------------+------------+--------+---------------+------+---------+------+------+---------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+--------+---------------+------+---------+------+------+---------------------+
| 1 | PRIMARY | a1 | system | NULL | NULL | NULL | NULL | 0 | const row not found |
| 1 | PRIMARY | <derived2> | system | NULL | NULL | NULL | NULL | 1 | |
| 2 | DERIVED | NULL | NULL | NULL | NULL | NULL | NULL | NULL | No tables used |
+----+-------------+------------+--------+---------------+------+---------+------+------+---------------------+
3 rows in set (0.00 sec)
mysql> SELECT * FROM t2;+------+
| c1 |
+------+
| 5 |
+------+
1 row in set (0.00 sec)

これはまた、次に示すような EXPLAIN SELECT ステートメントは、t1 内の行ごとに 1 回 BENCHMARK() 関数が実行されるため、実行に長い時間がかかる可能性があることも示しています。

EXPLAIN SELECT * FROM t1 AS a1, (SELECT BENCHMARK(1000000, MD5(NOW())));

13.2.10.9 サブクエリーのエラー

サブクエリーにのみ適用されるエラーがいくつか存在します。このセクションでは、これらについて説明します。

  • サポートされていないサブクエリー構文:

    ERROR 1235 (ER_NOT_SUPPORTED_YET)
    SQLSTATE = 42000
    Message = "This version of MySQL doesn't yet support
    'LIMIT & IN/ALL/ANY/SOME subquery'"

    これは、MySQL が次の形式のステートメントをサポートしていないことを示しています。

    SELECT * FROM t1 WHERE s1 IN (SELECT s2 FROM t2 ORDER BY s1 LIMIT 1)
  • サブクエリーからの正しくないカラム数:

    ERROR 1241 (ER_OPERAND_COL)
    SQLSTATE = 21000
    Message = "Operand should contain 1 column(s)"

    このエラーは、次のような場合に発生します。

    SELECT (SELECT column1, column2 FROM t2) FROM t1;

    目的が行の比較である場合は、複数のカラムを返すサブクエリーを使用できます。ほかのコンテキストでは、サブクエリーはスカラーオペランドである必要があります。セクション13.2.10.5「行サブクエリー」を参照してください。

  • サブクエリーからの正しくない行数:

    ERROR 1242 (ER_SUBSELECT_NO_1_ROW)
    SQLSTATE = 21000
    Message = "Subquery returns more than 1 row"

    このエラーは、サブクエリーが最大で 1 行しか返す必要がないにもかかわらず、複数の行を返すステートメントで発生します。次の例を考えてみます。

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

    SELECT column1 FROM t2 が 1 行だけを返す場合、前のクエリーは機能します。このサブクエリーが複数の行を返す場合は、エラー 1242 が発生します。その場合は、このクエリーを次のように書き換えてください。

    SELECT * FROM t1 WHERE column1 = ANY (SELECT column1 FROM t2);
  • サブクエリー内の誤って使用されているテーブル:

    Error 1093 (ER_UPDATE_TABLE_USED)
    SQLSTATE = HY000
    Message = "You can't specify target table 'x'
    for update in FROM clause"

    このエラーは、テーブルを変更し、さらにサブクエリーで同じテーブルから選択しようとする次のような場合に発生します。

    UPDATE t1 SET column2 = (SELECT MAX(column1) FROM t1);

    サブクエリーは SELECT ステートメントだけでなく、UPDATE および DELETE ステートメント内でも正当であるため、UPDATE ステートメント内の割り当てのためにサブクエリーを使用できます。ただし、サブクエリーの FROM 句と更新のターゲットの両方に同じテーブル (この場合は、テーブル t1) を使用することはできません。

トランザクションストレージエンジンの場合は、サブクエリーが失敗するとステートメント全体が失敗します。非トランザクションストレージエンジンの場合は、エラーが検出される前に行われたデータ変更が保持されます。

13.2.10.10 サブクエリーの最適化

開発が進行中であるため、長期にわたって信頼できる最適化のヒントはありません。次のリストは、試してみる価値のある、興味深いいくつかのコツを示しています。

  • サブクエリーで、行の数や順序に影響を与えるサブクエリー句を使用します。例:

    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);
  • 結合をサブクエリーに置き換えます。たとえば、次を試してみてください:

    SELECT DISTINCT column1 FROM t1 WHERE t1.column1 IN ( SELECT column1 FROM t2);

    次の代替として:

    SELECT DISTINCT t1.column1 FROM t1, t2 WHERE t1.column1 = t2.column1;
  • サブクエリーをサポートしていない古いバージョンの MySQL との互換性のために、一部のサブクエリーを結合に変換できます。ただし、場合によっては、サブクエリーを結合に変換するとパフォーマンスが向上することがあります。セクション13.2.10.11「サブクエリーの結合としての書き換え」を参照してください。

  • 句をサブクエリーの外部から内部に移動します。たとえば、次のクエリーを使用してください:

    SELECT * FROM t1 WHERE s1 IN (SELECT s1 FROM t1 UNION ALL SELECT s1 FROM t2);

    次のクエリーの代替として:

    SELECT * FROM t1 WHERE s1 IN (SELECT s1 FROM t1) OR s1 IN (SELECT s1 FROM t2);

    別の例として、このクエリーを使用してください:

    SELECT (SELECT column1 + 5 FROM t1) FROM t2;

    次のクエリーの代替として:

    SELECT (SELECT column1 FROM t1) + 5 FROM t2;
  • 相関サブクエリーの代わりに行サブクエリーを使用します。たとえば、次のクエリーを使用してください:

    SELECT * FROM t1 WHERE (column1,column2) IN (SELECT column1,column2 FROM t2);

    次のクエリーの代替として:

    SELECT * FROM t1 WHERE EXISTS (SELECT * FROM t2 WHERE t2.column1=t1.column1 AND t2.column2=t1.column2);
  • a <> ALL (...) ではなく、NOT (a = ANY (...)) を使用します。

  • x=1 OR x=2 ではなく、x = ANY (table containing (1,2)) を使用します。

  • EXISTS ではなく、= ANY を使用します。

  • 常に 1 行を返す非相関サブクエリーの場合、IN は常に = より低速です。たとえば、次のクエリーを使用してください:

    SELECT * FROM t1 WHERE t1.col_name = (SELECT a FROM t2 WHERE b = some_const);

    次のクエリーの代替として:

    SELECT * FROM t1 WHERE t1.col_name IN (SELECT a FROM t2 WHERE b = some_const);

これらのコツにより、プログラムは速くなる場合も遅くなる場合もあります。BENCHMARK() 関数などの MySQL 機能を使用すると、現在の状況に何が役立つかについてのアイデアを得ることができます。セクション12.14「情報関数」を参照してください。

MySQL 自体が行ういくつかの最適化を次に示します。

  • MySQL は、非相関サブクエリーを 1 回だけ実行します。特定のサブクエリーが実際に非相関になるようにするには、EXPLAIN を使用します。

  • MySQL は、サブクエリー内の選択リストカラムにインデックスが設定される可能性を利用しようとして、INALLANY、および SOME サブクエリーを書き換えます。

  • MySQL は、次の形式のサブクエリーをインデックス検索関数に置き換えます。この関数は、EXPLAIN によって特殊な結合型 (unique_subquery または index_subquery) として記述されます。

    ... IN (SELECT indexed_column FROM single_table ...)
  • MySQL は次の形式の式を、NULL 値または空のセットが含まれていないかぎり、MIN() または MAX() を含む式に拡張します。

    value {ALL|ANY|SOME} {> | < | >= | <=} (uncorrelated subquery)

    たとえば、次の WHERE

    WHERE 5 > ALL (SELECT x FROM t)

    は、オプティマイザによって次のように処理される可能性があります。

    WHERE 5 > (SELECT MAX(x) FROM t)

MySQL Internals: How MySQL Transforms Subqueries」も参照してください。

13.2.10.11 サブクエリーの結合としての書き換え

場合によっては、一連の値におけるメンバーシップをテストするために、サブクエリーを使用する以外の方法が存在することがあります。また、クエリーをサブクエリーなしで書き換えることが可能なだけでなく、サブクエリーを使用する代わりにこれらの手法のいくつかを使用する方が効率的になる場合もあります。これらのうちの 1 つが IN() 構造構文です。

たとえば、次のクエリー

SELECT * FROM t1 WHERE id IN (SELECT id FROM t2);

は次のように書き換えることができます。

SELECT DISTINCT t1.* FROM t1, t2 WHERE t1.id=t2.id;

次のクエリー

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);

は次のように書き換えることができます。

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

LEFT [OUTER] JOIN は、サーバーがそれをより適切に最適化できる可能性がある (MySQL Server だけに特有の事実ではありません) ため、同等のサブクエリーより高速になる場合があります。SQL-92 より前は、外部結合が存在しなかったため、サブクエリーが特定の処理を実行するための唯一の方法でした。今日では、MySQL Server やその他の多くの最新データベースシステムがさまざまなタイプの外部結合を提供しています。

MySQL Server は、1 つのテーブルからの情報や、場合によっては一度に多数のテーブルからの情報に基づいて行を効率的に削除するために使用できる複数テーブルの DELETE ステートメントをサポートしています。また、複数テーブルの UPDATE ステートメントもサポートされています。セクション13.2.2「DELETE 構文」およびセクション13.2.11「UPDATE 構文」を参照してください。

13.2.11 UPDATE 構文

単一テーブル構文:

UPDATE [LOW_PRIORITY] [IGNORE] table_reference SET col_name1={expr1|DEFAULT} [, col_name2={expr2|DEFAULT}] ... [WHERE where_condition] [ORDER BY ...] [LIMIT row_count]

複数テーブル構文:

UPDATE [LOW_PRIORITY] [IGNORE] table_references SET col_name1={expr1|DEFAULT} [, col_name2={expr2|DEFAULT}] ... [WHERE where_condition]

単一テーブル構文の場合、UPDATE ステートメントは、指定されたテーブル内の既存の行のカラムを新しい値に更新します。SET 句は、変更するカラムと、それらのカラムに指定される値を示します。各値は式か、またはカラムを明示的にそのデフォルト値に設定するキーワード DEFAULT として指定できます。WHERE 句 (指定されている場合) は、どの行を更新するかを識別する条件を指定します。WHERE 句がない場合は、すべての行が更新されます。ORDER BY 句が指定されている場合は、指定されている順序で行が更新されます。LIMIT 句は、更新できる行数に制限を設定します。

複数テーブル構文の場合、UPDATE は、条件を満たす table_references で指定されている各テーブル内の行を更新します。一致した各行は、条件に複数回一致した場合でも、1 回更新されます。複数テーブル構文の場合は、ORDER BY および LIMIT を使用できません。

パーティション化されたテーブルの場合は、このステートメントの単一テーブルと複数テーブルの両方の形式で、テーブル参照の一部としての PARTITION オプションの使用がサポートされます。このオプションは、1 つ以上のパーティションまたはサブパーティション (またはその両方) のリストを受け取ります。リストされているパーティション (またはサブパーティション) だけが一致をチェックされ、これらのパーティションまたはサブパーティションのいずれにも存在しない行は、where_condition を満たすかどうかにかかわらず更新されません。

注記

INSERT または REPLACE ステートメントで PARTITION を使用している場合とは異なり、それ以外は有効な UPDATE ... PARTITION ステートメントは、リストされているパーティション (またはサブパーティション) 内のどの行も where_condition に一致しない場合でも成功したと見なされます。

詳細および例については、セクション19.5「パーティション選択」を参照してください。

where_condition は、更新される各行に対して true に評価される式です。式の構文については、セクション9.5「式の構文」を参照してください。

table_referenceswhere_condition は、セクション13.2.9「SELECT 構文」で説明されているように指定されます。

実際に更新された、UPDATE 内で参照されているカラムに対してのみ UPDATE 権限が必要です。読み取られるが、変更されないカラムに対しては、SELECT 権限のみが必要です。

UPDATE ステートメントは、次の修飾子をサポートします。

  • LOW_PRIORITY キーワードを使用すると、UPDATE の実行は、ほかのどのクライアントもそのテーブルから読み取らなくなるまで遅延されます。これは、テーブルレベルロックのみを使用するストレージエンジン (MyISAMMEMORY、および MERGE) にのみ影響を与えます。

  • IGNORE キーワードを指定すると、更新中にエラーが発生した場合でも、更新ステートメントは中止されません。一意のキー値に関して重複キーの競合が発生した行は更新されません。データ変換エラーの原因になる値に更新された行は、代わりに、もっとも近い有効な値に更新されます。

MySQL 5.6.4 以降では、UPDATE IGNORE ステートメント (ORDER BY 句が存在するものを含む)、には、ステートメントベースのレプリケーションには安全でないというフラグが付けられます。(これは、どの行が無視されるかが、行が更新される順序によって決定されるためです。)この変更により、このようなステートメントは、ステートメントベースモードを使用しているときはログ内に警告を生成し、MIXED モードを使用しているときは行ベース形式を使用してログに記録されます。(Bug #11758262、Bug #50439) 詳細は、セクション17.1.2.3「バイナリロギングでの安全および安全でないステートメントの判断」を参照してください。

式で更新されるテーブルのカラムにアクセスする場合、UPDATE はそのカラムの現在の値を使用します。たとえば、次のステートメントは、col1 をその現在の値より 1 大きい値に設定します。

UPDATE t1 SET col1 = col1 + 1;

次のステートメントの 2 番目の割り当ては、col2 を元の col1 値ではなく、現在の (更新された) col1 値に設定します。この結果、col1col2 の値が同じになります。この動作は標準 SQL とは異なります。

UPDATE t1 SET col1 = col1 + 1, col2 = col1;

単一テーブルの UPDATE の割り当ては一般に、左から右に評価されます。複数テーブルの更新では、割り当てが特定の順序で実行される保証はありません。

カラムをその現在の値に設定した場合は、MySQL がこれに気付き、その更新を行いません。

NOT NULL として宣言されているカラムを NULL に設定することによって更新すると、厳密な SQL モードが有効になっている場合は、エラーが発生します。そうでない場合、カラムはそのカラムデータ型の暗黙のデフォルト値に設定され、警告数が 1 増やされます。暗黙のデフォルト値は、数値型では 0、文字列型では空の文字列 ('')、および日付と時間型では0の値です。セクション11.6「データ型デフォルト値」を参照してください。

UPDATE は、実際に変更された行数を返します。mysql_info() C API 関数は、一致して更新された行数と、UPDATE 中に発生した警告の数を返します。

LIMIT row_count を使用すると、UPDATE のスコープを制限できます。LIMIT 句は、一致した行の制限です。このステートメントは、実際に変更されたかどうかにかかわらず、WHERE 句を満たす row_count 行を見つけるとすぐに停止します。

UPDATE ステートメントに ORDER BY 句が含まれている場合は、この句で指定されている順序で行が更新されます。これは、通常であればエラーが発生する可能性のある特定の状況で役立つ場合があります。テーブル t に、一意のインデックスを持つカラム id が含まれているとします。次のステートメントは、行が更新される順序によっては、重複キーエラーで失敗する可能性があります。

UPDATE t SET id = id + 1;

たとえば、このテーブルの id カラムに 1 と 2 が含まれており、2 が 3 に更新される前に 1 が 2 に更新された場合は、エラーが発生します。この問題を回避するには、大きな id 値を持つ行が小さな値を持つ行の前に更新されるように、ORDER BY 句を追加します。

UPDATE t SET id = id + 1 ORDER BY id DESC;

また、複数のテーブルを範囲に含む UPDATE 操作を実行することもできます。ただし、複数テーブルの UPDATE では ORDER BY または LIMIT を使用できません。table_references 句は、結合に含まれるテーブルをリストします。その構文については、セクション13.2.9.2「JOIN 構文」で説明されています。次に例を示します。

UPDATE items,month SET items.price=month.price
WHERE items.id=month.id;

前の例は、カンマ演算子を使用する内部結合を示していますが、複数テーブルの UPDATE ステートメントは、SELECT ステートメント内で許可されている任意の型の結合 (LEFT JOIN など) を使用できます。

外部キー制約が存在する InnoDB テーブルを含む、複数テーブルの UPDATE ステートメントを使用した場合は、MySQL オプティマイザが、それらの親子関係の順序とは異なる順序でテーブルを処理する可能性があります。この場合、このステートメントは失敗し、ロールバックされます。代わりに、1 つのテーブルを更新したあと、InnoDB が提供する ON UPDATE 機能を使用して、ほかのテーブルがそれに応じて変更されるようにします。セクション14.6.6「InnoDB と FOREIGN KEY 制約」を参照してください。

現在、テーブルを更新し、さらにサブクエリーで同じテーブルから選択することはできません。

MySQL 5.6.6 より前は、テーブルレベルのロックを採用した MyISAM などのストレージエンジンを使用しているパーティション化されたテーブルに対する UPDATE によって、そのテーブルのすべてのパーティションがロックされました。これは、UPDATE ... PARTITION クエリーにも当てはまりました。(これは、行レベルロックを採用した InnoDB などのストレージエンジンでは発生しておらず、現在も発生しません。)MySQL 5.6.6 以降では、MySQL はパーティションロックプルーニングを使用します。これにより、そのテーブルのいずれかのパーティション化カラムが更新されないかぎり、UPDATE ステートメントの WHERE 句に一致する行を含むパーティションだけが実際にロックされるようになります。詳細は、セクション19.6.4「パーティショニングとロック」を参照してください。

13.3 MySQL トランザクションおよびロックステートメント

MySQL は、SET autocommitSTART TRANSACTIONCOMMITROLLBACK などのステートメントを介して (特定のクライアントセッション内の) ローカルトランザクションをサポートしています。セクション13.3.1「START TRANSACTION、COMMIT、および ROLLBACK 構文」を参照してください。XA トランザクションサポートにより、MySQL は分散トランザクションにも参加できます。セクション13.3.7「XA トランザクション」を参照してください。

13.3.1 START TRANSACTION、COMMIT、および ROLLBACK 構文

START TRANSACTION [transaction_characteristic [, transaction_characteristic] ...]transaction_characteristic: WITH CONSISTENT SNAPSHOT | READ WRITE | READ ONLY
BEGIN [WORK]
COMMIT [WORK] [AND [NO] CHAIN] [[NO] RELEASE]
ROLLBACK [WORK] [AND [NO] CHAIN] [[NO] RELEASE]
SET autocommit = {0 | 1}

次のステートメントにより、トランザクションの使用を制御できます。

  • START TRANSACTION または BEGIN は、新しいトランザクションを開始します。

  • COMMIT は、現在のトランザクションをコミットして、その変更を永続的なものにします。

  • ROLLBACK は、現在のトランザクションをロールバックして、その変更を取り消します。

  • SET autocommit は、現在のセッションのデフォルトの自動コミットモードを無効または有効にします。

デフォルトでは、MySQL は自動コミットモードが有効になった状態で動作します。つまり、テーブルを更新 (変更) するステートメントを実行するとすぐに、MySQL によってその更新がディスクに格納されて永続的になります。この変更はロールバックできません。

一連のステートメントに対して自動コミットモードを暗黙的に無効にするには、START TRANSACTION ステートメントを使用します。

START TRANSACTION;
SELECT @A:=SUM(salary) FROM table1 WHERE type=1;
UPDATE table2 SET summary=@A WHERE type=1;
COMMIT;

START TRANSACTION を使用すると、そのトランザクションを COMMIT または ROLLBACK で終了するまで、自動コミットは無効のままになります。そのあと、自動コミットモードはその以前の状態に戻ります。

START TRANSACTION では、トランザクションの特性を制御するいくつかの修飾子が許可されます。複数の修飾子を指定するには、それらをカンマで区切ります。

  • WITH CONSISTENT SNAPSHOT 修飾子は、この機能に対応しているストレージエンジンでの一貫性読み取りを開始します。これは、InnoDB にのみ適用されます。その効果は、任意の InnoDB テーブルから START TRANSACTION に続けて SELECT を発行することと同じです。セクション14.2.4「一貫性非ロック読み取り」を参照してください。WITH CONSISTENT SNAPSHOT 修飾子は、現在のトランザクション分離レベルを変更しないため、現在の分離レベルが一貫性読み取りを許可するものである場合にのみ、整合性のあるスナップショットを提供します。一貫性読み取りを許可する分離レベルは、REPEATABLE READ だけです。その他のすべての分離レベルの場合、WITH CONSISTENT SNAPSHOT 句は無視されます。

  • READ WRITE および READ ONLY 修飾子は、トランザクションアクセスモードを設定します。これらは、そのトランザクションで使用されるテーブルへの変更を許可または禁止します。READ ONLY の制限は、そのトランザクションが、ほかのトランザクションに表示されるトランザクションテーブルと非トランザクションテーブルの両方を変更またはロックしないようにします。このトランザクションは引き続き、一時テーブルを変更またはロックできます。これらの修飾子は、MySQL 5.6.5 の時点で使用できます。

    MySQL では、トランザクションが読み取り専用であることがわかっている場合、InnoDB テーブルに対するクエリーの追加の最適化が可能です。READ ONLY を指定すると、読み取り専用ステータスを自動的に特定できない場合に、これらの最適化が適用されることが保証されます。詳細は、セクション14.13.14「InnoDB の読み取り専用トランザクションの最適化」を参照してください。

    アクセスモードが指定されていない場合は、デフォルトモードが適用されます。デフォルトが変更されていないかぎり、それは読み取り/書き込みです。同じステートメント内で READ WRITEREAD ONLY の両方を指定することは許可されません。

    読み取り専用モードでは、DML ステートメントを使用して TEMPORARY キーワードで作成されたテーブルは引き続き変更できます。永続的なテーブルと同様に、DDL ステートメントによって行われる変更は許可されません。

    トランザクションアクセスモードの詳細 (デフォルトモードを変更する方法を含む) は、セクション13.3.6「SET TRANSACTION 構文」を参照してください。

    read_only システム変数が有効になっている場合、トランザクションを START TRANSACTION READ WRITE で明示的に開始するには、SUPER 権限が必要です。

重要

MySQL クライアントアプリケーションを記述するために使用される多くの API (JDBC など) は、クライアントから START TRANSACTION ステートメントを送信する代わりに使用できる (また、場合によっては使用すべき)、トランザクションを開始するための独自のメソッドを提供しています。詳細は、第23章「Connector および APIまたは API のドキュメントを参照してください。

自動コミットモードを明示的に無効にするには、次のステートメントを使用します。

SET autocommit=0;

autocommit 変数を 0 に設定することによって自動コミットモードを無効にしたあと、トランザクションセーフテーブル (InnoDB または NDB のテーブルなど) への変更がただちに永続的になることはありません。COMMIT を使用して変更をディスクに格納するか、または ROLLBACK を使用して変更を無視する必要があります。

autocommit はセッション変数であるため、セッションごとに設定する必要があります。新しい接続ごとに自動コミットモードを無効にするには、セクション5.1.4「サーバーシステム変数」にある autocommit システム変数の説明を参照してください。

BEGINBEGIN WORK は、トランザクションを開始するための START TRANSACTION のエイリアスとしてサポートされています。標準の SQL 構文である START TRANSACTION は、アドホックトランザクションを開始するための推奨される方法であり、BEGIN では許可されない修飾子が許可されます。

BEGIN ステートメントは、BEGIN ... END 複合ステートメントを開始する BEGIN キーワードの使用とは異なります。後者はトランザクションを開始しません。セクション13.6.1「BEGIN ... END 複合ステートメント構文」を参照してください。

注記

すべてのストアドプログラム (ストアドプロシージャーとストアドファンクション、トリガー、およびイベント) 内で、パーサーは、BEGIN [WORK]BEGIN ... END ブロックの開始として扱います。このコンテキストでは、代わりに START TRANSACTION を使用してトランザクションを開始します。

オプションの WORK キーワードは、CHAIN および RELEASE 句と同様に、COMMITROLLBACK に対してサポートされています。CHAINRELEASE は、トランザクションの完了に対する追加の制御に使用できます。completion_type システム変数の値によって、デフォルトの完了動作が決定されます。セクション5.1.4「サーバーシステム変数」を参照してください。

AND CHAIN 句を指定すると、現在のトランザクションが終了するとすぐに新しいトランザクションが開始され、新しいトランザクションの分離レベルは終了したばかりのトランザクションと同じになります。RELEASE 句を指定すると、サーバーは、現在のトランザクションを終了したあと現在のクライアントセッションを切り離します。NO キーワードを含めると、CHAIN または RELEASE の完了が抑制されます。これは、completion_type システム変数がデフォルトで、チェーンまたはリリースの完了が実行されるように設定されている場合に役立つことがあります。

トランザクションを開始すると、保留中のトランザクションはすべてコミットされます。詳細は、セクション13.3.3「暗黙的なコミットを発生させるステートメント」を参照してください。

また、トランザクションを開始すると、ユーザーが UNLOCK TABLES を実行したかのように、LOCK TABLES によって取得されたテーブルロックも解放されます。トランザクションを開始しても、FLUSH TABLES WITH READ LOCK によって取得されたグローバルな読み取りロックは解放されません。

最適な結果を得るために、トランザクションは、1 つのトランザクションセーフストレージエンジンによって管理されているテーブルのみを使用して実行するようにしてください。そうしないと、次の問題が発生する場合があります。

  • 複数のトランザクションセーフストレージエンジン (InnoDB など) からのテーブルを使用しており、かつトランザクション分離レベルが SERIALIZABLE でない場合は、あるトランザクションがコミットしたときに、同じテーブルを使用している別の進行中のトランザクションに最初のトランザクションによって行われた変更の一部しか表示されない可能性があります。つまり、混在したエンジンではトランザクションのアトミック性が保証されないため、不整合が発生する場合があります。(混在したエンジンでのトランザクションの頻度が低い場合は、SET TRANSACTION ISOLATION LEVEL を使用して、必要に応じてトランザクションごとに分離レベルを SERIALIZABLE に設定できます。)

  • トランザクション内でトランザクションセーフでないテーブルを使用する場合は、自動コミットモードのステータスには関係なく、それらのテーブルへの変更が一度に格納されます。

  • トランザクション内で非トランザクションテーブルを更新したあとに ROLLBACK ステートメントを発行すると、ER_WARNING_NOT_COMPLETE_ROLLBACK 警告が発生します。トランザクションセーフテーブルへの変更はロールバックされますが、非トランザクションセーフテーブルへの変更はロールバックされません。

各トランザクションは、COMMIT 時に、1 つのまとまりでバイナリログに格納されます。ロールバックされたトランザクションはログに記録されません。(例外: 非トランザクションテーブルへの変更はロールバックできません。ロールバックされるトランザクションに非トランザクションテーブルへの変更が含まれている場合は、非トランザクションテーブルへの変更が確実にレプリケートされるようにするために、最後に ROLLBACK ステートメントを使用してトランザクション全体がログに記録されます。) セクション5.2.4「バイナリログ」を参照してください。

トランザクションの分離レベルまたはアクセスモードは、SET TRANSACTION ステートメントを使用して変更できます。セクション13.3.6「SET TRANSACTION 構文」を参照してください。

ロールバックは、ユーザーが明示的に求めることなく (たとえば、エラーの発生時に) 暗黙的に発生する可能性のある低速な操作になる場合があります。このため、ROLLBACK ステートメントを使用して実行された明示的なロールバックに対してだけでなく、暗黙のロールバックに対しても、SHOW PROCESSLIST はセッションの State カラムに Rolling back を表示します。

注記

MySQL 5.6 では、BEGINCOMMIT、および ROLLBACK--replicate-do-db または --replicate-ignore-db ルールによって影響を受けません。

13.3.2 ロールバックできないステートメント

いくつかのステートメントはロールバックできません。これには一般に、データベースを作成または削除したり、テーブルやストアドルーチンを作成、削除、または変更したりするデータ定義言語 (DDL) ステートメントが含まれます。

このようなステートメントを含まないようにトランザクションを設計してください。ロールバックできないステートメントをトランザクション内で早期に発行し、そのあと別のステートメントが失敗したとすると、このような場合に ROLLBACK ステートメントを発行してもそのトランザクションのすべての効果をロールバックすることはできません。

13.3.3 暗黙的なコミットを発生させるステートメント

このセクションに示されているステートメント (およびそのすべてのシノニム) は、ユーザーがこのステートメントを実行する前に COMMIT を実行したかのように、現在のセッション内でアクティブなすべてのトランザクションを暗黙的に終了します。MySQL 5.5.3 の時点では、これらのステートメントのほとんどが、実行後に暗黙的なコミットも発生させます。詳細は、このセクションの最後を参照してください。

  • データベースオブジェクトを定義または変更するデータ定義言語 (DDL) ステートメント。ALTER DATABASE ... UPGRADE DATA DIRECTORY NAMEALTER EVENTALTER PROCEDUREALTER SERVERALTER TABLEALTER VIEWCREATE DATABASECREATE EVENTCREATE INDEXCREATE PROCEDURECREATE SERVERCREATE TABLECREATE TRIGGERCREATE VIEWDROP DATABASEDROP EVENTDROP INDEXDROP PROCEDUREDROP SERVERDROP TABLEDROP TRIGGERDROP VIEWRENAME TABLETRUNCATE TABLE

    ALTER FUNCTIONCREATE FUNCTION、および DROP FUNCTION もまた、ストアドファンクション (ただし、UDF を除く) で使用された場合は暗黙的なコミットを発生させます。(ALTER FUNCTION は、ストアドファンクションでのみ使用できます。)

    CREATE TABLE および DROP TABLE ステートメントは、TEMPORARY キーワードが使用されている場合はトランザクションをコミットしません。(これは、コミットを発生させる ALTER TABLECREATE INDEX などの、一時テーブルに対するその他の操作には適用されません。) ただし、暗黙的なコミットは発生しませんが、ステートメントのロールバックもできません。つまり、このようなステートメントを使用すると、トランザクションのアトミック性が侵害されます。たとえば、CREATE TEMPORARY TABLE を使用したあとにトランザクションをロールバックしても、そのテーブルは存在し続けます。

    InnoDB での CREATE TABLE ステートメントは、1 つのトランザクションとして処理されます。つまり、ユーザーが ROLLBACK を発行しても、ユーザーがそのトランザクション中に実行した CREATE TABLE ステートメントは元に戻されません。

    CREATE TABLE ... SELECT は、一時テーブル以外のテーブルを作成している場合、そのステートメントが実行される前後に暗黙的なコミットを発生させます。(CREATE TEMPORARY TABLE ... SELECT に対してコミットは発生しません。)これは、ロールバック後にマスター上でテーブルを作成できたが、バイナリログへの記録に失敗したため、スレーブにはレプリケートされないというレプリケーション中の問題を回避するために行われます。詳細は、Bug #22865 を参照してください。

  • mysql データベース内のテーブルを暗黙的に使用または変更するステートメント。CREATE USERDROP USERGRANTRENAME USERREVOKESET PASSWORD

  • トランザクション制御およびロックステートメント。BEGINLOCK TABLESSET autocommit = 1 (この値がまだ 1 でない場合)、START TRANSACTIONUNLOCK TABLES

    UNLOCK TABLES は、非トランザクションテーブルロックを取得するために現在 LOCK TABLES でロックされているテーブルがある場合にのみ、トランザクションをコミットします。FLUSH TABLES WITH READ LOCK はテーブルレベルのロックを取得しないため、このステートメントに続く UNLOCK TABLES に対してコミットは発生しません。

    トランザクションをネストすることはできません。これは、START TRANSACTION ステートメントまたはそのシノニムのいずれかを発行するときに、現在のすべてのトランザクションに対して実行される暗黙的なコミットの結果です。

    XA トランザクションが ACTIVE 状態にある間に、暗黙的なコミットを発生させるステートメントをそのトランザクションで使用することはできません。

    BEGIN ステートメントは、BEGIN ... END 複合ステートメントを開始する BEGIN キーワードの使用とは異なります。後者は暗黙的なコミットを発生させません。セクション13.6.1「BEGIN ... END 複合ステートメント構文」を参照してください。

  • データロードステートメント。LOAD DATA INFILELOAD DATA INFILE は、NDB ストレージエンジンを使用しているテーブルに対してのみ暗黙的なコミットを発生させます。詳細は、Bug #11151 を参照してください。

  • 管理ステートメント。ANALYZE TABLECACHE INDEXCHECK TABLELOAD INDEX INTO CACHEOPTIMIZE TABLEREPAIR TABLE

  • レプリケーション制御ステートメント。MySQL 5.6.7 から: START SLAVESTOP SLAVERESET SLAVECHANGE MASTER TO。(Bug #13858841)

MySQL 5.5.3 の時点では、以前は実行前に暗黙的なコミットを発生させたステートメントのほとんどが、実行後にも発生させます。その目的は、このような各ステートメントはいずれにしてもロールバックできないため、それを独自の特殊なトランザクションで処理することにあります。次のリストは、この変更に関連する追加の詳細を示しています。

  • 以前は特殊なケースであった CREATE TABLE バリアント (InnoDB テーブルに対する CREATE TABLECREATE TABLE ... SELECT) は、CREATE TABLE が一様に実行の前後に暗黙的なコミットを発生させるため、現在では特殊ではなくなっています。

  • FLUSH および RESET ステートメントは暗黙的なコミットを発生させます。

  • トランザクション制御およびロックステートメントは、以前と同様に動作します。

13.3.4 SAVEPOINT、ROLLBACK TO SAVEPOINT、および RELEASE SAVEPOINT 構文

SAVEPOINT identifierROLLBACK [WORK] TO [SAVEPOINT] identifierRELEASE SAVEPOINT identifier

InnoDB は、SQL ステートメント SAVEPOINTROLLBACK TO SAVEPOINTRELEASE SAVEPOINT のほか、ROLLBACK のオプションの WORK キーワードをサポートしています。

SAVEPOINT ステートメントは、identifier の名前を持つ名前付きのトランザクションセーブポイントを設定します。現在のトランザクションに同じ名前を持つセーブポイントが含まれている場合、古いセーブポイントは削除され、新しいセーブポイントが設定されます。

ROLLBACK TO SAVEPOINT ステートメントは、トランザクションを終了することなく、そのトランザクションを指定されたセーブポイントにロールバックします。セーブポイントが設定されたあとに現在のトランザクションが行に対して行なった変更はロールバックで元に戻されますが、InnoDB は、セーブポイントのあとにメモリーに格納された行ロックを解放しません。(新しく挿入された行の場合、ロック情報は、その行に格納されているトランザクション ID によって伝達されます。ロックが個別にメモリーに格納されるわけではありません。この場合、行ロックは Undo で解放されます。)指定されたセーブポイントよりあとで設定されたセーブポイントは削除されます。

ROLLBACK TO SAVEPOINT ステートメントが次のエラーを返した場合は、指定された名前を持つセーブポイントが存在しないことを示しています。

ERROR 1305 (42000): SAVEPOINT identifier does not exist

RELEASE SAVEPOINT ステートメントは、指定されたセーブポイントを現在のトランザクションの一連のセーブポイントから削除します。コミットまたはロールバックは発生しません。そのセーブポイントが存在しない場合はエラーになります。

COMMIT、またはセーブポイントを指定しない ROLLBACK を実行した場合は、現在のトランザクションのすべてのセーブポイントが削除されます。

ストアドファンクションが呼び出されるか、またはトリガーがアクティブ化されると、新しいセーブポイントレベルが作成されます。以前のレベルにあるセーブポイントは使用できなくなるため、新しいレベルのセーブポイントとは競合しません。関数またはトリガーが終了すると、その関数またはトリガーによって作成されたセーブポイントはすべて解放され、以前のセーブポイントレベルがリストアされます。

13.3.5 LOCK TABLES および UNLOCK TABLES 構文

LOCK TABLES tbl_name [[AS] alias] lock_type [, tbl_name [[AS] alias] lock_type] ...lock_type: READ [LOCAL] | [LOW_PRIORITY] WRITE
UNLOCK TABLES

MySQL では、クライアントセッションは、ほかのセッションと連携してテーブルにアクセスするために、またはそのセッションにテーブルへの排他的アクセスが必要な期間中はほかのセッションによってそのテーブルが変更されないようにするために、明示的にテーブルロックを取得できます。セッションがロックを取得または解放できるのは、それ自体のためだけです。あるセッションが別のセッションのためにロックを取得したり、別のセッションによって保持されているロックを解放したりすることはできません。

ロックを使用すると、トランザクションをエミュレートするか、またはテーブル更新時の速度を向上させることができます。これについては、このセクションのあとの方でさらに詳細に説明されています。

LOCK TABLES は、現在のクライアントセッションのテーブルロックを明示的に取得します。テーブルロックは、ベーステーブルまたはビューに対して取得できます。ロックされる各オブジェクトに対する LOCK TABLES 権限と SELECT 権限が必要です。

ビューのロックの場合、LOCK TABLES は、そのビューで使用されているすべてのベーステーブルをロックされるテーブルのセットに追加し、それらのテーブルを自動的にロックします。セクション13.3.5.2「LOCK TABLES とトリガー」で説明されているように、LOCK TABLES によって明示的にテーブルをロックした場合は、トリガーで使用されているテーブルもすべて暗黙的にロックされます。

UNLOCK TABLES は、現在のセッションによって保持されているテーブルロックをすべて明示的に解放します。LOCK TABLES は、新しいロックを取得する前に、現在のセッションによって保持されているテーブルロックをすべて暗黙的に解放します。

UNLOCK TABLES の別の使用法として、すべてのデータベース内のすべてのテーブルをロックできる FLUSH TABLES WITH READ LOCK ステートメントによって取得されたグローバルな読み取りロックの解放があります。セクション13.7.6.3「FLUSH 構文」を参照してください。(これは、特定時点のスナップショットを取得できる、Veritas などのファイルシステムがある場合にバックアップを取得するための非常に便利な方法です。)

テーブルロックでは、ほかのセッションによる不適切な読み取りまたは書き込みからのみ保護されます。WRITE ロックを保持しているセッションは、DROP TABLETRUNCATE TABLE などのテーブルレベルの操作を実行できます。READ ロックを保持しているセッションの場合、DROP TABLE および TRUNCATE TABLE 操作は許可されません。TRUNCATE TABLE 操作はトランザクションセーフではないため、セッションがアクティブなトランザクション中または READ ロックを保持している間にこの操作を行おうとすると、エラーが発生します。

次の説明は、TEMPORARY 以外のテーブルにのみ適用されます。LOCK TABLESTEMPORARY テーブルに対して許可されます (ただし、無視されます)。テーブルは、ほかのどのようなロックが有効になっているかには関係なく、そのテーブルが作成されたセッションから自由にアクセスできます。ほかのどのセッションもそのテーブルを参照できないため、ロックは必要ありません。

LOCK TABLES の使用に関するその他の条件や、LOCK TABLES が有効になっている間は使用できないステートメントについては、セクション13.3.5.3「テーブルロックの制限と条件」を参照してください。

ロック取得のルール

現在のセッション内でテーブルロックを取得するには、LOCK TABLES ステートメントを使用します。次のロックタイプを使用できます。

READ [LOCAL] ロック:

  • このロックを保持しているセッションは、テーブルを読み取ることができます (ただし、書き込みはできません)。

  • 複数のセッションが同時にテーブルに対する READ ロックを取得できます。

  • ほかのセッションは、READ ロックを明示的に取得することなく、テーブルを読み取ることができます。

  • LOCAL 修飾子を使用すると、ロックが保持されている間、ほかのセッションによる競合しない INSERT ステートメント (並列挿入) を実行できます。(セクション8.10.3「同時挿入」を参照してください。)ただし、ロックを保持している間、サーバーの外部にあるプロセスを使用してデータベースを操作しようとしている場合は、READ LOCAL を使用できません。InnoDB テーブルの場合、READ LOCALREAD と同じです。

[LOW_PRIORITY] WRITE ロック:

  • このロックを保持しているセッションは、テーブルの読み取りおよび書き込みが可能です。

  • このロックを保持しているセッションだけがテーブルにアクセスできます。ロックが解放されるまで、ほかのどのセッションもアクセスできません。

  • WRITE ロックが保持されている間、テーブルに対するほかのセッションからのロック要求はブロックされます。

  • LOW_PRIORITY 修飾子は何の効果もありません。以前のバージョンの MySQL では、ロックの動作に影響を与えましたが、これは当てはまらなくなっています。MySQL 5.6.5 の時点では、これは非推奨であり、使用すると警告が生成されます。代わりに、LOW_PRIORITY のない WRITE を使用してください。

LOCK TABLES ステートメントが、いずれかのテーブルに対するほかのセッションによって保持されているロックのために待機する必要がある場合、このステートメントはすべてのロックを取得できるまでブロックされます。

ロックが必要なセッションは、必要なすべてのロックを 1 つの LOCK TABLES ステートメントで取得する必要があります。このように取得されたロックが保持されている間、このセッションは、ロックされたテーブルにのみアクセスできます。たとえば、次のステートメントシーケンスでは、t2LOCK TABLES ステートメントでロックされていないため、このテーブルにアクセスしようとするとエラーが発生します。

mysql> LOCK TABLES t1 READ;mysql> SELECT COUNT(*) FROM t1;+----------+
| COUNT(*) |
+----------+
| 3 |
+----------+
mysql> SELECT COUNT(*) FROM t2;ERROR 1100 (HY000): Table 't2' was not locked with LOCK TABLES

INFORMATION_SCHEMA データベース内のテーブルは例外です。これらのテーブルは、セッションが LOCK TABLES によって取得されたテーブルロックを保持している間であっても、明示的にロックされることなくアクセスできます。

ロックされたテーブルを、同じ名前を使用して 1 つのクエリーで複数回参照することはできません。代わりにエイリアスを使用し、そのテーブルと各エイリアスのための個別のロックを取得します。

mysql> LOCK TABLE t WRITE, t AS t1 READ;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;

最初の INSERT では、ロックされたテーブルに対する同じ名前への参照が 2 つ存在するため、エラーが発生します。2 番目の INSERT は、テーブルへの参照で異なる名前が使用されるため、成功します。

ステートメントがエイリアスを使用してテーブルを参照する場合は、その同じエイリアスを使用してテーブルをロックする必要があります。エイリアスを指定しないでテーブルをロックすることはできません。

mysql> LOCK TABLE t READ;mysql> SELECT * FROM t AS myalias;ERROR 1100: Table 'myalias' was not locked with LOCK TABLES

逆に、エイリアスを使用してテーブルをロックする場合は、ステートメント内でそのエイリアスを使用してテーブルを参照する必要があります。

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 ロックは通常、更新ができるだけ早く処理されるように、READ ロックより高い優先度を持っています。つまり、あるセッションが READ ロックを取得したあと、別のセッションが WRITE ロックを要求した場合は、WRITE ロックを要求したセッションがロックを取得して解放するまで、以降の READ ロック要求が待たされます。

LOCK TABLES は、次のようにロックを取得します。

  1. ロックされるすべてのテーブルを内部で定義された順序でソートします。ユーザーから見て、この順序は定義されていません。

  2. テーブルを読み取りおよび書き込みロックでロックする場合は、書き込みロック要求を読み取りロック要求の前に配置します。

  3. セッションがすべてのロックを取得するまで、1 回につき 1 つのテーブルをロックします。

このポリシーによって、テーブルロックでデッドロックが発生しないことが保証されます。

注記

LOCK TABLES または UNLOCK TABLES は、パーティション化されたテーブルに適用された場合、常にテーブル全体をロックまたはロック解除します。これらのステートメントは、パーティションロックプルーニングをサポートしていません。セクション19.6.4「パーティショニングとロック」を参照してください。

ロック解放のルール

セッションによって保持されているテーブルロックが解放される場合は、すべてのテーブルロックが一度に解放されます。セッションは明示的にロックを解放できます。また、特定の状況で、ロックが暗黙的に解放される場合もあります。

  • セッションは、UNLOCK TABLES によって明示的にロックを解放できます。

  • セッションがすでにロックを保持している間にロックを取得するために LOCK TABLES ステートメントを発行した場合は、新しいロックが付与される前に、その既存のロックが暗黙的に解放されます。

  • セッションが (たとえば、START TRANSACTION で) トランザクションを開始した場合は、暗黙的な UNLOCK TABLES が実行され、既存のロックが解放されます。(テーブルロックとトランザクションの間の通信の詳細は、セクション13.3.5.1「テーブルロックとトランザクションの通信」を参照してください。)

クライアントセッションの接続が (正常または異常にかかわらず) 終了した場合、サーバーは、そのセッションによって保持されているすべてのテーブルロック (トランザクションおよび非トランザクション) を暗黙的に解放します。そのクライアントが再接続した場合、ロックは有効でなくなります。さらに、クライアントにアクティブなトランザクションがある場合、サーバーは切断時にそのトランザクションをロールバックし、再接続が発生した場合は、自動コミットが有効になった状態で新しいセッションが開始されます。このため、クライアントは自動再接続を無効にすることが必要になる場合があります。自動再接続が有効な場合、再接続が発生してもクライアントには通知されませんが、すべてのテーブルロックまたは現在のトランザクションが失われます。自動再接続が無効になっている場合は、接続が削除されると、発行された次のステートメントに対してエラーが発生します。クライアントはそのエラーを検出し、ロックの再取得やトランザクションの再実行などの適切なアクションを実行できます。セクション23.7.16「自動再接続動作の制御」を参照してください。

注記

ロックされたテーブル上で ALTER TABLE を使用すると、そのテーブルがロック解除される場合があります。たとえば、2 番目の ALTER TABLE 操作を試みると、エラー「テーブル 'tbl_name' は LOCK TABLES でロックされていません」が発生する場合があります。これに対処するには、2 番目の変更の前にテーブルを再度ロックします。セクションB.5.7.1「ALTER TABLE での問題」も参照してください。

13.3.5.1 テーブルロックとトランザクションの通信

LOCK TABLES および UNLOCK TABLES は、トランザクションの使用との間で次のように通信します。

  • LOCK TABLES はトランザクションセーフではないため、テーブルをロックしようとする前に、アクティブなトランザクションをすべて暗黙的にコミットします。

  • UNLOCK TABLES は、アクティブなトランザクションをすべて暗黙的にコミットしますが、これが行われるのは、テーブルロックを取得するために LOCK TABLES が使用された場合のみです。たとえば、次の一連のステートメントでは、UNLOCK TABLES がグローバルな読み取りロックを解放しますが、有効なテーブルロックがないためにトランザクションはコミットされません。

    FLUSH TABLES WITH READ LOCK;
    START TRANSACTION;
    SELECT ... ;
    UNLOCK TABLES;
  • トランザクションを (たとえば、START TRANSACTION で) 開始すると、現在のトランザクションはすべて暗黙的にコミットされ、既存のテーブルロックが解放されます。

  • FLUSH TABLES WITH READ LOCK は、グローバルな読み取りロックを取得しますが、テーブルロックは取得しないため、テーブルロックと暗黙的なコミットに関して LOCK TABLES および UNLOCK TABLES と同じ動作には従いません。たとえば、START TRANSACTION は、グローバルな読み取りロックを解放しません。セクション13.7.6.3「FLUSH 構文」を参照してください。

  • 暗黙的にトランザクションのコミットを発生させるその他のステートメントは、既存のテーブルロックを解放しません。このようなステートメントのリストについては、セクション13.3.3「暗黙的なコミットを発生させるステートメント」を参照してください。

  • トランザクションテーブル (InnoDB テーブルなど) で LOCK TABLES および UNLOCK TABLES を使用するための正しい方法は、SET autocommit = 0 (START TRANSACTION ではなく) に続けて LOCK TABLES を指定することによってトランザクションを開始し、そのトランザクションを明示的にコミットするまで UNLOCK TABLES を呼び出さないことです。たとえば、テーブル t1 に書き込み、テーブル t2 から読み取る必要がある場合は、次のように実行できます。

    SET autocommit=0;
    LOCK TABLES t1 WRITE, t2 READ, ...;... do something with tables t1 and t2 here ...COMMIT;
    UNLOCK TABLES;

    LOCK TABLES を呼び出すと、InnoDB は内部的に独自のテーブルロックを取得し、MySQL は独自のテーブルロックを取得します。InnoDB は次のコミット時に内部のテーブルロックを解放しますが、MySQL でテーブルロックが解放されるようにするには、UNLOCK TABLES を呼び出す必要があります。autocommit = 1 を指定すると、LOCK TABLES の呼び出しの直後に InnoDB によって内部のテーブルロックが解放され、デッドロックが非常に発生しやすくなる場合があるため、この指定は行わないようにしてください。autocommit = 1 が指定された場合、古いアプリケーションが不必要なデッドロックを回避するのに役立つように、InnoDB は内部のテーブルロックをまったく取得しません。

  • ROLLBACK は、テーブルロックを解放しません。

13.3.5.2 LOCK TABLES とトリガー

LOCK TABLES によって明示的にテーブルをロックした場合は、トリガーで使用されているテーブルもすべて暗黙的にロックされます。

  • これらのロックは、LOCK TABLES ステートメントによって明示的に取得されるロックと同時に取得されます。

  • トリガーで使用されているテーブルに対するロックは、そのテーブルが読み取りのみに使用されているかどうかによって異なります。読み取りのみに使用されている場合は、読み取りロックで十分です。そうでない場合は、書き込みロックが使用されます。

  • テーブルが LOCK TABLES によって読み取りに対して明示的にロックされているが、トリガー内で変更される可能性があるために書き込みに対してロックする必要がある場合は、読み取りロックではなく書き込みロックが取得されます。(つまり、トリガー内でのテーブルの表示のために必要な暗黙の書き込みロックによって、テーブルに対する明示的な読み取りロック要求が書き込みロック要求に変換されます。)

次のステートメントを使用して、2 つのテーブル t1t2 をロックするとします。

LOCK TABLES t1 WRITE, t2 READ;

t1 または t2 にトリガーが含まれている場合は、そのトリガー内で使用されているテーブルもロックされます。t1 に、次のように定義されたトリガーが含まれているとします。

CREATE TRIGGER t1_a_ins AFTER INSERT ON t1 FOR EACH ROW
BEGIN UPDATE t4 SET count = count+1 WHERE id = NEW.id AND EXISTS (SELECT a FROM t3); INSERT INTO t2 VALUES(1, 2);
END;

LOCK TABLES ステートメントの結果として、t1t2 は、このステートメントに現れるためにロックされます。また、t3t4 は、トリガー内で使用されているためにロックされます。

  • t1 は、WRITE ロック要求ごとに、書き込みに対してロックされます。

  • t2 は、要求が READ ロックに対するものであったとしても、書き込みに対してロックされます。これは、トリガー内で t2 に挿入されるために発生します。したがって、READ 要求は WRITE 要求に変換されます。

  • t3 は、トリガー内から読み取られるだけであるため、読み取りに対してロックされます。

  • t4 は、トリガー内で更新される可能性があるため、書き込みに対してロックされます。

13.3.5.3 テーブルロックの制限と条件

テーブルロックを待機しているセッションを終了するために、KILL を安全に使用できます。セクション13.7.6.4「KILL 構文」を参照してください。

INSERT DELAYED で使用しているテーブルはロックしないでください。挿入は、ロックを保持するセッションではなく、別のスレッドによって処理される必要があるため、この場合の INSERT DELAYED はエラーになります。

LOCK TABLES および UNLOCK TABLES は、ストアドプログラム内では使用できません。

performance_schema データベース内のテーブルは、setup_xxx テーブルを除き、LOCK TABLES ではロックできません。

LOCK TABLES ステートメントが有効になっている間、次のステートメントは禁止されます。CREATE TABLECREATE TABLE ... LIKECREATE VIEWDROP VIEW、およびストアドファンクション、ストアドプロシージャー、イベントでの DDL ステートメント。

一部の操作では、mysql データベース内のシステムテーブルにアクセスする必要があります。たとえば、HELP ステートメントにはサーバー側のヘルプテーブルの内容が必要であり、また CONVERT_TZ() はタイムゾーンテーブルの読み取りが必要になる可能性があります。サーバーは、ユーザーが明示的にロックしなくても済むように、必要に応じてシステムテーブルを読み取りに対して暗黙的にロックします。次のテーブルは、今説明したように処理されます。

mysql.help_category
mysql.help_keyword
mysql.help_relation
mysql.help_topic
mysql.proc
mysql.time_zone
mysql.time_zone_leap_second
mysql.time_zone_name
mysql.time_zone_transition
mysql.time_zone_transition_type

これらのテーブルのいずれかに対する WRITE ロックを LOCK TABLES ステートメントで明示的に設定する場合は、そのテーブルがロックされる唯一のテーブルである必要があります。ほかのどのテーブルも、同じステートメントではロックできません。

1 つの UPDATE ステートメントはすべてアトミックであるため、通常、テーブルをロックする必要はありません。現在実行中の SQL ステートメントを、ほかのどのセッションも妨げることはできません。ただし、テーブルのロックによって利点が得られる可能性のある場合がいくつかあります。

  • 一連の MyISAM テーブルに対して多くの操作を実行しようとしている場合は、使用しようとしているテーブルをロックする方がはるかに高速です。MyISAM テーブルをロックすると、MySQL はロックされたテーブルのキーキャッシュを UNLOCK TABLES が呼び出されるまでフラッシュしないため、そのテーブルに対する挿入、更新、または削除が高速化されます。通常、キーキャッシュは各 SQL ステートメントのあとでフラッシュされます。

    テーブルロックのマイナス面は、READ によってロックされたテーブルをどのセッションも更新できず (ロックを保持しているセッションを含む)、ロックを保持しているセッションを除き、WRITE によってロックされたテーブルにどのセッションもアクセスできない点です。

  • 非トランザクションストレージエンジンに対してテーブルを使用している場合、SELECTUPDATE の間にテーブルがほかのセッションによって変更されないようにするには、LOCK TABLES を使用する必要があります。次に示す例では、安全に実行するために LOCK TABLES が必要です。

    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;

    LOCK TABLES を使用しない場合は、SELECT ステートメントと UPDATE ステートメントの実行の間に、別のセッションによって trans テーブルに新しい行が挿入される可能性があります。

多くの場合は、相対的な更新 (UPDATE customer SET value=value+new_value) または LAST_INSERT_ID() 関数を使用することによって LOCK TABLES の使用を回避できます。セクション1.7.2.3「トランザクションおよびアトミック操作の違い」を参照してください。

場合によっては、ユーザーレベルのアドバイザリロック関数 GET_LOCK() および RELEASE_LOCK() を使用してテーブルのロックを回避することもできます。高速化のために、これらのロックはサーバーのハッシュテーブル内に保存され、pthread_mutex_lock()pthread_mutex_unlock() で実装されます。セクション12.18「その他の関数」を参照してください。

ロックポリシーの詳細は、セクション8.10.1「内部ロック方法」を参照してください。

13.3.6 SET TRANSACTION 構文

SET [GLOBAL | SESSION] TRANSACTION transaction_characteristic [, transaction_characteristic] ...transaction_characteristic: ISOLATION LEVEL level | READ WRITE | READ ONLYlevel: REPEATABLE READ | READ COMMITTED | READ UNCOMMITTED | SERIALIZABLE

このステートメントは、トランザクションの特性を指定します。これは、カンマで区切られた 1 つ以上の特性値のリストを受け取ります。これらの特性は、トランザクションの分離レベルまたはアクセスモードを設定します。分離レベルは、InnoDB テーブルに対する操作に使用されます。アクセスモードは MySQL 5.6.5 の時点で指定することができ、トランザクションが読み取り/書き込みまたは読み取り専用のどちらのモードで動作するかを示します。

さらに、SET TRANSACTION には、ステートメントのスコープを示すオプションの GLOBAL または SESSION キーワードを含めることができます。

トランザクションの特性のスコープ

トランザクションの特性はグローバルに、現在のセッションに対して、または次のトランザクションに対して設定できます。

  • GLOBAL キーワードを指定すると、このステートメントは、以降のすべてのセッションに対してグローバルに適用されます。既存のセッションは影響を受けません。

  • SESSION キーワードを指定すると、このステートメントは、現在のセッション内で実行される以降のすべてのトランザクションに適用されます。

  • SESSION または GLOBAL キーワードのどちらも指定しない場合、このステートメントは、現在のセッション内で実行される次の (開始されていない) トランザクションに適用されます。

トランザクションの特性をグローバルに変更するには、SUPER 権限が必要です。どのセッションも、そのセッションの特性 (トランザクションの途中であっても)、または次のトランザクションの特性を自由に変更できます。

アクティブなトランザクションが存在する間は、GLOBAL または SESSION を指定しない SET TRANSACTION は許可されません。

mysql> START TRANSACTION;Query OK, 0 rows affected (0.02 sec)
mysql> SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;ERROR 1568 (25001): Transaction characteristics can't be changed
while a transaction is in progress

サーバーの起動時にグローバルなデフォルトの分離レベルを設定するには、コマンド行またはオプションファイルで mysqld に対して --transaction-isolation=level オプションを使用します。このオプションの level の値では、スペースではなくダッシュが使用されるため、許可される値は READ-UNCOMMITTEDREAD-COMMITTEDREPEATABLE-READ、または SERIALIZABLE です。たとえば、デフォルトの分離レベルを REPEATABLE READ に設定するには、オプションファイルの [mysqld] セクションで次の行を使用します。

[mysqld]
transaction-isolation = REPEATABLE-READ

グローバルなトランザクション分離レベルやセッションのトランザクション分離レベルは、tx_isolation システム変数を使用して、実行時にチェックまたは設定できます。

SELECT @@GLOBAL.tx_isolation, @@tx_isolation;
SET GLOBAL tx_isolation='REPEATABLE-READ';
SET SESSION tx_isolation='SERIALIZABLE';

同様に、サーバーの起動時または実行時にトランザクションアクセスモードを設定するには、--transaction-read-only オプションまたは tx_read_only システム変数を使用します。デフォルトでは、これらは OFF (モードは読み取り/書き込み) ですが、ON に設定して読み取り専用のデフォルトモードにすることができます。

tx_isolation または tx_read_only のグローバルまたはセッション値を設定することは、SET GLOBAL TRANSACTION または SET SESSION TRANSACTION で分離レベルまたはアクセスモードを設定することと同等です。

分離レベルの詳細および使用方法

InnoDB は、ここで説明されている各トランザクション分離レベルを、異なるロックの方法を使用してサポートしています。ACID 準拠が重要な要件である重要なデータに対する操作の場合は、デフォルトの REPEATABLE READ レベルを使用して高度な一貫性を適用できます。あるいは、正確な一貫性や繰り返し可能な結果がロックのためのオーバーヘッドの量の最少化ほど重要でない一括レポートなどの状況では、READ COMMITTED や場合によっては READ UNCOMMITTED を使用して一貫性のルールを緩和できます。SERIALIZABLEREPEATABLE READ よりさらに厳密なルールを適用し、主に XA トランザクションのほか、並列性やデッドロックに関する問題のトラブルシューティングなどの特殊な状況で使用されます。

これらの分離レベルが InnoDB トランザクションと連携する方法に関する完全な情報については、セクション14.2.2「InnoDB のトランザクションモデルおよびロック」を参照してください。特に、InnoDB のレコードレベルのロック、およびそれを使用してさまざまな種類のステートメントが実行される方法の詳細は、セクション14.2.6「InnoDB のレコード、ギャップ、およびネクストキーロック」およびセクション14.2.8「InnoDB のさまざまな SQL ステートメントで設定されたロック」を参照してください。

次のリストは、MySQL が各種のトランザクションレベルをどのようにサポートするかについて説明しています。このリストは、もっとも一般的に使用されるレベルから使用頻度の低い順に並べられています。

  • REPEATABLE READ

    これが InnoDB のデフォルトの分離レベルです。一貫性読み取りでは、READ COMMITTED 分離レベルとの重要な違いがあります。同じトランザクション内の一貫性読み取りはすべて、最初の読み取りによって確立されたスナップショットを読み取ります。この規則は、同じトランザクション内で複数のプレーン (非ロック) SELECT ステートメントを発行した場合、これらの SELECT ステートメントは互いに関しても一貫性があることを示します。セクション14.2.4「一貫性非ロック読み取り」を参照してください。

    ロック読み取り (FOR UPDATE または LOCK IN SHARE MODE を含む SELECT)、UPDATE、および DELETE ステートメントの場合、ロックは、そのステートメントが一意のインデックスを一意の検索条件または範囲タイプの検索条件のどちらで使用しているかによって異なります。一意の検索条件を使用した一意のインデックスの場合、InnoDB は見つかったインデックスレコードのみをロックし、その前にあるギャップはロックしません。その他の検索条件の場合、InnoDB は、ギャップロックまたはネクストキーロックを使用して、範囲に含まれるギャップへのほかのセッションによる挿入をブロックすることによって、スキャンされたインデックス範囲をロックします。

  • READ COMMITTED

    一貫性 (非ロック) 読み取りに関して、いくぶん Oracle に似た分離レベルです。各一貫性読み取りが (同じトランザクション内であっても)、独自の新しいスナップショットを設定して読み取ります。セクション14.2.4「一貫性非ロック読み取り」を参照してください。

    ロック読み取り (FOR UPDATE または LOCK IN SHARE MODE を含む SELECT)、UPDATE ステートメント、および DELETE ステートメントの場合、InnoDB はインデックスレコードのみをロックし、その前にあるギャップはロックしないため、ロックされたレコードの横への新しいレコードの自由な挿入が許可されます。

    注記

    MySQL 5.6 では、READ COMMITTED 分離レベルが使用されている場合、または非推奨の innodb_locks_unsafe_for_binlog システム変数が有効になっている場合、外部キー制約チェックと重複キーチェックを除き、InnoDB のギャップロックは存在しません。また、一致しない行に対するレコードロックも、MySQL が WHERE 条件を評価したあとに解放されます。

    READ COMMITTED を使用するか、または innodb_locks_unsafe_for_binlog を有効にする場合は、行ベースのバイナリロギングを使用する必要があります

  • READ UNCOMMITTED

    SELECT ステートメントは非ロックの方法で実行されますが、以前のバージョンの行が使用される可能性もあります。そのため、この分離レベルを使用すると、このような読み取りには一貫性がありません。これは、ダーティー読み取りとも呼ばれます。そうでなければ、この分離レベルは READ COMMITTED のように機能します。

  • SERIALIZABLE

    このレベルは REPEATABLE READ に似ていますが、自動コミットが無効になっている場合、InnoDB はすべてのプレーン SELECT ステートメントを SELECT ... LOCK IN SHARE MODE に暗黙的に変換します。自動コミットが有効になっている場合、SELECT は独自のトランザクションです。したがって、読み取り専用であることがわかっているため、一貫性のある (非ロック) 読み取りとして実行された場合は直列化することができ、ほかのトランザクションのためのブロックは必要ありません。(選択された行がほかのトランザクションによって変更された場合、プレーン SELECT で強制的にブロックするには、自動コミットを無効にします。)

トランザクションアクセスモード

MySQL 5.6.5 の時点では、トランザクションアクセスモードは SET TRANSACTION で指定できます。デフォルトでは、トランザクションは読み取り/書き込みモードで実行され、そのトランザクションで使用されるテーブルに対して読み取りと書き込みの両方が許可されます。このモードは、READ WRITE のアクセスモードを使用して明示的に指定できます。

トランザクションアクセスモードが READ ONLY に設定されている場合は、テーブルへの変更が禁止されます。これにより、書き込みが許可されていない場合に可能になる、ストレージエンジンのパフォーマンス向上が実現される可能性があります。

同じステートメント内で READ WRITEREAD ONLY の両方を指定することは許可されません。

読み取り専用モードでは、DML ステートメントを使用して TEMPORARY キーワードで作成されたテーブルは引き続き変更できます。永続的なテーブルと同様に、DDL ステートメントによって行われる変更は許可されません。

READ WRITE および READ ONLY アクセスモードは、START TRANSACTION ステートメントを使用して個々のトランザクションに対しても指定できます。

13.3.7 XA トランザクション

XA トランザクションのサポートは、InnoDB ストレージエンジンに対して使用できます。MySQL XA 実装は、X/Open CAE ドキュメント分散トランザクション処理: XA 仕様に基づいています。このドキュメントは The Open Group によって発行されており、http://www.opengroup.org/public/pubs/catalog/c193.htm で入手できます。現在の XA 実装の制限については、セクションD.6「XA トランザクションの制約」で説明されています。

クライアント側には、特殊な要件は何もありません。MySQL サーバーへの XA インタフェースは、XA キーワードで始まる SQL ステートメントで構成されています。MySQL クライアントプログラムは、SQL ステートメントを送信したり、XA ステートメントインタフェースのセマンティクスを理解したりできる必要があります。これらが、最新のクライアントライブラリに対してリンクされている必要はありません。古いクライアントライブラリも機能します。

現在、MySQL Connector の中で、MySQL Connector/J 5.0.0 以降は、XA SQL ステートメントインタフェースを自動的に処理するクラスインタフェースを使用して XA を直接サポートします。

XA は分散トランザクション、つまり、複数の個別のトランザクションリソースがグローバルトランザクションに参加することを許可する機能をサポートしています。トランザクションリソースは多くの場合 RDBMS ですが、ほかの種類のリソースであってもかまいません。

グローバルトランザクションには、それ自体でトランザクションである複数のアクションが含まれますが、そのすべてがグループとして正常に完了するか、またはすべてがグループとしてロールバックされるかのどちらかである必要があります。基本的に、これは ACID プロパティーを1 レベル上に拡張することにより、複数の ACID トランザクションを、同じく ACID プロパティーを持つグローバル操作のコンポーネントとして連携して実行できるようにします。(ただし、分散トランザクションに対しては、SERIALIZABLE 分離レベルを使用して ACID プロパティーを実現する必要があります。非分散トランザクションに対しては REPEATABLE READ を使用すれば十分ですが、分散トランザクションに対しては不十分です。)

分散トランザクションのいくつかの例:

  • あるアプリケーションが、メッセージングサービスを RDBMS と組み合わせる統合ツールとして機能する場合があります。このアプリケーションは、同じくトランザクションデータベースを含む、メッセージの送信、取得、および処理を行うトランザクションがすべて、確実にグローバルトランザクション内で実行されるようにします。これは、トランザクション電子メールと考えることができます。

  • アプリケーションが、MySQL サーバーや Oracle サーバー (または複数の MySQL サーバー) などの異なるデータベースサーバーに関連するアクションを実行します。ここで、複数のサーバーに関連するアクションは、各サーバーに対してローカルな個別のトランザクションとしてではなく、グローバルトランザクションの一部として実行する必要があります。

  • 銀行が口座情報を RDBMS 内に保持し、現金自動預け払い機 (ATM) を通して現金を出し入れしています。ATM のアクションが口座に正しく反映されるように保証することが必要ですが、これは RDBMS だけでは実行できません。グローバルなトランザクションマネージャーが ATM とデータベースリソースを統合して、財務トランザクションの全体的な一貫性を確保します。

グローバルトランザクションを使用するアプリケーションには、1 つまたは複数のリソースマネージャーと 1 つのトランザクションマネージャーが含まれています。

  • リソースマネージャー (RM) は、トランザクションリソースへのアクセスを提供します。データベースサーバーは、1 つの種類のリソースマネージャーです。これは、RM によって管理されているトランザクションをコミットまたはロールバックできる必要があります。

  • トランザクションマネージャー (TM) は、グローバルトランザクションの一部であるトランザクションを調整します。これは、これらの各トランザクションを処理する RM と通信します。グローバルトランザクション内の個々のトランザクションは、グローバルトランザクションのブランチです。グローバルトランザクションとそのブランチは、あとで説明されている名付けスキームによって識別されます。

XA MySQL の MySQL 実装では、MySQL サーバーは、グローバルトランザクション内の XA トランザクションを処理するリソースマネージャーとして機能できます。MySQL サーバーに接続するクライアントプログラムは、トランザクションマネージャーとして機能します。

グローバルトランザクションを実行するには、どのコンポーネントが関連しているかを知り、各コンポーネントをそのコミットまたはロールバックが可能なポイントに持っていくことが必要です。各コンポーネントが自身の成功する能力に関してレポートする内容に応じて、それらのすべてが、アトミックグループとしてコミットまたはロールバックする必要があります。つまり、すべてのコンポーネントがコミットするか、またはすべてのコンポーネントがロールバックする必要があります。グローバルトランザクションを管理するには、いずれかのコンポーネントまたは接続しているネットワークが失敗する可能性があることを考慮に入れる必要があります。

グローバルトランザクションを実行するためのプロセスでは、2 フェーズコミット (2PC) が使用されます。これは、グローバルトランザクションのブランチによって実行されるアクションが実行されたあとに行われます。

  1. 最初のフェーズでは、すべてのブランチが準備されます。つまり、これらは TM からコミットの準備を行うよう指示されます。これは通常、ブランチを管理する各 RM が、そのブランチのアクションを安定したストレージ内に記録することを示します。これらのブランチはこれを実行できるかどうかを示し、これらの結果が 2 番目のフェーズに使用されます。

  2. 2 番目のフェーズでは、TM が RM にコミットまたはロールバックのどちらを行うかを指示します。すべてのブランチが、準備できたときにコミットできることを示した場合は、すべてのブランチがコミットするよう指示されます。いずれかのブランチが、準備できたときにコミットできないことを示した場合は、すべてのブランチがロールバックするよう指示されます。

場合によっては、グローバルトランザクションで 1 フェーズコミット (1PC) が使用されることがあります。たとえば、グローバルトランザクションが 1 つのトランザクションリソース (つまり、1 つのブランチ) だけで構成されていることがトランザクションマネージャーによって検出された場合は、そのリソースに準備とコミットを一度に行うよう指示できます。

13.3.7.1 XA トランザクションの SQL 構文

MySQL で XA トランザクションを実行するには、次のステートメントを使用します。

XA {START|BEGIN} xid [JOIN|RESUME]
XA END xid [SUSPEND [FOR MIGRATE]]
XA PREPARE xidXA COMMIT xid [ONE PHASE]
XA ROLLBACK xidXA RECOVER

XA START では、JOIN および RESUME 句はサポートされていません。

XA END では、SUSPEND [FOR MIGRATE] 句はサポートされていません。

各 XA ステートメントは XA キーワードで始まり、そのほとんどに xid 値が必要です。xid は XA トランザクション識別子です。これは、このステートメントがどのトランザクションに適用されるかを示します。xid 値はクライアントによって指定されるか、または MySQL サーバーによって生成されます。xid 値には、1 つから 3 つの部分が含まれています。

xid: gtrid [, bqual [, formatID ]]

gtrid はグローバルトランザクション識別子であり、bqual はブランチ修飾子であり、formatID は、gtrid および bqual 値で使用される形式を識別する数値です。構文で示されているように、bqualformatID はオプションです。bqual が指定されていない場合、そのデフォルト値は '' です。formatID が指定されていない場合、そのデフォルト値は 1 です。

gtridbqual はそれぞれ、最大 64 バイト長 (64 文字ではありません) の文字列リテラルである必要があります。gtridbqual は、いくつかの方法で指定できます。引用符で囲まれた文字列 ('ab')、16 進文字列 (0x6162X'ab')、またはビット値 (b'nnnn') を使用できます。

formatID は符号なし整数です。

gtrid および bqual 値は、MySQL サーバーのベースとなる XA サポートルーチンによってバイト単位で解釈されます。ただし、XA ステートメントを含む SQL ステートメントが解析されている間、サーバーは何からの特定の文字セットで動作します。安全のために、gtridbqual は 16 進文字列として記述してください。

xid 値は通常、トランザクションマネージャーによって生成されます。ある TM によって生成される値は、ほかの TM によって生成される値とは異なっている必要があります。特定の TM は、XA RECOVER ステートメントによって返された値のリスト内の自身の xid 値を認識できる必要があります。

XA START xid は、指定された xid 値を使用して XA トランザクションを開始します。各 XA トランザクションが一意の xid 値を持っている必要があるため、その値が現在、別の XA トランザクションによって使用されていてはいけません。一意性は、gtrid および bqual 値を使用して評価されます。XA トランザクションに対する以降のすべての XA ステートメントを、XA START ステートメントで指定されたものと同じ xid 値を使用して指定する必要があります。これらのステートメントのいずれかを使用しているが、既存の XA トランザクションに対応していない xid 値を指定した場合は、エラーが発生します。

1 つ以上の XA トランザクションを同じグローバルトランザクションの一部にすることができます。特定のグローバルトランザクション内のすべての XA トランザクションが xid 値内の同じ gtrid 値を使用する必要があります。このため、特定の XA トランザクションがどのグローバルトランザクションの一部であるかについてのあいまいさがないように、gtrid 値はグローバルに一意である必要があります。xid 値の bqual 部分は、グローバルトランザクション内の XA トランザクションごとに異なっている必要があります。(bqual 値が異なっているという要件は、現在の MySQL XA 実装の制限です。これは XA 仕様の一部ではありません。)

XA RECOVER ステートメントは、PREPARED 状態にある MySQL サーバー上の XA トランザクションに関する情報を返します。(セクション13.3.7.2「XA トランザクションの状態」を参照してください。) この出力には、どのクライアントによって開始されたかには関係なく、サーバー上のこのような XA トランザクションごとの行が含まれています。

XA RECOVER の出力行は次のようになります ('abc''def'7 の各部分から成る xid 値の例の場合)。

mysql> XA RECOVER;+----------+--------------+--------------+--------+
| formatID | gtrid_length | bqual_length | data |
+----------+--------------+--------------+--------+
| 7 | 3 | 3 | abcdef |
+----------+--------------+--------------+--------+

出力カラムには次の意味があります。

  • formatID は、トランザクション xidformatID 部分です。

  • gtrid_length は、xidgtrid 部分の長さ (バイト単位) です。

  • bqual_length は、xidbqual 部分の長さ (バイト単位) です。

  • data は、xidgtrid および bqual 部分の連結です。

13.3.7.2 XA トランザクションの状態

XA トランザクションは、次の各状態を経由して処理されます。

  1. XA START を使用して、XA トランザクションを開始し、それを ACTIVE 状態にします。

  2. ACTIVE XA トランザクションに対しては、トランザクションを構成する SQL ステートメントを発行したあと、XA END ステートメントを発行します。XA END は、トランザクションを IDLE 状態にします。

  3. IDLE XA トランザクションに対しては、XA PREPARE ステートメントまたは XA COMMIT ... ONE PHASE ステートメントのどちらかを発行できます。

    • XA PREPARE は、トランザクションを PREPARED 状態にします。この時点での XA RECOVER ステートメントは、XA RECOVERPREPARED 状態にあるすべての XA トランザクションをリストするため、その出力にトランザクションの xid 値が含まれます。

    • XA COMMIT ... ONE PHASE は、トランザクションの準備とコミットを行います。トランザクションが終了するため、xid 値は XA RECOVER によってリストされません。

  4. PREPARED XA トランザクションに対しては、XA COMMIT ステートメントを発行してトランザクションをコミットおよび終了するか、または XA ROLLBACK を発行してトランザクションをロールバックおよび終了することができます。

グローバルトランザクションの一部としてテーブルに行を挿入する単純な XA トランザクションを次に示します。

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)

特定のクライアント接続のコンテキスト内では、XA トランザクションとローカル (非 XA) トランザクションは相互に排他的です。たとえば、XA トランザクションを開始するために XA START が発行された場合は、その XA トランザクションがコミットまたはロールバックされるまでローカルトランザクションを開始できません。逆に、START TRANSACTION を使用してローカルトランザクションが開始された場合は、そのトランザクションがコミットまたはロールバックされるまで XA ステートメントを使用できません。

XA トランザクションが ACTIVE 状態にある場合は、暗黙的なコミットを発生させるどのステートメントも発行できません。その XA トランザクションをロールバックできないため、それを行うことは XA 規約に違反します。このようなステートメントを実行しようとすると、次のエラーが表示されます。

ERROR 1399 (XAE07): XAER_RMFAIL: The command cannot be executed
when global transaction is in the ACTIVE state

前の注意事項が適用されるステートメントは、セクション13.3.3「暗黙的なコミットを発生させるステートメント」に示されています。

13.4 レプリケーションステートメント

レプリケーションは、このセクションで説明されているステートメントを使用した SQL インタフェースを通して制御できます。ステートメントの 1 つのグループがマスターサーバーを制御し、もう 1 つのグループがスレーブサーバーを制御します。

13.4.1 マスターサーバーを制御するための SQL ステートメント

このセクションでは、マスターレプリケーションサーバーを管理するためのステートメントについて説明します。セクション13.4.2「スレーブサーバーを制御するための SQL ステートメント」では、スレーブサーバーを管理するためのステートメントについて説明しています。

ここで説明されているステートメントに加えて、レプリケーションのマスターサーバーでは次の SHOW ステートメントが使用されます。これらのステートメントについては、セクション13.7.5「SHOW 構文」を参照してください。

  • <