Chapter 12. SQL Statement Syntax
Table of Contents
This chapter describes the syntax for the SQL statements supported in MySQL versions 4.1 and earlier.
ALTER DATABASE [db_name]alter_specification...alter_specification: [DEFAULT] CHARACTER SET [=]charset_name| [DEFAULT] COLLATE [=]collation_name
ALTER DATABASE enables you to
change the overall characteristics of a database. These
characteristics are stored in the db.opt file
in the database directory. To use ALTER
DATABASE, you need the
ALTER privilege on the database.
The CHARACTER SET clause changes the default
database character set. The COLLATE clause
changes the default database collation. Section 9.1, “Character Set Support”,
discusses character set and collation names.
Beginning with MySQL 4.1.0, you can see what character sets and
collations are available using, respectively, the
SHOW CHARACTER SET and
SHOW COLLATION statements. See
Section 12.5.5.3, “SHOW CHARACTER SET Syntax”, and
Section 12.5.5.4, “SHOW COLLATION Syntax”, for more information.
ALTER DATABASE was added in MySQL
4.1.1. Beginning with MySQL 4.1.8, the database name can be
omitted, in which case the statement applies to the default
database.
MySQL Enterprise In a production environment, alteration of a database is not a common occurrence and may indicate a security breach. Advisors provided as part of the MySQL Enterprise Monitor automatically alert you when data definition statements are issued. For more information, see http://www.mysql.com/products/enterprise/advisors.html.
ALTER [IGNORE] TABLEtbl_namealter_specification[,alter_specification] ...alter_specification:table_options| ADD [COLUMN]col_namecolumn_definition[FIRST | AFTERcol_name] | ADD [COLUMN] (col_namecolumn_definition,...) | ADD {INDEX|KEY} [index_name] [index_type] (index_col_name,...) | ADD [CONSTRAINT [symbol]] PRIMARY KEY [index_type] (index_col_name,...) | ADD [CONSTRAINT [symbol]] UNIQUE [INDEX|KEY] [index_name] [index_type] (index_col_name,...) | ADD [FULLTEXT|SPATIAL] [INDEX|KEY] [index_name] (index_col_name,...) | ADD [CONSTRAINT [symbol]] FOREIGN KEY [index_name] (index_col_name,...)reference_definition| ALTER [COLUMN]col_name{SET DEFAULTliteral| DROP DEFAULT} | CHANGE [COLUMN]old_col_namenew_col_namecolumn_definition[FIRST|AFTERcol_name] | MODIFY [COLUMN]col_namecolumn_definition[FIRST | AFTERcol_name] | DROP [COLUMN]col_name| DROP PRIMARY KEY | DROP {INDEX|KEY}index_name| DROP FOREIGN KEYfk_symbol| DISABLE KEYS | ENABLE KEYS | RENAME [TO]new_tbl_name| ORDER BYcol_name[,col_name] ... | CONVERT TO CHARACTER SETcharset_name[COLLATEcollation_name] | [DEFAULT] CHARACTER SET [=]charset_name[COLLATE [=]collation_name] | DISCARD TABLESPACE | IMPORT TABLESPACEindex_col_name:col_name[(length)] [ASC | DESC]index_type: USING {BTREE | HASH | RTREE}table_options:table_option[[,]table_option] ...
ALTER TABLE enables you to change
the structure of an existing table. For example, you can add or
delete columns, create or destroy indexes, change the type of
existing columns, or rename columns or the table itself. You can
also change the comment for the table and type of the table.
The syntax for many of the allowable alterations is similar to
clauses of the CREATE TABLE
statement. See Section 12.1.5, “CREATE TABLE Syntax”, for more
information.
Some operations may result in warnings if attempted on a table for
which the storage engine does not support the operation. In MySQL
4.1 and up, these warnings can be displayed with
SHOW WARNINGS. See
Section 12.5.5.26, “SHOW WARNINGS Syntax”.
If you use ALTER TABLE to change a
column specification but DESCRIBE
indicates that your
column was not changed, it is possible that MySQL ignored your
modification for one of the reasons described in
Section 12.1.5.1, “Silent Column Specification Changes”. For example, if you try
to change a tbl_nameVARCHAR column to
CHAR, MySQL still uses
VARCHAR if the table contains other
variable-length columns.
In most cases, ALTER TABLE works by
making a temporary copy of the original table. The alteration is
performed on the copy, and then the original table is deleted and
the new one is renamed. While ALTER
TABLE is executing, the original table is readable by
other sessions. Updates and writes to the table are stalled until
the new table is ready, and then are automatically redirected to
the new table without any failed updates. The temporary table is
created in the database directory of the new table. This can be
different from the database directory of the original table if
ALTER TABLE is renaming the table
to a different database.
If you use ALTER TABLE
without any
other options, MySQL simply renames any files that correspond to
the table tbl_name RENAME TO
new_tbl_nametbl_name. (You can also use
the RENAME TABLE statement to
rename tables. See Section 12.1.9, “RENAME TABLE Syntax”.) Any privileges
granted specifically for the renamed table are not migrated to the
new name. They must be changed manually.
If you use any option to ALTER
TABLE other than RENAME, MySQL always
creates a temporary table, even if the data wouldn't strictly need
to be copied (such as when you change the name of a column). For
MyISAM tables, you can speed up the index
re-creation operation (which is the slowest part of the alteration
process) by setting the
myisam_sort_buffer_size system
variable to a high value.
For information on troubleshooting ALTER
TABLE, see Section A.1.7.1, “Problems with ALTER TABLE”.
To use
ALTER TABLE, you needALTER,INSERT, andCREATEprivileges for the table.IGNOREis a MySQL extension to standard SQL. It controls howALTER TABLEworks if there are duplicates on unique keys in the new table or if warnings occur when strict mode is enabled. IfIGNOREis not specified, the copy is aborted and rolled back if duplicate-key errors occur. IfIGNOREis specified, only the first row is used of rows with duplicates on a unique key, The other conflicting rows are deleted. Incorrect values are truncated to the closest matching acceptable value.table_optionsignifies a table option of the kind that can be used in theCREATE TABLEstatement, such asENGINE,AUTO_INCREMENT, orAVG_ROW_LENGTH. (Section 12.1.5, “CREATE TABLESyntax”, lists all table options.) However,ALTER TABLEignores theDATA DIRECTORYandINDEX DIRECTORYtable options.For example, to convert a table to be an
InnoDBtable, use this statement:ALTER TABLE t1 ENGINE = InnoDB;
To change the value of the
AUTO_INCREMENTcounter to be used for new rows, do this:ALTER TABLE t2 AUTO_INCREMENT =
value;You cannot reset the counter to a value less than or equal to any that have already been used. For
MyISAM, if the value is less than or equal to the maximum value currently in theAUTO_INCREMENTcolumn, the value is reset to the current maximum plus one. ForInnoDB, you can useALTER TABLE ... AUTO_INCREMENT =as of MySQL 4.1.12, but if the value is less than the current maximum value in the column, no error occurs and the current sequence value is not changed.valueYou can issue multiple
ADD,ALTER,DROP, andCHANGEclauses in a singleALTER TABLEstatement, separated by commas. This is a MySQL extension to standard SQL, which allows only one of each clause perALTER TABLEstatement. For example, to drop multiple columns in a single statement, do this:ALTER TABLE t2 DROP COLUMN c, DROP COLUMN d;
CHANGE,col_nameDROP, andcol_nameDROP INDEXare MySQL extensions to standard SQL.MODIFYis an Oracle extension toALTER TABLE.The word
COLUMNis optional and can be omitted.column_definitionclauses use the same syntax forADDandCHANGEas forCREATE TABLE. See Section 12.1.5, “CREATE TABLESyntax”.You can rename a column using a
CHANGEclause. To do so, specify the old and new column names and the definition that the column currently has. For example, to rename anold_col_namenew_col_namecolumn_definitionINTEGERcolumn fromatob, you can do this:ALTER TABLE t1 CHANGE a b INTEGER;
If you want to change a column's type but not the name,
CHANGEsyntax still requires an old and new column name, even if they are the same. For example:ALTER TABLE t1 CHANGE b b BIGINT NOT NULL;
However, as of MySQL 3.22.16a, you can also use
MODIFYto change a column's type without renaming it:ALTER TABLE t1 MODIFY b BIGINT NOT NULL;
When you use
CHANGEorMODIFY,column_definitionmust include the data type and all attributes that should apply to the new column, other than index attributes such asPRIMARY KEYorUNIQUE. Attributes present in the original definition but not specified for the new definition are not carried forward. Suppose a columncol1is defined asINT UNSIGNED DEFAULT 1 COMMENT 'my column'and you modify the column as follows:ALTER TABLE t1 MODIFY col1 BIGINT;
The resulting column will be defined as
BIGINT, but will not include the attributesUNSIGNED DEFAULT 1 COMMENT 'my column'. To retain them, the statement should be:ALTER TABLE t1 MODIFY col1 BIGINT UNSIGNED DEFAULT 1 COMMENT 'my column';
When you change a data type using
CHANGEorMODIFY, MySQL tries to convert existing column values to the new type as well as possible.Warning
This conversion may result in alteration of data. For example, if you shorten a string column, values may be truncated.
In MySQL 3.22 or later, to add a column at a specific position within a table row, use
FIRSTorAFTER. The default is to add the column last. From MySQL 4.0.1 on, you can also usecol_nameFIRSTandAFTERinCHANGEorMODIFYoperations to reorder columns within a table.ALTER ... SET DEFAULTorALTER ... DROP DEFAULTspecify a new default value for a column or remove the old default value, respectively. If the old default is removed and the column can beNULL, the new default isNULL. If the column cannot beNULL, MySQL assigns a default value as described in Section 10.1.4, “Data Type Default Values”.DROP INDEXremoves an index. This is a MySQL extension to standard SQL. See Section 12.1.7, “DROP INDEXSyntax”. If you are unsure of the index name, useSHOW INDEX FROM.tbl_nameIf columns are dropped from a table, the columns are also removed from any index of which they are a part. If all columns that make up an index are dropped, the index is dropped as well. If you use
CHANGEorMODIFYto shorten a column for which an index exists on the column, and the resulting column length is less than the index length, MySQL shortens the index automatically.If a table contains only one column, the column cannot be dropped. If what you intend is to remove the table, use
DROP TABLEinstead.DROP PRIMARY KEYdrops the primary key. If there is no primary key, an error occurs. (Prior to MySQL 4.1.2, if no primary key exists,DROP PRIMARY KEYdrops the firstUNIQUEindex in the table. MySQL marks the firstUNIQUEkey as thePRIMARY KEYif noPRIMARY KEYwas specified explicitly.)If you add a
UNIQUE INDEXorPRIMARY KEYto a table, it is stored before any nonunique index so that MySQL can detect duplicate keys as early as possible.From MySQL 4.1.0 on, some storage engines allow you to specify an index type when creating an index. The syntax for the
index_typespecifier isUSING. For details abouttype_nameUSING, see Section 12.1.4, “CREATE INDEXSyntax”.ORDER BYenables you to create the new table with the rows in a specific order. Note that the table does not remain in this order after inserts and deletes. This option is useful primarily when you know that you are mostly to query the rows in a certain order most of the time. By using this option after major changes to the table, you might be able to get higher performance. In some cases, it might make sorting easier for MySQL if the table is in order by the column that you want to order it by later.ORDER BYsyntax allows for one or more column names to be specified for sorting, each of which optionally can be followed byASCorDESCto indicate ascending or descending sort order, respectively. The default is ascending order. Only column names are allowed as sort criteria; arbitrary expressions are not allowed.ORDER BYdoes not make sense forInnoDBtables that contain a user-defined clustered index (PRIMARY KEYorNOT NULL UNIQUEindex).InnoDBalways orders table rows according to such an index if one is present. The same is true forBDBtables that contain a user-definedPRIMARY KEY.If you use
ALTER TABLEon aMyISAMtable, all nonunique indexes are created in a separate batch (as forREPAIR TABLE). This should makeALTER TABLEmuch faster when you have many indexes.As of MySQL 4.0, this feature can be activated explicitly for a
MyISAMtable.ALTER TABLE ... DISABLE KEYStells MySQL to stop updating nonunique indexes.ALTER TABLE ... ENABLE KEYSthen should be used to re-create missing indexes. MySQL does this with a special algorithm that is much faster than inserting keys one by one, so disabling keys before performing bulk insert operations should give a considerable speedup. UsingALTER TABLE ... DISABLE KEYSrequires theINDEXprivilege in addition to the privileges mentioned earlier.While the nonunique indexes are disabled, they are ignored for statements such as
SELECTandEXPLAINthat otherwise would use them.If
ALTER TABLEfor anInnoDBtable results in changes to column values (for example, because a column is truncated),InnoDB'sFOREIGN KEYconstraint checks do not notice possible violations caused by changing the values.The
FOREIGN KEYandREFERENCESclauses are supported by theInnoDBstorage engine, which implementsADD [CONSTRAINT [. See Section 13.2.5.4, “symbol]] FOREIGN KEY (...) REFERENCES ... (...)FOREIGN KEYConstraints”. For other storage engines, the clauses are parsed but ignored. TheCHECKclause is parsed but ignored by all storage engines. See Section 12.1.5, “CREATE TABLESyntax”. The reason for accepting but ignoring syntax clauses is for compatibility, to make it easier to port code from other SQL servers, and to run applications that create tables with references. See Section 1.7.5, “MySQL Differences from Standard SQL”.Important
The inline
REFERENCESspecifications where the references are defined as part of the column specification are silently ignored byInnoDB. InnoDB only acceptsREFERENCESclauses defined as part of a separateFOREIGN KEYspecification.Starting from MySQL 4.0.13,
InnoDBsupports the use ofALTER TABLEto drop foreign keys:ALTER TABLE
tbl_nameDROP FOREIGN KEYfk_symbol;For more information, see Section 13.2.5.4, “
FOREIGN KEYConstraints”.You cannot add a foreign key and drop a foreign key in separate clauses of a single
ALTER TABLEstatement. You must use separate statements.For an
InnoDBtable that is created with its own tablespace in an.ibdfile, that file can be discarded and imported. To discard the.ibdfile, use this statement:ALTER TABLE
tbl_nameDISCARD TABLESPACE;This deletes the current
.ibdfile, so be sure that you have a backup first. Attempting to access the table while the tablespace file is discarded results in an error.To import the backup
.ibdfile back into the table, copy it into the database directory, and then issue this statement:ALTER TABLE
tbl_nameIMPORT TABLESPACE;Pending
INSERT DELAYEDstatements are lost if a table is write locked andALTER TABLEis used to modify the table structure.From MySQL 4.1.2 on, if you want to change the table default character set and all character columns (
CHAR,VARCHAR,TEXT) to a new character set, use a statement like this:ALTER TABLE
tbl_nameCONVERT TO CHARACTER SETcharset_name;This is useful, for example, after upgrading from MySQL 4.0.x to 4.1.x. See Section 9.1.10, “Upgrading Character Sets from MySQL 4.0”.
If you specify
CONVERT TO CHARACTER SET binary, theCHAR,VARCHAR, andTEXTcolumns are converted to their corresponding binary string types (BINARY,VARBINARY,BLOB). This means that the columns no longer will have a character set and a subsequentCONVERT TOoperation will not apply to them.If
charset_nameisDEFAULT, the database character set is used.Warning
The
CONVERT TOoperation converts column values between the character sets. This is not what you want if you have a column in one character set (likelatin1) but the stored values actually use some other, incompatible character set (likeutf8). In this case, you have to do the following for each such column:ALTER TABLE t1 CHANGE c1 c1 BLOB; ALTER TABLE t1 CHANGE c1 c1 TEXT CHARACTER SET utf8;
The reason this works is that there is no conversion when you convert to or from
BLOBcolumns.To change only the default character set for a table, use this statement:
ALTER TABLE
tbl_nameDEFAULT CHARACTER SETcharset_name;The word
DEFAULTis optional. The default character set is the character set that is used if you do not specify the character set for columns that you add to a table later (for example, withALTER TABLE ... ADD column).Warning
From MySQL 4.1.2 and up,
ALTER TABLE ... DEFAULT CHARACTER SETandALTER TABLE ... CHARACTER SETare equivalent and change only the default table character set. In MySQL 4.1 releases before 4.1.2,ALTER TABLE ... DEFAULT CHARACTER SETchanges the default character set, butALTER TABLE ... CHARACTER SET(withoutDEFAULT) changes the default character set and also converts all columns to the new character set.
With the mysql_info() C API
function, you can find out how many rows were copied, and (when
IGNORE is used) how many rows were deleted due
to duplication of unique key values. See
Section 17.7.3.33, “mysql_info()”.
Here are some examples that show uses of
ALTER TABLE. Begin with a table
t1 that is created as shown here:
CREATE TABLE t1 (a INTEGER,b CHAR(10));
To rename the table from t1 to
t2:
ALTER TABLE t1 RENAME t2;
To change column a from
INTEGER to TINYINT NOT
NULL (leaving the name the same), and to change column
b from CHAR(10) to
CHAR(20) as well as renaming it from
b to c:
ALTER TABLE t2 MODIFY a TINYINT NOT NULL, CHANGE b c CHAR(20);
To add a new TIMESTAMP column named
d:
ALTER TABLE t2 ADD d TIMESTAMP;
To add an index on column d and a
UNIQUE index on column a:
ALTER TABLE t2 ADD INDEX (d), ADD UNIQUE (a);
To remove column c:
ALTER TABLE t2 DROP COLUMN c;
To add a new AUTO_INCREMENT integer column
named c:
ALTER TABLE t2 ADD c INT UNSIGNED NOT NULL AUTO_INCREMENT, ADD PRIMARY KEY (c);
Note that we indexed c (as a PRIMARY
KEY) because AUTO_INCREMENT columns
must be indexed, and also that we declare c as
NOT NULL because primary key columns cannot be
NULL.
When you add an AUTO_INCREMENT column, column
values are filled in with sequence numbers automatically. For
MyISAM tables, you can set the first sequence
number by executing SET
INSERT_ID= before
valueALTER TABLE or by using the
AUTO_INCREMENT=
table option. See Section 5.1.4, “Session System Variables”.
value
With MyISAM tables, if you do not change the
AUTO_INCREMENT column, the sequence number is
not affected. If you drop an AUTO_INCREMENT
column and then add another AUTO_INCREMENT
column, the numbers are resequenced beginning with 1.
When replication is used, adding an
AUTO_INCREMENT column to a table might not
produce the same ordering of the rows on the slave and the master.
This occurs because the order in which the rows are numbered
depends on the specific storage engine used for the table and the
order in which the rows were inserted. If it is important to have
the same order on the master and slave, the rows must be ordered
before assigning an AUTO_INCREMENT number.
Assuming that you want to add an AUTO_INCREMENT
column to the table t1, the following
statements produce a new table t2 identical to
t1 but with an
AUTO_INCREMENT column:
CREATE TABLE t2 (id INT AUTO_INCREMENT PRIMARY KEY) SELECT * FROM t1 ORDER BY col1, col2;
This assumes that the table t1 has columns
col1 and col2.
This set of statements will also produce a new table
t2 identical to t1, with the
addition of an AUTO_INCREMENT column:
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;
Important
To guarantee the same ordering on both master and slave,
all columns of t1 must
be referenced in the ORDER BY clause.
Regardless of the method used to create and populate the copy
having the AUTO_INCREMENT column, the final
step is to drop the original table and then rename the copy:
DROP t1; ALTER TABLE t2 RENAME t1;
CREATE DATABASE [IF NOT EXISTS]db_name[create_specification] ...create_specification: [DEFAULT] CHARACTER SET [=]charset_name| [DEFAULT] COLLATE [=]collation_name
CREATE DATABASE creates a database
with the given name. To use this statement, you need the
CREATE privilege for the database.
An error occurs if the database exists and you did not specify
IF NOT EXISTS.
As of MySQL 4.1.1, create_specification
options specify database characteristics. Database characteristics
are stored in the db.opt file in the database
directory. The CHARACTER SET clause specifies
the default database character set. The COLLATE
clause specifies the default database collation.
Section 9.1, “Character Set Support”, discusses character set and collation
names.
A database in MySQL is implemented as a directory containing files
that correspond to tables in the database. Because there are no
tables in a database when it is initially created, the
CREATE DATABASE statement only
creates a directory under the MySQL data directory (and the
db.opt file, for MySQL 4.1.1 and up). Rules
for allowable database names are given in
Section 8.2, “Database, Table, Index, Column, and Alias Names”.
If you manually create a directory under the data directory (for
example, with mkdir), the server considers it a
database directory and it shows up in the output of
SHOW DATABASES.
You can also use the mysqladmin program to create databases. See Section 4.5.2, “mysqladmin — Client for Administering a MySQL Server”.
CREATE [UNIQUE|FULLTEXT|SPATIAL] INDEXindex_name[index_type] ONtbl_name(index_col_name,...)index_col_name:col_name[(length)] [ASC | DESC]index_type: USING {BTREE | HASH}
In MySQL 3.22 or later, CREATE
INDEX is mapped to an ALTER
TABLE statement to create indexes. See
Section 12.1.2, “ALTER TABLE Syntax”. The CREATE
INDEX statement does not do anything prior to MySQL
3.22. For more information about indexes, see
Section 7.4.4, “How MySQL Uses Indexes”.
Normally, you create all indexes on a table at the time the table
itself is created with CREATE
TABLE. See Section 12.1.5, “CREATE TABLE Syntax”.
CREATE INDEX enables you to add
indexes to existing tables.
A column list of the form (col1,col2,...)
creates a multiple-column index. Index values are formed by
concatenating the values of the given columns.
Indexes can be created that use only the leading part of column
values, using
syntax to specify an index prefix length:
col_name(length)
Prefixes can be specified for
CHAR,VARCHAR,BINARY, andVARBINARYcolumns.BLOBandTEXTcolumns also can be indexed, but a prefix length must be given.Prefix lengths are given in characters for nonbinary string types and in bytes for binary string types. That is, index entries consist of the first
lengthcharacters of each column value forCHAR,VARCHAR, andTEXTcolumns, and the firstlengthbytes of each column value forBINARY,VARBINARY, andBLOBcolumns.For spatial columns, prefix values can be given as described later in this section.
The statement shown here creates an index using the first 10
characters of the name column:
CREATE INDEX part_of_name ON customer (name(10));
If names in the column usually differ in the first 10 characters,
this index should not be much slower than an index created from
the entire name column. Also, using column
prefixes for indexes can make the index file much smaller, which
could save a lot of disk space and might also speed up
INSERT operations.
Prefix lengths are storage engine-dependent (for example, a prefix
can be up to 1000 bytes long for MyISAM tables,
767 bytes for InnoDB tables). (Before MySQL
4.1.2, the limit is 255 bytes for all tables.) Note that prefix
limits are measured in bytes, whereas the prefix length in
CREATE INDEX statements is
interpreted as number of characters for nonbinary data types
(CHAR,
VARCHAR,
TEXT). Take this into account when
specifying a prefix length for a column that uses a multi-byte
character set.
A UNIQUE index creates a constraint such that
all values in the index must be distinct. An error occurs if you
try to add a new row with a key value that matches an existing
row. This constraint does not apply to NULL
values except for the BDB storage engine. For
other engines, a UNIQUE index allows multiple
NULL values for columns that can contain
NULL.
MySQL Enterprise Lack of proper indexes can greatly reduce performance. Subscribe to the MySQL Enterprise Monitor for notification of inefficient use of indexes. For more information, see http://www.mysql.com/products/enterprise/advisors.html.
FULLTEXT indexes are supported only for
MyISAM tables and can include only
CHAR,
VARCHAR, and
TEXT columns. Indexing always
happens over the entire column; column prefix indexing is not
supported and any prefix length is ignored if specified. See
Section 11.8, “Full-Text Search Functions”, for details of operation.
FULLTEXT indexes are available in MySQL 3.23.23
or later.
The MyISAM storage engine supports spatial
columns such as (POINT and
GEOMETRY.
(Chapter 16, Spatial Extensions, describes the spatial data
types.) Spatial and nonspatial indexes are available according to
the following rules.
Spatial indexes (created using SPATIAL INDEX):
Available only for
MyISAMtables in MySQL 4.1 or later.Indexed columns must be
NOT NULL.The full width of each column is indexed by default, but column prefix lengths are allowed. However, as of MySQL 5.0.40, the length is not displayed in
SHOW CREATE TABLEoutput. mysqldump uses that statement. As of that version, if a table withSPATIALindexes containing prefixed columns is dumped and reloaded, the index is created with no prefixes. (The full column width of each column is indexed.)
Nonspatial indexes (created with INDEX,
UNIQUE, or PRIMARY KEY):
Allowed for
MyISAMtables.Columns can be
NULLunless the index is a primary key.For each spatial column in a non-
SPATIALindex exceptPOINTcolumns, a column prefix length must be specified. (This is the same requirement as for indexedBLOBcolumns.) The prefix length is given in bytes.The index type for a non-
SPATIALindex depends on the storage engine. Currently, B-tree is used.
You can add an index on a column that can have
NULL values only if you are using MySQL 3.23.2
or newer and are using the MyISAM,
InnoDB, or BDB storage
engine. This is also true for MEMORY tables as
of MySQL 4.0.2. You can only add an index on a
BLOB or
TEXT column if you are using MySQL
3.23.2 or newer and are using the MyISAM or
BDB storage engine, or MySQL 4.0.14 or newer
and the InnoDB storage engine.
An index_col_name specification can end
with ASC or DESC. These
keywords are allowed for future extensions for specifying
ascending or descending index value storage. Currently, they are
parsed but ignored; index values are always stored in ascending
order.
From MySQL 4.1.0 on, some storage engines allow you to specify an index type when creating an index. The allowable index type values supported by different storage engines are shown in the following table. Where multiple index types are listed, the first one is the default when no index type specifier is given.
| Storage Engine | Allowable Index Types |
MyISAM | BTREE, RTREE |
InnoDB | BTREE |
MEMORY/HEAP | HASH, BTREE |
NDB (MySQL 4.1.3 and later) | HASH, BTREE (see note in text) |
Note
BTREE indexes are implemented by the
NDBCLUSTER storage engine as T-tree
indexes.
For indexes on NDBCLUSTER table
columns, the USING clause can be specified
only for a unique index or primary key. In such cases, the
USING HASH clause prevents the creation of an
implicit ordered index. Without USING HASH, a
statement defining a unique index or primary key automatically
results in the creation of a HASH index in
addition to the ordered index, both of which index the same set
of columns.
The RTREE index type is allowable only for
SPATIAL indexes.
If you specify an index type that is not legal for a given storage engine, but there is another index type available that the engine can use without affecting query results, the engine uses the available type.
Examples:
CREATE TABLE lookup (id INT) ENGINE = MEMORY; CREATE INDEX id_index USING BTREE ON lookup (id);
TYPE is
recognized as a synonym for type_nameUSING
. However,
type_nameUSING is the preferred form.
CREATE [TEMPORARY] TABLE [IF NOT EXISTS]tbl_name(create_definition,...) [table_options]
Or:
CREATE [TEMPORARY] TABLE [IF NOT EXISTS]tbl_name[(create_definition,...)] [table_options]select_statement
Or:
CREATE [TEMPORARY] TABLE [IF NOT EXISTS]tbl_name{ LIKEold_tbl_name| (LIKEold_tbl_name) }
create_definition:col_namecolumn_definition| [CONSTRAINT [symbol]] PRIMARY KEY [index_type] (index_col_name,...) | {INDEX|KEY} [index_name] [index_type] (index_col_name,...) | [CONSTRAINT [symbol]] UNIQUE [INDEX|KEY] [index_name] [index_type] (index_col_name,...) | {FULLTEXT|SPATIAL} [INDEX|KEY] [index_name] (index_col_name,...) | [CONSTRAINT [symbol]] FOREIGN KEY [index_name] (index_col_name,...)reference_definition| CHECK (expr)column_definition:data_type[NOT NULL | NULL] [DEFAULTdefault_value] [AUTO_INCREMENT] [UNIQUE [KEY] | [PRIMARY] KEY] [COMMENT 'string'] [reference_definition]data_type: TINYINT[(length)] [UNSIGNED] [ZEROFILL] | SMALLINT[(length)] [UNSIGNED] [ZEROFILL] | MEDIUMINT[(length)] [UNSIGNED] [ZEROFILL] | INT[(length)] [UNSIGNED] [ZEROFILL] | INTEGER[(length)] [UNSIGNED] [ZEROFILL] | BIGINT[(length)] [UNSIGNED] [ZEROFILL] | REAL[(length,decimals)] [UNSIGNED] [ZEROFILL] | DOUBLE[(length,decimals)] [UNSIGNED] [ZEROFILL] | FLOAT[(length,decimals)] [UNSIGNED] [ZEROFILL] | DECIMAL[(length[,decimals])] [UNSIGNED] [ZEROFILL] | NUMERIC[(length[,decimals])] [UNSIGNED] [ZEROFILL] | DATE | TIME | TIMESTAMP | DATETIME | YEAR | CHAR[(length)] [CHARACTER SETcharset_name] [COLLATEcollation_name] | VARCHAR(length) [CHARACTER SETcharset_name] [COLLATEcollation_name] | BINARY[(length)] | VARBINARY(length) | TINYBLOB | BLOB | MEDIUMBLOB | LONGBLOB | TINYTEXT [BINARY] [CHARACTER SETcharset_name] [COLLATEcollation_name] | TEXT [BINARY] [CHARACTER SETcharset_name] [COLLATEcollation_name] | MEDIUMTEXT [BINARY] [CHARACTER SETcharset_name] [COLLATEcollation_name] | LONGTEXT [BINARY] [CHARACTER SETcharset_name] [COLLATEcollation_name] | ENUM(value1,value2,value3,...) [CHARACTER SETcharset_name] [COLLATEcollation_name] | SET(value1,value2,value3,...) [CHARACTER SETcharset_name] [COLLATEcollation_name] |spatial_typeindex_col_name:col_name[(length)] [ASC | DESC]index_type: USING {BTREE | HASH | RTREE}reference_definition: REFERENCEStbl_name(index_col_name,...) [MATCH FULL | MATCH PARTIAL | MATCH SIMPLE] [ON DELETEreference_option] [ON UPDATEreference_option]reference_option: RESTRICT | CASCADE | SET NULL | NO ACTIONtable_options:table_option[[,]table_option] ...table_option: {ENGINE|TYPE} =engine_name| AUTO_INCREMENT =value| AVG_ROW_LENGTH =value| [DEFAULT] CHARACTER SET =charset_name| CHECKSUM = {0 | 1} | [DEFAULT] COLLATE =collation_name| COMMENT = 'string' | DATA DIRECTORY = 'absolute path to directory' | DELAY_KEY_WRITE = {0 | 1} | INDEX DIRECTORY = 'absolute path to directory' | INSERT_METHOD = { NO | FIRST | LAST } | MAX_ROWS =value| MIN_ROWS =value| PACK_KEYS = {0 | 1 | DEFAULT} | PASSWORD = 'string' | RAID_TYPE = { 1 | STRIPED | RAID0 } RAID_CHUNKS =valueRAID_CHUNKSIZE =value| ROW_FORMAT = {DEFAULT|DYNAMIC|FIXED|COMPRESSED} | UNION = (tbl_name[,tbl_name]...)select_statement:[IGNORE | REPLACE] [AS] SELECT ... (Some legal select statement)
CREATE TABLE creates a table with
the given name. You must have the
CREATE privilege for the table.
Rules for allowable table names are given in Section 8.2, “Database, Table, Index, Column, and Alias Names”. By default, the table is created in the default database. An error occurs if the table exists, if there is no default database, or if the database does not exist.
In MySQL 3.22 or later, the table name can be specified as
db_name.tbl_name to create the table in
a specific database. This works regardless of whether there is a
default database, assuming that the database exists. If you use
quoted identifiers, quote the database and table names separately.
For example, write `mydb`.`mytbl`, not
`mydb.mytbl`.
From MySQL 3.23 on, you can use the TEMPORARY
keyword when creating a table. A TEMPORARY
table is visible only to the current connection, and is dropped
automatically when the connection is closed. This means that two
different connections can use the same temporary table name
without conflicting with each other or with an existing
non-TEMPORARY table of the same name. (The
existing table is hidden until the temporary table is dropped.)
From MySQL 4.0.2 on, to create temporary tables, you must have the
CREATE TEMPORARY TABLES privilege.
Note
CREATE TABLE does not
automatically commit the current active transaction if you use
the TEMPORARY keyword.
In MySQL 3.23 or later, the keywords IF NOT
EXISTS prevent an error from occurring if the table
exists. However, there is no verification that the existing table
has a structure identical to that indicated by the
CREATE TABLE statement.
MySQL represents each table by an .frm table
format (definition) file in the database directory. The storage
engine for the table might create other files as well. In the case
of MyISAM tables, the storage engine creates
data and index files. Thus, for each MyISAM
table tbl_name, there are three disk
files.
| File | Purpose |
| Table format (definition) file |
| Data file |
| Index file |
Chapter 13, Storage Engines, describes what files each storage engine creates to represent tables.
data_type represents the data type in a
column definition. spatial_type
represents a spatial data type. The data type syntax shown is
representative only. For a full description of the syntax
available for specifying column data types, as well as information
about the properties of each type, see
Chapter 10, Data Types, and
Chapter 16, Spatial Extensions.
Some attributes do not apply to all data types.
AUTO_INCREMENT applies only to integer and
floating-point types. DEFAULT does not apply to
the BLOB or
TEXT types.
If neither
NULLnorNOT NULLis specified, the column is treated as thoughNULLhad been specified.An integer or floating-point column can have the additional attribute
AUTO_INCREMENT. When you insert a value ofNULL(recommended) or0into an indexedAUTO_INCREMENTcolumn, the column is set to the next sequence value. Typically this is, wherevalue+1valueis the largest value for the column currently in the table.AUTO_INCREMENTsequences begin with1.To retrieve an
AUTO_INCREMENTvalue after inserting a row, use theLAST_INSERT_ID()SQL function or themysql_insert_id()C API function. See Section 11.10.3, “Information Functions”, and Section 17.7.3.35, “mysql_insert_id()”.As of MySQL 4.1.1, if the
NO_AUTO_VALUE_ON_ZEROSQL mode is enabled, you can store0inAUTO_INCREMENTcolumns as0without generating a new sequence value. See Section 5.1.7, “Server SQL Modes”.Note
There can be only one
AUTO_INCREMENTcolumn per table, it must be indexed, and it cannot have aDEFAULTvalue. As of MySQL 3.23, anAUTO_INCREMENTcolumn works properly only if it contains only positive values. Inserting a negative number is regarded as inserting a very large positive number. This is done to avoid precision problems when numbers “wrap” over from positive to negative and also to ensure that you do not accidentally get anAUTO_INCREMENTcolumn that contains0.For
MyISAMandBDBtables, you can specify anAUTO_INCREMENTsecondary column in a multiple-column key. See Section 3.6.9, “UsingAUTO_INCREMENT”.To make MySQL compatible with some ODBC applications, you can find the
AUTO_INCREMENTvalue for the last inserted row with the following query:SELECT * FROM
tbl_nameWHEREauto_colIS NULLFor information about
InnoDBandAUTO_INCREMENT, see Section 13.2.5.3, “AUTO_INCREMENTHandling inInnoDB”.As of MySQL 4.1, character data types (
CHAR,VARCHAR,TEXT) can includeCHARACTER SETandCOLLATEattributes to specify the character set and collation for the column. For details, see Section 9.1, “Character Set Support”.CHARSETis a synonym forCHARACTER SET. Example:CREATE TABLE t (c CHAR(20) CHARACTER SET utf8 COLLATE utf8_bin);
Also as of 4.1, MySQL interprets length specifications in character column definitions in characters. (Earlier versions interpret them in bytes.) Lengths for
BINARYandVARBINARYare in bytes.NULLvalues are handled differently forTIMESTAMPcolumns than for other column types. Before MySQL 4.1.6, you cannot store a literalNULLin aTIMESTAMPcolumn; setting the column toNULLsets it to the current date and time. BecauseTIMESTAMPcolumns behave this way, theNULLandNOT NULLattributes do not apply in the normal way and are ignored if you specify them. On the other hand, to make it easier for MySQL clients to useTIMESTAMPcolumns, the server reports that such columns can be assignedNULLvalues (which is true), even thoughTIMESTAMPnever actually contains aNULLvalue. You can see this when you useDESCRIBEto get a description of your table.tbl_nameNote that setting a
TIMESTAMPcolumn to0is not the same as setting it toNULL, because0is a validTIMESTAMPvalue.The
DEFAULTclause specifies a default value for a column. With one exception, the default value must be a constant; it cannot be a function or an expression. This means, for example, that you cannot set the default for a date column to be the value of a function such asNOW()orCURRENT_DATE. The exception is that you can specifyCURRENT_TIMESTAMPas the default for aTIMESTAMPcolumn as of MySQL 4.1.2. See Section 10.3.1.2, “TIMESTAMPProperties as of MySQL 4.1”.If a column definition includes no explicit
DEFAULTvalue, MySQL determines the default value as described in Section 10.1.4, “Data Type Default Values”.A comment for a column can be specified with the
COMMENToption. The comment is displayed by theSHOW CREATE TABLEandSHOW FULL COLUMNSstatements. This option is operational as of MySQL 4.1. (It is allowed but ignored in earlier versions.)KEYis normally a synonym forINDEX. From MySQL 4.1, the key attributePRIMARY KEYcan also be specified as justKEYwhen given in a column definition. This was implemented for compatibility with other database systems.A
UNIQUEindex creates a constraint such that all values in the index must be distinct. An error occurs if you try to add a new row with a key value that matches an existing row. This constraint does not apply toNULLvalues except for theBDBstorage engine. For other engines, aUNIQUEindex allows multipleNULLvalues for columns that can containNULL.A
PRIMARY KEYis a unique index where all key columns must be defined asNOT NULL. If they are not explicitly declared asNOT NULL, MySQL declares them so implicitly (and silently). A table can have only onePRIMARY KEY. If you do not have aPRIMARY KEYand an application asks for thePRIMARY KEYin your tables, MySQL returns the firstUNIQUEindex that has noNULLcolumns as thePRIMARY KEY.In
InnoDBtables, having a longPRIMARY KEYwastes a lot of space. (See Section 13.2.11, “InnoDBTable and Index Structures”.)In the created table, a
PRIMARY KEYis placed first, followed by allUNIQUEindexes, and then the nonunique indexes. This helps the MySQL optimizer to prioritize which index to use and also more quickly to detect duplicatedUNIQUEkeys.A
PRIMARY KEYcan be a multiple-column index. However, you cannot create a multiple-column index using thePRIMARY KEYkey attribute in a column specification. Doing so only marks that single column as primary. You must use a separatePRIMARY KEY(clause.index_col_name, ...)If a
PRIMARY KEYorUNIQUEindex consists of only one column that has an integer type, you can also refer to the column as_rowidinSELECTstatements (new in MySQL 3.23.11).In MySQL, the name of a
PRIMARY KEYisPRIMARY. For other indexes, if you do not assign a name, the index is assigned the same name as the first indexed column, with an optional suffix (_2,_3,...) to make it unique. You can see index names for a table usingSHOW INDEX FROM. See Section 12.5.5.13, “tbl_nameSHOW INDEXSyntax”.From MySQL 4.1.0 on, some storage engines allow you to specify an index type when creating an index. The syntax for the
index_typespecifier isUSING.type_nameExample:
CREATE TABLE lookup (id INT, INDEX USING BTREE (id)) ENGINE = MEMORY;
For details about
USING, see Section 12.1.4, “CREATE INDEXSyntax”.For more information about indexes, see Section 7.4.4, “How MySQL Uses Indexes”.
Only the
MyISAM,InnoDB,BDB, and (as of MySQL 4.0.2)MEMORYstorage engines support indexes on columns that can haveNULLvalues. In other cases, you must declare indexed columns asNOT NULLor an error results.For
CHAR,VARCHAR,BINARY, andVARBINARYcolumns, indexes can be created that use only the leading part of column values, usingsyntax to specify an index prefix length.col_name(length)BLOBandTEXTcolumns also can be indexed, but a prefix length must be given. Prefix lengths are given in characters for nonbinary string types and in bytes for binary string types. That is, index entries consist of the firstlengthcharacters of each column value forCHAR,VARCHAR, andTEXTcolumns, and the firstlengthbytes of each column value forBINARY,VARBINARY, andBLOBcolumns. Indexing only a prefix of column values like this can make the index file much smaller. See Section 7.4.2, “Column Indexes”.Only the
MyISAMand (as of MySQL 4.0.14)InnoDBstorage engines support indexing onBLOBandTEXTcolumns. For example:CREATE TABLE test (blob_col BLOB, INDEX(blob_col(10)));
Prefixes can be up to 1000 bytes long (767 bytes for
InnoDBtables). (Before MySQL 4.1.2, the limit is 255 bytes for all tables.) Note that prefix limits are measured in bytes, whereas the prefix length inCREATE TABLEstatements is interpreted as number of characters for nonbinary data types (CHAR,VARCHAR,TEXT). Take this into account when specifying a prefix length for a column that uses a multi-byte character set.An
index_col_namespecification can end withASCorDESC. These keywords are allowed for future extensions for specifying ascending or descending index value storage. Currently, they are parsed but ignored; index values are always stored in ascending order.When you use
ORDER BYorGROUP BYon aTEXTorBLOBcolumn in aSELECT, the server sorts values using only the initial number of bytes indicated by themax_sort_lengthsystem variable. See Section 10.4.3, “TheBLOBandTEXTTypes”.In MySQL 3.23.23 or later, you can create special
FULLTEXTindexes, which are used for full-text searches. Only theMyISAMtable type supportsFULLTEXTindexes. They can be created only fromCHAR,VARCHAR, andTEXTcolumns. Indexing always happens over the entire column; column prefix indexing is not supported and any prefix length is ignored if specified. See Section 11.8, “Full-Text Search Functions”, for details of operation.In MySQL 4.1 or later, you can create
SPATIALindexes on spatial data types. Spatial types are supported only forMyISAMtables and indexed columns must be declared asNOT NULL. See Chapter 16, Spatial Extensions.In MySQL 3.23.44 or later,
InnoDBtables support checking of foreign key constraints. See Section 13.2, “TheInnoDBStorage Engine”. Note that theFOREIGN KEYsyntax inInnoDBis more restrictive than the syntax presented for theCREATE TABLEstatement at the beginning of this section: The columns of the referenced table must always be explicitly named.InnoDBsupports bothON DELETEandON UPDATEactions on foreign keys as of MySQL 3.23.50 and 4.0.8, respectively. For the precise syntax, see Section 13.2.5.4, “FOREIGN KEYConstraints”.For other storage engines, MySQL Server parses and ignores the
FOREIGN KEYandREFERENCESsyntax inCREATE TABLEstatements. TheCHECKclause is parsed but ignored by all storage engines. See Section 1.7.5.5, “Foreign Keys”.Important
For users familiar with the ANSI/ISO SQL Standard, please note that no storage engine, including
InnoDB, recognizes or enforces theMATCHclause used in referential integrity constraint definitions. Use of an explicitMATCHclause will not have the specified effect, and also causesON DELETEandON UPDATEclauses to be ignored. For these reasons, specifyingMATCHshould be avoided.The
MATCHclause in the SQL standard controls howNULLvalues in a composite (multiple-column) foreign key are handled when comparing to a primary key. Starting from MySQL 3.23.50,InnoDBdoes not check foreign key constraints on those foreign key or referenced key values that contain aNULLcolumn.InnoDBessentially implements the semantics defined byMATCH SIMPLE, which allow a foreign key to be all or partiallyNULL. In that case, the (child table) row containing such a foreign key is allowed to be inserted, and does not match any row in the referenced (parent) table.Additionally, MySQL and
InnoDBrequire that the referenced columns be indexed for performance. However, the system does not enforce a requirement that the referenced columns beUNIQUEor be declaredNOT NULL. The handling of foreign key references to nonunique keys or keys that containNULLvalues is not well defined for operations such asUPDATEorDELETE CASCADE. You are advised to use foreign keys that reference onlyUNIQUEandNOT NULLkeys.Furthermore,
InnoDBdoes not recognize or support “inlineREFERENCESspecifications” (as defined in the SQL standard) where the references are defined as part of the column specification.InnoDBacceptsREFERENCESclauses only when specified as part of a separateFOREIGN KEYspecification. For other storage engines, MySQL Server parses and ignores foreign key specifications.There is a hard limit of 4096 columns per table, but the effective maximum may be less for a given table and depends on the factors discussed in Section C.3.2, “The Maximum Number of Columns Per Table”.
The table_option part of the
CREATE TABLE syntax can be used in
MySQL 3.23 and above. The = that separates an
option name and its value is optional as of MySQL 4.1.
The ENGINE and TYPE options
specify the storage engine for the table.
ENGINE was added in MySQL 4.0.18 (for 4.0) and
4.1.2 (for 4.1). It is the preferred option name as of those
versions, and TYPE has become deprecated.
TYPE is supported throughout the 4.x series,
but likely will be removed in the future.
The ENGINE and TYPE table
options take the storage engine names shown in the following
table.
| Storage Engine | Description |
ARCHIVE | The archiving storage engine. See
Section 13.7, “The ARCHIVE Storage Engine”. |
BDB | Transaction-safe tables with page locking. Also known as
BerkeleyDB. See
Section 13.5, “The BDB (BerkeleyDB) Storage
Engine”. |
CSV | Tables that store rows in comma-separated values format. See
Section 13.8, “The CSV Storage Engine”. |
EXAMPLE | An example engine. See Section 13.6, “The EXAMPLE Storage Engine”. |
HEAP | The data for this table is stored only in memory. See
Section 13.4, “The MEMORY (HEAP) Storage Engine”. |
ISAM | The original MySQL storage engine. See
Section 13.10, “The ISAM Storage Engine”. |
InnoDB | Transaction-safe tables with row locking and foreign keys. See
Section 13.2, “The InnoDB Storage Engine”. |
MEMORY | An alias for HEAP. (Actually, as of MySQL 4.1,
MEMORY is the preferred term.) |
MERGE | A collection of MyISAM tables used as one table. Also
known as MRG_MyISAM. See
Section 13.3, “The MERGE Storage Engine”. |
MyISAM | The binary portable storage engine that is the improved replacement for
ISAM. See
Section 13.1, “The MyISAM Storage Engine”. |
NDBCLUSTER | Clustered, fault-tolerant, memory-based tables. Also known as
NDB. See
Chapter 15, MySQL Cluster. |
If a storage engine is specified that is not available, MySQL uses
the default engine instead. Normally, this is
MyISAM. For example, if a table definition
includes the ENGINE=BDB option but the MySQL
server does not support BDB tables, the table
is created as a MyISAM table. This makes it
possible to have a replication setup where you have transactional
tables on the master but tables created on the slave are
nontransactional (to get more speed). In MySQL 4.1.1, a warning
occurs if the storage engine specification is not honored.
The other table options are used to optimize the behavior of the
table. In most cases, you do not have to specify any of them.
These options apply to all storage engines unless otherwise
indicated. Options that do not apply to a given storage engine may
be accepted and remembered as part of the table definition. Such
options then apply if you later use ALTER
TABLE to convert the table to use a different storage
engine.
AUTO_INCREMENTThe initial
AUTO_INCREMENTvalue for the table. This works forMyISAMonly, forMEMORYas of MySQL 4.1.0, and forInnoDBas of MySQL 4.1.2. To set the first auto-increment value for engines that do not support theAUTO_INCREMENTtable option, insert a “dummy” row with a value one less than the desired value after creating the table, and then delete the dummy row.For engines that support the
AUTO_INCREMENTtable option inCREATE TABLEstatements, you can also useALTER TABLEto reset thetbl_nameAUTO_INCREMENT =NAUTO_INCREMENTvalue. The value cannot be set lower than the maximum value currently in the column.AVG_ROW_LENGTHAn approximation of the average row length for your table. You need to set this only for large tables with variable-size rows.
When you create a
MyISAMtable, MySQL uses the product of theMAX_ROWSandAVG_ROW_LENGTHoptions to decide how big the resulting table is. If you do not specify either option, the maximum size forMyISAMdata and index files is 4GB. (If your operating system does not support files that large, table sizes are constrained by the operating system limit.) If you want to keep down the pointer sizes to make the index smaller and faster and you do not really need big files, you can decrease the default pointer size by setting themyisam_data_pointer_sizesystem variable, which was added in MySQL 4.1.2. (See Section 5.1.3, “Server System Variables”.) If you want all your tables to be able to grow above the default limit and are willing to have your tables slightly slower and larger than necessary, you may increase the default pointer size by setting this variable. Setting the value to 7 allows table sizes up to 65,536TB.[DEFAULT] CHARACTER SETSpecify a default character set for the table.
CHARSETis a synonym forCHARACTER SET. If the character set name isDEFAULT, the database character set is used.CHECKSUMSet this to 1 if you want MySQL to maintain a live checksum for all rows (that is, a checksum that MySQL updates automatically as the table changes). This makes the table a little slower to update, but also makes it easier to find corrupted tables. The
CHECKSUM TABLEstatement reports the checksum. (MyISAMonly.)[DEFAULT] COLLATESpecify a default collation for the table.
COMMENTA comment for the table, up to 60 characters long.
DATA DIRECTORY,INDEX DIRECTORYBy using
DATA DIRECTORY='ordirectory'INDEX DIRECTORY='you can specify where thedirectory'MyISAMstorage engine should put a table's data file and index file. The directory must be the full path name to the directory, not a relative path.These options work only for
MyISAMtables from MySQL 4.0 on, when you are not using the--skip-symbolic-linksoption. Your operating system must also have a working, thread-saferealpath()call. See Section 7.6.1.2, “Using Symbolic Links for Tables on Unix”, for more complete information.Important
Beginning with MySQL 4.1.24, you cannot use path names that contain the MySQL data directory with
DATA DIRECTORYorINDEX DIRECTORY. (See Bug#32167.)DELAY_KEY_WRITESet this to 1 if you want to delay key updates for the table until the table is closed. See the description of the
delay_key_writesystem variable in Section 5.1.3, “Server System Variables”. (MyISAMonly.)INSERT_METHODIf you want to insert data into a
MERGEtable, you must specify withINSERT_METHODthe table into which the row should be inserted.INSERT_METHODis an option useful forMERGEtables only. Use a value ofFIRSTorLASTto have inserts go to the first or last table, or a value ofNOto prevent inserts. This option was introduced in MySQL 4.0.0. See Section 13.3, “TheMERGEStorage Engine”.MAX_ROWSThe maximum number of rows you plan to store in the table. This is not a hard limit, but rather a hint to the storage engine that the table must be able to store at least this many rows.
MIN_ROWSThe minimum number of rows you plan to store in the table. The
MEMORYstorage engine uses this option as a hint about memory use.PACK_KEYSPACK_KEYStakes effect only withMyISAMtables. Set this option to 1 if you want to have smaller indexes. This usually makes updates slower and reads faster. Setting the option to 0 disables all packing of keys. Setting it toDEFAULTtells the storage engine to pack only longCHAR,VARCHAR,BINARY, orVARBINARYcolumns.If you do not use
PACK_KEYS, the default is to pack strings, but not numbers. If you usePACK_KEYS=1, numbers are packed as well.When packing binary number keys, MySQL uses prefix compression:
Every key needs one extra byte to indicate how many bytes of the previous key are the same for the next key.
The pointer to the row is stored in high-byte-first order directly after the key, to improve compression.
This means that if you have many equal keys on two consecutive rows, all following “same” keys usually only take two bytes (including the pointer to the row). Compare this to the ordinary case where the following keys takes
storage_size_for_key + pointer_size(where the pointer size is usually 4). Conversely, you get a significant benefit from prefix compression only if you have many numbers that are the same. If all keys are totally different, you use one byte more per key, if the key is not a key that can haveNULLvalues. (In this case, the packed key length is stored in the same byte that is used to mark if a key isNULL.)PASSWORDThis option is unused. If you have a need to scramble your
.frmfiles and make them unusable to any other MySQL server, please contact our sales department.The
RAID_TYPEoption can help you to exceed the 2GB/4GB limit for theMyISAMdata file (not the index file) on operating systems that do not support big files. This option is unnecessary and not recommended for file systems that support big files.You can get more speed from the I/O bottleneck by putting
RAIDdirectories on different physical disks. The only allowedRAID_TYPEisSTRIPED.1andRAID0are aliases forSTRIPED.If you specify the
RAID_TYPEoption for aMyISAMtable, specify theRAID_CHUNKSandRAID_CHUNKSIZEoptions as well. The maximumRAID_CHUNKSvalue is 255.MyISAMcreatesRAID_CHUNKSsubdirectories named00,01,02, ...09,0a,0b, ... in the database directory. In each of these directories,MyISAMcreates a file. When writing data to the data file, thetbl_name.MYDRAIDhandler maps the firstRAID_CHUNKSIZE*1024bytes to the first file, the nextRAID_CHUNKSIZE*1024bytes to the next file, and so on.RAID_TYPEworks on any operating system, as long as you have built MySQL with the--with-raidoption to configure. To determine whether a server supportsRAIDtables, useSHOW VARIABLES LIKE 'have_raid'to see whether the variable value isYES.ROW_FORMATDefines how the rows should be stored. Currently, this option works only with
MyISAMtables. The option value can beFIXEDorDYNAMICfor static or variable-length row format. myisampack sets the type toCOMPRESSED. See Section 13.1.3, “MyISAMTable Storage Formats”.Note
When executing a
CREATE TABLEstatement, if you specify a row format which is not supported by the storage engine that is used for the table, the table is created using that storage engine's default row format. The information reported in this column in response toSHOW TABLE STATUSis the actual row format used. This may differ from the value in theCreate_optionscolumn because the originalCREATE TABLEdefinition is retained during creation.UNIONis used when you want to access a collection of identicalMyISAMtables as one. This works only withMERGEtables. See Section 13.3, “TheMERGEStorage Engine”.In MySQL 4.1, you must have
SELECT,UPDATE, andDELETEprivileges for the tables you map to aMERGEtable.Note
Originally, all tables used had to be in the same database as the
MERGEtable itself. This restriction has been lifted as of MySQL 4.1.1.
Important
The original CREATE TABLE
statement, including all specifications and table options are
stored by MySQL when the table is created. The information is
retained so that if you change storage engines, collations or
other settings using an ALTER
TABLE statement, the original table options specified
are retained. This allows you to change between
InnoDB and MyISAM table
types even though the row formats supported by the two engines
are different.
Because the text of the original statement is retained, but due
to the way that certain values and options may be silently
reconfigured (such as the ROW_FORMAT), the
active table definition (accessible through
DESCRIBE or with
SHOW TABLE STATUS) and the table
creation string (accessible through SHOW
CREATE TABLE) will report different values.
As of MySQL 3.23, you can create one table from another by adding
a SELECT statement at the end of
the CREATE TABLE statement:
CREATE TABLEnew_tblSELECT * FROMorig_tbl;
MySQL creates new columns for all elements in the
SELECT. For example:
mysql>CREATE TABLE test (a INT NOT NULL AUTO_INCREMENT,->PRIMARY KEY (a), KEY(b))->TYPE=MyISAM SELECT b,c FROM test2;
This creates a MyISAM table with three columns,
a, b, and
c. Notice that the columns from the
SELECT statement are appended to
the right side of the table, not overlapped onto it. Take the
following example:
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)
For each row in table foo, a row is inserted in
bar with the values from foo
and default values for the new columns.
In a table resulting from
CREATE TABLE ...
SELECT, columns named only in the
CREATE TABLE part come first.
Columns named in both parts or only in the
SELECT part come after that. The
data type of SELECT columns can be
overridden by also specifying the column in the
CREATE TABLE part.
If any errors occur while copying the data to the table, it is automatically dropped and not created.
CREATE TABLE ...
SELECT does not automatically create any indexes for
you. This is done intentionally to make the statement as flexible
as possible. If you want to have indexes in the created table, you
should specify these before the
SELECT statement:
mysql> CREATE TABLE bar (UNIQUE (n)) SELECT n FROM foo;
Some conversion of data types might occur. For example, the
AUTO_INCREMENT attribute is not preserved, and
VARCHAR columns can become
CHAR columns. Retrained attributes
are NULL (or NOT NULL) and,
for those columns that have them, CHARACTER
SET, COLLATION,
COMMENT, and the DEFAULT
clause.
When creating a table with CREATE ... SELECT,
make sure to alias any function calls or expressions in the query.
If you do not, the CREATE statement might fail
or result in undesirable column names.
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;
As of MySQL 4.1, you can explicitly specify the data type for a generated column:
CREATE TABLE foo (a TINYINT NOT NULL) SELECT b+1 AS a FROM bar;
For CREATE TABLE ...
SELECT, if IF NOT EXISTS is given and
the table already exists, MySQL handles the statement as follows:
The table definition given in the
CREATE TABLEpart is ignored. No error occurs, even if the definition does not match that of the existing table.If there is a mismatch between the number of columns in the table and the number of columns produced by the
SELECTpart, the selected values are assigned to the rightmost columns. For example, if the table containsncolumns and theSELECTproducesmcolumns, wherem<n, the selected values are assigned to themrightmost columns in the table. Each of the initialn–mcolumns is assigned its default value, either that specified explicitly in the column definition or the implicit column data type default if the definition contains no default.
The following example illustrates IF NOT EXISTS
handling:
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)
In MySQL 4.1, you can also use LIKE to create
an empty table based on the definition of another table, including
any column attributes and indexes the original table has:
CREATE TABLEnew_tblLIKEorig_tbl;
The copy is created using the same version of the table storage format as the original table.
CREATE TABLE ... LIKE does not preserve any
DATA DIRECTORY or INDEX
DIRECTORY table options that were specified for the
original table, or any foreign key definitions.
You can precede the SELECT by
IGNORE or
REPLACE to indicate how to handle
rows that duplicate unique key values. With
IGNORE, new rows that duplicate an existing row
on a unique key value are discarded. With
REPLACE, new rows replace rows that
have the same unique key value. If neither
IGNORE nor
REPLACE is specified, duplicate
unique key values result in an error.
To ensure that the update log or binary log can be used to
re-create the original tables, MySQL does not allow concurrent
inserts for CREATE
TABLE ... SELECT statements.
In some cases, MySQL silently changes column specifications from
those given in a CREATE TABLE or
ALTER TABLE statement. These
might be changes to a data type, to attributes associated with a
data type, or to an index specification.
Possible data type changes are given in the following list.
VARCHARcolumns with a length less than four are changed toCHAR.If any column in a table has a variable length, the entire row becomes variable-length as a result. Therefore, if a table contains any variable-length columns (
VARCHAR,TEXT, orBLOB), allCHARcolumns longer than three characters are changed toVARCHARcolumns. This does not affect how you use the columns in any way; in MySQL,VARCHARis just a different way to store characters. MySQL performs this conversion because it saves space and makes table operations faster. See Chapter 13, Storage Engines.From MySQL 4.1.0 onward, a
CHARorVARCHARcolumn with a length specification greater than 255 is converted to the smallestTEXTtype that can hold values of the given length. For example,VARCHAR(500)is converted toTEXT, andVARCHAR(200000)is converted toMEDIUMTEXT. Similar conversions occur forBINARYandVARBINARY, except that they are converted to aBLOBtype.Note that these conversions result in a change in behavior with regard to treatment of trailing spaces.
From MySQL 4.1.2 on, specifying the
CHARACTER SET binaryattribute for a character data type causes the column to be created as the corresponding binary data type:CHARbecomesBINARY,VARCHARbecomesVARBINARY, andTEXTbecomesBLOB. For theENUMandSETdata types, this does not occur; they are created as declared. Suppose that you specify a table using this definition:CREATE TABLE t ( c1 VARCHAR(10) CHARACTER SET binary, c2 TEXT CHARACTER SET binary, c3 ENUM('a','b','c') CHARACTER SET binary );The resulting table has this definition:
CREATE TABLE t ( c1 VARBINARY(10), c2 BLOB, c3 ENUM('a','b','c') CHARACTER SET binary );For a specification of
DECIMAL(, ifM,D)Mis not larger thanD, it is adjusted upward. For example,DECIMAL(10,10)becomesDECIMAL(11,10).
Other silent column specification changes include modifications to attribute or index specifications:
TIMESTAMPdisplay sizes are discarded from MySQL 4.1 on, due to changes made to theTIMESTAMPdata type in that version. Before MySQL 4.1,TIMESTAMPdisplay sizes must be even and in the range from 2 to 14. If you specify a display size of 0 or greater than 14, the size is coerced to 14. Odd-valued sizes in the range from 1 to 13 are coerced to the next higher even number.Also note that, in MySQL 4.1 and later,
TIMESTAMPcolumns areNOT NULLby default.Before MySQL 4.1.6, you cannot store a literal
NULLin aTIMESTAMPcolumn; setting it toNULLsets it to the current date and time. BecauseTIMESTAMPcolumns behave this way, theNULLandNOT NULLattributes do not apply in the normal way and are ignored if you specify them.DESCRIBEalways reports that atbl_nameTIMESTAMPcolumn can be assignedNULLvalues.Columns that are part of a
PRIMARY KEYare madeNOT NULLeven if not declared that way.Starting from MySQL 3.23.51, trailing spaces are automatically deleted from
ENUMandSETmember values when the table is created.MySQL maps certain data types used by other SQL database vendors to MySQL types. See Section 10.7, “Using Data Types from Other Database Engines”.
If you include a
USINGclause to specify an index type that is not legal for a given storage engine, but there is another index type available that the engine can use without affecting query results, the engine uses the available type.
To see whether MySQL used a data type other than the one you
specified, issue a DESCRIBE or
SHOW CREATE TABLE statement after
creating or altering the table.
Certain other data type changes can occur if you compress a table using myisampack. See Section 13.1.3.3, “Compressed Table Characteristics”.
DROP DATABASE [IF EXISTS] db_name
DROP DATABASE drops all tables in
the database and deletes the database. Be
very careful with this statement! To use
DROP DATABASE, you need the
DROP privilege on the database.
Important
When a database is dropped, user privileges on the database are
not automatically dropped. See
Section 12.5.1.2, “GRANT Syntax”.
In MySQL 3.22 or later, you can use the keywords IF
EXISTS to prevent an error from occurring if the
database does not exist.
If you use DROP DATABASE on a
symbolically linked database, both the link and the original
database are deleted.
As of MySQL 4.1.2, DROP DATABASE
returns the number of tables that were removed. This corresponds
to the number of .frm files removed.
The DROP DATABASE statement removes
from the given database directory those files and directories that
MySQL itself may create during normal operation:
All files with the following extensions.
.BAK.DAT.HSH.ISD.ISM.MRG.MYD.MYI.db.frm.ibd.ndbAll subdirectories with names that consist of two hex digits
00-ff. These are subdirectories used forRAIDtables. (These directories are not removed in versions of MySQL after 4.1, where support forRAIDtables is removed. You should convert any existingRAIDtables and remove these directories manually before upgrading to later MySQL versions.)The
db.optfile, if it exists.
If other files or directories remain in the database directory
after MySQL removes those just listed, the database directory
cannot be removed. In this case, you must remove any remaining
files or directories manually and issue the
DROP DATABASE statement again.
You can also drop databases with mysqladmin. See Section 4.5.2, “mysqladmin — Client for Administering a MySQL Server”.
DROP INDEXindex_nameONtbl_name
DROP INDEX drops the index named
index_name from the table
tbl_name. In MySQL 3.22 or later,
DROP INDEX is mapped to an
ALTER TABLE statement to drop the
index. See Section 12.1.2, “ALTER TABLE Syntax”.
DROP INDEX does not do anything
prior to MySQL 3.22.
DROP [TEMPORARY] TABLE [IF EXISTS]
tbl_name [, tbl_name] ...
[RESTRICT | CASCADE]
DROP TABLE removes one or more
tables. You must have the DROP
privilege for each table. All table data and the table definition
are removed, so be
careful with this statement! If any of the tables named
in the argument list do not exist, MySQL returns an error
indicating by name which nonexisting tables it was unable to drop,
but it also drops all of the tables in the list that do exist.
Important
When a table is dropped, user privileges on the table are
not automatically dropped. See
Section 12.5.1.2, “GRANT Syntax”.
In MySQL 3.22 or later, you can use the keywords IF
EXISTS to prevent an error from occurring for tables
that do not exist. As of MySQL 4.1, a NOTE is
generated for each nonexistent table when using IF
EXISTS. See Section 12.5.5.26, “SHOW WARNINGS Syntax”.
RESTRICT and CASCADE are
allowed to make porting easier. In MySQL 4.1 and
earlier, they do nothing.
Note
DROP TABLE automatically commits
the current active transaction, unless you are using MySQL 4.1
or higher and the TEMPORARY keyword.
The TEMPORARY keyword is ignored in MySQL 4.0.
As of 4.1, it has the following effect:
The statement drops only
TEMPORARYtables.The statement does not end an ongoing transaction.
No access rights are checked. (A
TEMPORARYtable is visible only to the session that created it, so no check is necessary.)
Using TEMPORARY is a good way to ensure that
you do not accidentally drop a non-TEMPORARY
table.
RENAME TABLEtbl_nameTOnew_tbl_name[,tbl_name2TOnew_tbl_name2] ...
This statement renames one or more tables. It was added in MySQL 3.23.23.
The rename operation is done atomically, which means that no other
session can access any of the tables while the rename is running.
For example, if you have an existing table
old_table, you can create another table
new_table that has the same structure but is
empty, and then replace the existing table with the empty one as
follows (assuming that backup_table does not
already exist):
CREATE TABLE new_table (...); RENAME TABLE old_table TO backup_table, new_table TO old_table;
If the statement renames more than one table, renaming operations
are done from left to right. If you want to swap two table names,
you can do so like this (assuming that
tmp_table does not already exist):
RENAME TABLE old_table TO tmp_table,
new_table TO old_table,
tmp_table TO new_table;
As long as two databases are on the same file system, you can use
RENAME TABLE to move a table from
one database to another:
RENAME TABLEcurrent_db.tbl_nameTOother_db.tbl_name;
Any privileges granted specifically for the renamed table or view are not migrated to the new name. They must be changed manually.
When you execute RENAME, you cannot have any
locked tables or active transactions. You must also have the
ALTER and
DROP privileges on the original
table, and the CREATE and
INSERT privileges on the new table.
If MySQL encounters any errors in a multiple-table rename, it does a reverse rename for all renamed tables to return everything to its original state.
You cannot use RENAME to rename a
TEMPORARY table. However, you can use
ALTER TABLE instead:
mysql> ALTER TABLE orig_name RENAME new_name;
Single-table syntax:
DELETE [LOW_PRIORITY] [QUICK] [IGNORE] FROMtbl_name[WHEREwhere_condition] [ORDER BY ...] [LIMITrow_count]
Multiple-table syntax:
DELETE [LOW_PRIORITY] [QUICK] [IGNORE]
tbl_name[.*] [, tbl_name[.*]] ...
FROM table_references
[WHERE where_condition]
Or:
DELETE [LOW_PRIORITY] [QUICK] [IGNORE]
FROM tbl_name[.*] [, tbl_name[.*]] ...
USING table_references
[WHERE where_condition]
For the single-table syntax, the
DELETE statement deletes rows from
tbl_name. The number of rows deleted
can be determined by calling the
mysql_info() C API function. The
WHERE clause, if given, specifies the
conditions that identify which rows to delete. With no
WHERE clause, all rows are deleted. If the
ORDER BY clause is specified, the rows are
deleted in the order that is specified. The
LIMIT clause places a limit on the number of
rows that can be deleted.
For the multiple-table syntax,
DELETE deletes from each
tbl_name the rows that satisfy the
conditions. In this case, ORDER BY and
LIMIT cannot be used.
where_condition is an expression that
evaluates to true for each row to be deleted. It is specified as
described in Section 12.2.7, “SELECT Syntax”.
Currently, you cannot delete from a table and select from the same table in a subquery.
As stated, a DELETE statement with
no WHERE clause deletes all rows. A faster way
to do this, when you do not need to know the number of deleted
rows, is to use TRUNCATE
TABLE. However, within a transaction or if you have a
lock on the table,
TRUNCATE TABLE
cannot be used whereas DELETE can.
See Section 12.2.9, “TRUNCATE Syntax”, and Section 12.4.5, “LOCK TABLES and
UNLOCK
TABLES Syntax”.
In MySQL 3.23, DELETE without a
WHERE clause returns zero as the number of
affected rows.
In MySQL 3.23, if you really want to know how many rows are
deleted when you are deleting all rows, and are willing to suffer
a speed penalty, you can use a
DELETE statement that includes a
WHERE clause with an expression that is true
for every row. For example:
mysql> DELETE FROM tbl_name WHERE 1>0;
This is much slower than TRUNCATE
, because it deletes
rows one at a time.
tbl_name
If you delete the row containing the maximum value for an
AUTO_INCREMENT column, the value is reused
later for an ISAM or BDB
table, but not for a MyISAM or
InnoDB table. If you delete all rows in the
table with DELETE FROM
(without a
tbl_nameWHERE clause) in
autocommit mode, the sequence
starts over for all storage engines except
InnoDB and (as of MySQL 4.0)
MyISAM. There are some exceptions to this
behavior for InnoDB tables, as discussed in
Section 13.2.5.3, “AUTO_INCREMENT Handling in InnoDB”.
For MyISAM and BDB tables,
you can specify an AUTO_INCREMENT secondary
column in a multiple-column key. In this case, reuse of values
deleted from the top of the sequence occurs even for
MyISAM tables. See
Section 3.6.9, “Using AUTO_INCREMENT”.
The DELETE statement supports the
following modifiers:
If you specify
LOW_PRIORITY, the server delays execution of theDELETEuntil no other clients are reading from the table. This affects only storage engines that use only table-level locking (MyISAM,MEMORY,MERGE).For
MyISAMtables, if you use theQUICKkeyword, the storage engine does not merge index leaves during delete, which may speed up some kinds of delete operations.The
IGNOREkeyword causes MySQL to ignore all errors during the process of deleting rows. (Errors encountered during the parsing stage are processed in the usual manner.) Errors that are ignored due to the use ofIGNOREare returned as warnings. This option first appeared in MySQL 4.1.1.
The speed of delete operations may also be affected by factors
discussed in Section 7.2.16, “Speed of DELETE Statements”.
In MyISAM tables, deleted rows are maintained
in a linked list and subsequent
INSERT operations reuse old row
positions. To reclaim unused space and reduce file sizes, use the
OPTIMIZE TABLE statement or the
myisamchk utility to reorganize tables.
OPTIMIZE TABLE is easier to use,
but myisamchk is faster. See
Section 12.5.2.5, “OPTIMIZE TABLE Syntax”, and Section 4.6.2, “myisamchk — MyISAM Table-Maintenance Utility”.
The QUICK modifier affects whether index leaves
are merged for delete operations. DELETE QUICK
is most useful for applications where index values for deleted
rows are replaced by similar index values from rows inserted
later. In this case, the holes left by deleted values are reused.
DELETE QUICK is not useful when deleted values
lead to underfilled index blocks spanning a range of index values
for which new inserts occur again. In this case, use of
QUICK can lead to wasted space in the index
that remains unreclaimed. Here is an example of such a scenario:
Create a table that contains an indexed
AUTO_INCREMENTcolumn.Insert many rows into the table. Each insert results in an index value that is added to the high end of the index.
Delete a block of rows at the low end of the column range using
DELETE QUICK.
In this scenario, the index blocks associated with the deleted
index values become underfilled but are not merged with other
index blocks due to the use of QUICK. They
remain underfilled when new inserts occur, because new rows do not
have index values in the deleted range. Furthermore, they remain
underfilled even if you later use
DELETE without
QUICK, unless some of the deleted index values
happen to lie in index blocks within or adjacent to the
underfilled blocks. To reclaim unused index space under these
circumstances, use OPTIMIZE TABLE.
If you are going to delete many rows from a table, it might be
faster to use DELETE QUICK followed by
OPTIMIZE TABLE. This rebuilds the
index rather than performing many index block merge operations.
The MySQL-specific LIMIT
option to
row_countDELETE tells the server the maximum
number of rows to be deleted before control is returned to the
client. This can be used to ensure that a given
DELETE statement does not take too
much time. You can simply repeat the
DELETE statement until the number
of affected rows is less than the LIMIT value.
If the DELETE statement includes an
ORDER BY clause, rows are deleted in the order
specified by the clause. This is useful primarily in conjunction
with LIMIT. For example, the following
statement finds rows matching the WHERE clause,
sorts them by timestamp_column, and deletes the
first (oldest) one:
DELETE FROM somelog WHERE user = 'jcole' ORDER BY timestamp_column LIMIT 1;
ORDER BY may also be useful in some cases to
delete rows in an order required to avoid referential integrity
violations.
ORDER BY can be used with
DELETE beginning with MySQL 4.0.0.
From MySQL 4.0, you can specify multiple tables in the
DELETE statement to delete rows
from one or more tables depending on a particular condition in
multiple tables. However, you cannot use ORDER
BY or LIMIT in a multiple-table
DELETE.
If you are deleting many rows from a large table, you may exceed
the lock table size for an InnoDB table. To
avoid this problem, or simply to minimize the time that the table
remains locked, the following strategy (which does not use
DELETE at all) might be helpful:
Select the rows not to be deleted into an empty table that has the same structure as the original table:
INSERT INTO t_copy SELECT * FROM t WHERE ... ;
Use
RENAME TABLEto atomically move the original table out of the way and rename the copy to the original name:RENAME TABLE t TO t_old, t_copy TO t;
Drop the original table:
DROP TABLE t_old;
No other sessions can access the tables involved while
RENAME TABLE executes, so the
rename operation is not subject to concurrency problems. See
Section 12.1.9, “RENAME TABLE Syntax”.
You can specify multiple tables in a
DELETE statement to delete rows
from one or more tables depending on the particular condition in
the WHERE clause. However, you cannot use
ORDER BY or LIMIT in a
multiple-table DELETE. The
table_references clause lists the
tables involved in the join. Its syntax is described in
Section 12.2.7.1, “JOIN Syntax”.
The first multiple-table DELETE
syntax is supported starting from MySQL 4.0.0. The second is
supported starting from MySQL 4.0.2.
For the first multiple-table syntax, only matching rows from the
tables listed before the FROM clause are
deleted. For the second multiple-table syntax, only matching rows
from the tables listed in the FROM clause
(before the USING clause) are deleted. The
effect is that you can delete rows from many tables at the same
time and have additional tables that are used only for searching:
DELETE t1, t2 FROM t1 INNER JOIN t2 INNER JOIN t3 WHERE t1.id=t2.id AND t2.id=t3.id;
Or:
DELETE FROM t1, t2 USING t1 INNER JOIN t2 INNER JOIN t3 WHERE t1.id=t2.id AND t2.id=t3.id;
These statements use all three tables when searching for rows to
delete, but delete matching rows only from tables
t1 and t2.
The preceding examples use INNER JOIN, but
multiple-table DELETE statements
can use other types of join allowed in
SELECT statements, such as
LEFT JOIN. For example, to delete rows that
exist in t1 that have no match in
t2, use a LEFT JOIN:
DELETE t1 FROM t1 LEFT JOIN t2 ON t1.id=t2.id WHERE t2.id IS NULL;
The syntax allows .* after each
tbl_name for compatibility with
Access.
If you use a multiple-table DELETE
statement involving InnoDB tables for which
there are foreign key constraints, the MySQL optimizer might
process tables in an order that differs from that of their
parent/child relationship. In this case, the statement fails and
rolls back. Instead, you should delete from a single table and
rely on the ON DELETE capabilities that
InnoDB provides to cause the other tables to be
modified accordingly.
If table aliases are used, they should be declared in the
table_references part of the statement.
Elsewhere in the statement, aliases references are allowed but
should not be declared.
Note
The syntax for multiple-table
DELETE statements that use table
aliases changed between MySQL 4.0 and 4.1. In MySQL 4.0, you
should use the true table name to refer to any table from which
rows should be deleted:
DELETE test FROM test AS t1, test2 WHERE ...
In MySQL 4.1, if you declare an alias for a table, you must use the alias when referring to the table:
DELETE t1 FROM test AS t1, test2 WHERE ...
We did not make this change in 4.0 to avoid breaking any old 4.0
applications that were using the old syntax. However, if you use
such DELETE statements and are
using replication, the change in syntax means that a 4.0 master
cannot replicate to 4.1 (or higher) slaves.
Cross-database deletes are supported for multiple-table deletes, but prior to MySQL 4.1.2 you must refer to the tables without using aliases. For example:
DELETE test1.tmp1, test2.tmp2 FROM test1.tmp1, test2.tmp2 WHERE ...
As of MySQL 4.1.2, aliases can be used, but you should be aware
that in the list of tables from which to delete rows, aliases will
have a default database unless one is specified explicitly. For
example, if the current database is test, the
following statement does not work because the unqualified alias
a1 has a default database of
test:
DELETE a1, a2 FROM db1.t1 AS a1 INNER JOIN db2.t2 AS a2 WHERE a1.id=a2.id;
To correctly match the alias, you must explicitly qualify it with the database of the table being aliased:
DELETE db1.a1, db2.a2 FROM db1.t1 AS a1 INNER JOIN db2.t2 AS a2 WHERE a1.id=a2.id;
DOexpr[,expr] ...
DO executes the expressions but
does not return any results. In most respects,
DO is shorthand for SELECT
, but has the
advantage that it is slightly faster when you do not care about
the result.
expr, ...
DO is useful primarily with
functions that have side effects, such as
RELEASE_LOCK().
DO was added in MySQL 3.23.47.
HANDLERtbl_nameOPEN [ [AS]alias] HANDLERtbl_nameREADindex_name{ = | >= | <= | < } (value1,value2,...) [ WHEREwhere_condition] [LIMIT ... ] HANDLERtbl_nameREADindex_name{ FIRST | NEXT | PREV | LAST } [ WHEREwhere_condition] [LIMIT ... ] HANDLERtbl_nameREAD { FIRST | NEXT } [ WHEREwhere_condition] [LIMIT ... ] HANDLERtbl_nameCLOSE
The HANDLER statement provides
direct access to table storage engine interfaces. It is available
for MyISAM tables as MySQL 4.0.0 and
InnoDB tables as of MySQL 4.0.3.
The HANDLER ... OPEN statement opens a table,
making it accessible via subsequent HANDLER ...
READ statements. This table object is not shared by
other sessions and is not closed until the session calls
HANDLER ... CLOSE or the session terminates. If
you open the table using an alias, further references to the open
table with other HANDLER statements
must use the alias rather than the table name.
The first HANDLER ... READ syntax fetches a row
where the index specified satisfies the given values and the
WHERE condition is met. If you have a
multiple-column index, specify the index column values as a
comma-separated list. Either specify values for all the columns in
the index, or specify values for a leftmost prefix of the index
columns. Suppose that an index my_idx includes
three columns named col_a,
col_b, and col_c, in that
order. The HANDLER statement can
specify values for all three columns in the index, or for the
columns in a leftmost prefix. For example:
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) ...
To employ the HANDLER interface to
refer to a table's PRIMARY KEY, use the quoted
identifier `PRIMARY`:
HANDLER tbl_name READ `PRIMARY` ...
The second HANDLER ... READ syntax fetches a
row from the table in index order that matches the
WHERE condition.
The third HANDLER ... READ syntax fetches a row
from the table in natural row order that matches the
WHERE condition. It is faster than
HANDLER when a full table
scan is desired. Natural row order is the order in which rows are
stored in a tbl_name READ
index_nameMyISAM table data file. This
statement works for InnoDB tables as well, but
there is no such concept because there is no separate data file.
Without a LIMIT clause, all forms of
HANDLER ... READ fetch a single row if one is
available. To return a specific number of rows, include a
LIMIT clause. It has the same syntax as for the
SELECT statement. See
Section 12.2.7, “SELECT Syntax”.
HANDLER ... CLOSE closes a table that was
opened with HANDLER ... OPEN.
There are several reasons to use the
HANDLER interface instead of normal
SELECT statements:
HANDLERis faster thanSELECT:A designated storage engine handler object is allocated for the
HANDLER ... OPEN. The object is reused for subsequentHANDLERstatements for that table; it need not be reinitialized for each one.There is less parsing involved.
There is no optimizer or query-checking overhead.
The table does not have to be locked between two handler requests.
The handler interface does not have to provide a consistent look of the data (for example, dirty reads are allowed), so the storage engine can use optimizations that
SELECTdoes not normally allow.
For applications that use a low-level
ISAM-like interface,HANDLERmakes it much easier to port them to MySQL.HANDLERenables you to traverse a database in a manner that is difficult (or even impossible) to accomplish withSELECT. TheHANDLERinterface is a more natural way to look at data when working with applications that provide an interactive user interface to the database.
HANDLER is a somewhat low-level
statement. For example, it does not provide consistency. That is,
HANDLER ... OPEN does not
take a snapshot of the table, and does not
lock the table. This means that after a HANDLER ...
OPEN statement is issued, table data can be modified (by
the current session or other sessions) and these modifications
might be only partially visible to HANDLER ...
NEXT or HANDLER ... PREV scans.
An open handler can be closed and marked for reopen, in which case the handler loses its position in the table. This occurs when both of the following circumstances are true:
Any session executes
FLUSH TABLESor DDL statements on the handler's table.The session in which the handler is open executes non-
HANDLERstatements that use tables.
INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE]
[INTO] tbl_name [(col_name,...)]
{VALUES | VALUE} ({expr | DEFAULT},...),(...),...
[ ON DUPLICATE KEY UPDATE
col_name=expr
[, col_name=expr] ... ]
Or:
INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE]
[INTO] tbl_name
SET col_name={expr | DEFAULT}, ...
[ ON DUPLICATE KEY UPDATE
col_name=expr
[, col_name=expr] ... ]
Or:
INSERT [LOW_PRIORITY | HIGH_PRIORITY] [IGNORE]
[INTO] tbl_name [(col_name,...)]
SELECT ...
[ ON DUPLICATE KEY UPDATE
col_name=expr
[, col_name=expr] ... ]
INSERT inserts new rows into an
existing table. The INSERT
... VALUES and
INSERT ... SET
forms of the statement insert rows based on explicitly specified
values. The INSERT
... SELECT form inserts rows selected from another table
or tables. The INSERT ...
VALUES form with multiple value lists is supported in
MySQL 3.22.5 or later. The
INSERT ... SET
syntax is supported in MySQL 3.22.10 or later.
INSERT ...
SELECT is discussed further in
Section 12.2.4.1, “INSERT ...
SELECT Syntax”.
You can use REPLACE instead of
INSERT to overwrite old rows.
REPLACE is the counterpart to
INSERT IGNORE in
the treatment of new rows that contain unique key values that
duplicate old rows: The new rows are used to replace the old rows
rather than being discarded. See Section 12.2.6, “REPLACE Syntax”.
tbl_name is the table into which rows
should be inserted. The columns for which the statement provides
values can be specified as follows:
You can provide a comma-separated list of column names following the table name. In this case, a value for each named column must be provided by the
VALUESlist or theSELECTstatement.If you do not specify a list of column names for
INSERT ... VALUESorINSERT ... SELECT, values for every column in the table must be provided by theVALUESlist or theSELECTstatement. If you do not know the order of the columns in the table, useDESCRIBEto find out.tbl_nameThe
SETclause indicates the column names explicitly.
Column values can be given in several ways:
Normally, any column not explicitly given a value is set to its default (explicit or implicit) value. For example, if you specify a column list that does not name all the columns in the table, unnamed columns are set to their default values. Default value assignment is described in Section 10.1.4, “Data Type Default Values”, and Section 1.7.6.2, “Constraints on Invalid Data”.
You can use the keyword
DEFAULTto explicitly set a column to its default value. (New in MySQL 4.0.3.) This makes it easier to writeINSERTstatements that assign values to all but a few columns, because it enables you to avoid writing an incompleteVALUESlist that does not include a value for each column in the table. Otherwise, you would have to write out the list of column names corresponding to each value in theVALUESlist.As of MySQL 4.1.0, you can use
DEFAULT(as a more general form that can be used in expressions to produce a given column's default value.col_name)If both the column list and the
VALUESlist are empty,INSERTcreates a row with each column set to its default value:INSERT INTO
tbl_name() VALUES();You can specify an expression
exprto provide a column value. This might involve type conversion if the type of the expression does not match the type of the column, and conversion of a given value can result in different inserted values depending on the data type. For example, inserting the string'1999.0e-2'into anINT,FLOAT,DECIMAL(10,6), orYEARcolumn results in the values1999,19.9921,19.992100, and1999being inserted, respectively. The reason the value stored in theINTandYEARcolumns is1999is that the string-to-integer conversion looks only at as much of the initial part of the string as may be considered a valid integer or year. For the floating-point and fixed-point columns, the string-to-floating-point conversion considers the entire string a valid floating-point value.An expression
exprcan refer to any column that was set earlier in a value list. For example, you can do this because the value forcol2refers tocol1, which has previously been assigned:INSERT INTO
tbl_name(col1,col2) VALUES(15,col1*2);But the following is not legal, because the value for
col1refers tocol2, which is assigned aftercol1:INSERT INTO
tbl_name(col1,col2) VALUES(col2*2,15);One exception involves columns that contain
AUTO_INCREMENTvalues. Because theAUTO_INCREMENTvalue is generated after other value assignments, any reference to anAUTO_INCREMENTcolumn in the assignment returns a0.
INSERT statements that use
VALUES syntax can insert multiple rows. To do
this, include multiple lists of column values, each enclosed
within parentheses and separated by commas. Example:
INSERT INTO tbl_name (a,b,c) VALUES(1,2,3),(4,5,6),(7,8,9);
The values list for each row must be enclosed within parentheses. The following statement is illegal because the number of values in the list does not match the number of column names:
INSERT INTO tbl_name (a,b,c) VALUES(1,2,3,4,5,6,7,8,9);
VALUE is a synonym for
VALUES in this context. Neither implies
anything about the number of values lists, and either may be used
whether there is a single values list or multiple lists.
The affected-rows value for an
INSERT can be obtained using the
mysql_affected_rows() C API
function (see Section 17.7.3.1, “mysql_affected_rows()”).
If you use an INSERT ...
VALUES statement with multiple value lists or
INSERT ...
SELECT, the statement returns an information string in
this format:
Records: 100 Duplicates: 0 Warnings: 0
Records indicates the number of rows processed
by the statement. (This is not necessarily the number of rows
actually inserted because Duplicates can be
nonzero.) Duplicates indicates the number of
rows that could not be inserted because they would duplicate some
existing unique index value. Warnings indicates
the number of attempts to insert column values that were
problematic in some way. Warnings can occur under any of the
following conditions:
Inserting
NULLinto a column that has been declaredNOT NULL. For multiple-rowINSERTstatements orINSERT INTO ... SELECTstatements, the column is set to the implicit default value for the column data type. This is0for numeric types, the empty string ('') for string types, and the “zero” value for date and time types.INSERT INTO ... SELECTstatements are handled the same way as multiple-row inserts because the server does not examine the result set from theSELECTto see whether it returns a single row. (For a single-rowINSERT, no warning occurs whenNULLis inserted into aNOT NULLcolumn. Instead, the statement fails with an error.)Setting a numeric column to a value that lies outside the column's range. The value is clipped to the closest endpoint of the range.
Assigning a value such as
'10.34 a'to a numeric column. The trailing nonnumeric text is stripped off and the remaining numeric part is inserted. If the string value has no leading numeric part, the column is set to0.Inserting a string into a string column (
CHAR,VARCHAR,TEXT, orBLOB) that exceeds the column's maximum length. The value is truncated to the column's maximum length.Inserting a value into a date or time column that is illegal for the data type. The column is set to the appropriate zero value for the type.
If you are using the C API, the information string can be obtained
by invoking the mysql_info()
function. See Section 17.7.3.33, “mysql_info()”.
If INSERT inserts a row into a
table that has an AUTO_INCREMENT column, you
can find the value used for that column by using the SQL
LAST_INSERT_ID() function. From
within the C API, use the
mysql_insert_id() function.
However, you should note that the two functions do not always
behave identically. The behavior of
INSERT statements with respect to
AUTO_INCREMENT columns is discussed further in
Section 11.10.3, “Information Functions”, and
Section 17.7.3.35, “mysql_insert_id()”.
The INSERT statement supports the
following modifiers:
If you use the
DELAYEDkeyword, the server puts the row or rows to be inserted into a buffer, and the client issuing theINSERT DELAYEDstatement can then continue immediately. If the table is in use, the server holds the rows. When the table is free, the server begins inserting rows, checking periodically to see whether there are any new read requests for the table. If there are, the delayed row queue is suspended until the table becomes free again. See Section 12.2.4.2, “INSERT DELAYEDSyntax”.DELAYEDwas added in MySQL 3.22.5.DELAYEDis ignored withINSERT ... SELECTorINSERT ... ON DUPLICATE KEY UPDATE.If you use the
LOW_PRIORITYkeyword, execution of theINSERTis delayed until no other clients are reading from the table. This includes other clients that began reading while existing clients are reading, and while theINSERT LOW_PRIORITYstatement is waiting. It is possible, therefore, for a client that issues anINSERT LOW_PRIORITYstatement to wait for a very long time (or even forever) in a read-heavy environment. (This is in contrast toINSERT DELAYED, which lets the client continue at once. Note thatLOW_PRIORITYshould normally not be used withMyISAMtables because doing so disables concurrent inserts. See Section 7.3.3, “Concurrent Inserts”.LOW_PRIORITYwas added in MySQL 3.22.5.LOW_PRIORITYandHIGH_PRIORITYaffect only storage engines that use only table-level locking (MyISAM,MEMORY,MERGE).If you specify
HIGH_PRIORITY, it overrides the effect of the--low-priority-updatesoption if the server was started with that option. It also causes concurrent inserts not to be used. See Section 7.3.3, “Concurrent Inserts”.HIGH_PRIORITYwas added in MySQL 3.23.11.If you use the
IGNOREkeyword, errors that occur while executing theINSERTstatement are treated as warnings instead. For example, withoutIGNORE, a row that duplicates an existingUNIQUEindex orPRIMARY KEYvalue in the table causes a duplicate-key error and the statement is aborted. WithIGNORE, the row still is not inserted, but no error is issued. Data conversions that would trigger errors abort the statement ifIGNOREis not specified. WithIGNORE, invalid values are adjusted to the closest values and inserted; warnings are produced but the statement does not abort. You can determine with themysql_info()C API function how many rows were actually inserted into the table.If you specify
ON DUPLICATE KEY UPDATE, and a row is inserted that would cause a duplicate value in aUNIQUEindex orPRIMARY KEY, anUPDATEof the old row is performed. is performed. The affected-rows value per row is 1 if the row is inserted as a new row and 2 if an existing row is updated. See Section 12.2.4.3, “INSERT ... ON DUPLICATE KEY UPDATESyntax”.ON DUPLICATE KEY UPDATEwas added in MySQL 4.1.0.
Inserting into a table requires the
INSERT privilege for the table. If
the ON DUPLICATE KEY UPDATE clause is used and
a duplicate key causes an UPDATE to
be performed instead, the statement requires the
UPDATE privilege for the columns to
be updated. For columns that are read but not modified you need
only the SELECT privilege (such as
for a column referenced only on the right hand side of an
col_name=expr
assignment in an ON DUPLICATE KEY UPDATE
clause).
INSERT [LOW_PRIORITY | HIGH_PRIORITY] [IGNORE]
[INTO] tbl_name [(col_name,...)]
SELECT ...
[ ON DUPLICATE KEY UPDATE col_name=expr, ... ]
With INSERT ...
SELECT, you can quickly insert many rows into a table
from one or many tables. For example:
INSERT INTO tbl_temp2 (fld_id) SELECT tbl_temp1.fld_order_id FROM tbl_temp1 WHERE tbl_temp1.fld_order_id > 100;
The following conditions hold for a
INSERT ...
SELECT statements:
Prior to MySQL 4.0.1,
INSERT ... SELECTimplicitly operates inIGNOREmode. As of MySQL 4.0.1, specifyIGNOREexplicitly to ignore rows that would cause duplicate-key violations.DELAYEDis ignored withINSERT ... SELECT.Prior to MySQL 4.0.14, the target table of the
INSERTstatement cannot appear in theFROMclause of theSELECTpart of the query. This limitation is lifted in 4.0.14. In this case, MySQL creates a temporary table to hold the rows from theSELECTand then inserts those rows into the target table. However, it remains true that you cannot useINSERT INTO t ... SELECT ... FROM twhentis aTEMPORARYtable, becauseTEMPORARYtables cannot be referred to twice in the same statement (see Section A.1.7.3, “TEMPORARYTable Problems”).AUTO_INCREMENTcolumns work as usual.To ensure that the binary log can be used to re-create the original tables, MySQL does not allow concurrent inserts for
INSERT ... SELECTstatements.Currently, you cannot insert into a table and select from the same table in a subquery.
To avoid ambiguous column reference problems when the
SELECTand theINSERTrefer to the same table, provide a unique alias for each table used in theSELECTpart, and qualify column names in that part with the appropriate alias.
In the values part of ON DUPLICATE KEY
UPDATE, you can refer to columns in other tables, as
long as you do not use GROUP BY in the
SELECT part. One side effect is
that you must qualify nonunique column names in the values part.
INSERT DELAYED ...
The DELAYED option for the
INSERT statement is a MySQL
extension to standard SQL that is very useful if you have
clients that cannot or need not wait for the
INSERT to complete. This is a
common situation when you use MySQL for logging and you also
periodically run SELECT and
UPDATE statements that take a
long time to complete. DELAYED was introduced
in MySQL 3.22.15.
When a client uses INSERT
DELAYED, it gets an okay from the server at once, and
the row is queued to be inserted when the table is not in use by
any other thread.
Another major benefit of using INSERT
DELAYED is that inserts from many clients are bundled
together and written in one block. This is much faster than
performing many separate inserts.
Note that INSERT DELAYED is
slower than a normal INSERT if
the table is not otherwise in use. There is also the additional
overhead for the server to handle a separate thread for each
table for which there are delayed rows. This means that you
should use INSERT DELAYED only
when you are really sure that you need it.
The queued rows are held only in memory until they are inserted
into the table. This means that if you terminate
mysqld forcibly (for example, with
kill -9) or if mysqld dies
unexpectedly, any queued rows that have not been
written to disk are lost.
There are some constraints on the use of
DELAYED:
INSERT DELAYEDworks only withISAM,MyISAM, and (beginning with MySQL 4.1)MEMORYtables. For engines that do not supportDELAYED, an error occurs.An error occurs for
INSERT DELAYEDif used with a table that has been locked withLOCK TABLESbecause the insert must be handled by a separate thread, not by the session that holds the lock.For
MyISAMtables, if there are no free blocks in the middle of the data file, concurrentSELECTandINSERTstatements are supported. Under these circumstances, you very seldom need to useINSERT DELAYEDwithMyISAM.INSERT DELAYEDshould be used only forINSERTstatements that specify value lists. This is enforced as of MySQL 4.0.18. The server ignoresDELAYEDforINSERT ... SELECTorINSERT ... ON DUPLICATE KEY UPDATEstatements.Because the
INSERT DELAYEDstatement returns immediately, before the rows are inserted, you cannot useLAST_INSERT_ID()to get theAUTO_INCREMENTvalue that the statement might generate.DELAYEDrows are not visible toSELECTstatements until they actually have been inserted.INSERT DELAYEDis treated as a normalINSERTif the statement inserts multiple rows and binary logging is enabled.DELAYEDis ignored on slave replication servers, so thatINSERT DELAYEDis treated as a normalINSERTon slaves. This is becauseDELAYEDcould cause the slave to have different data than the master.Pending
INSERT DELAYEDstatements are lost if a table is write locked andALTER TABLEis used to modify the table structure.
The following describes in detail what happens when you use the
DELAYED option to
INSERT or
REPLACE. In this description, the
“thread” is the thread that received an
INSERT DELAYED statement and
“handler” is the thread that handles all
INSERT DELAYED statements for a
particular table.
When a thread executes a
DELAYEDstatement for a table, a handler thread is created to process allDELAYEDstatements for the table, if no such handler already exists.The thread checks whether the handler has previously acquired a
DELAYEDlock; if not, it tells the handler thread to do so. TheDELAYEDlock can be obtained even if other threads have aREADorWRITElock on the table. However, the handler waits for allALTER TABLElocks orFLUSH TABLESstatements to finish, to ensure that the table structure is up to date.The thread executes the
INSERTstatement, but instead of writing the row to the table, it puts a copy of the final row into a queue that is managed by the handler thread. Any syntax errors are noticed by the thread and reported to the client program.The client cannot obtain from the server the number of duplicate rows or the
AUTO_INCREMENTvalue for the resulting row, because theINSERTreturns before the insert operation has been completed. (If you use the C API, themysql_info()function does not return anything meaningful, for the same reason.)The binary log is updated by the handler thread when the row is inserted into the table. In case of multiple-row inserts, the binary log is updated when the first row is inserted.
Each time that
delayed_insert_limitrows are written, the handler checks whether anySELECTstatements are still pending. If so, it allows these to execute before continuing.When the handler has no more rows in its queue, the table is unlocked. If no new
INSERT DELAYEDstatements are received withindelayed_insert_timeoutseconds, the handler terminates.If more than
delayed_queue_sizerows are pending in a specific handler queue, the thread requestingINSERT DELAYEDwaits until there is room in the queue. This is done to ensure that mysqld does not use all memory for the delayed memory queue.The handler thread shows up in the MySQL process list with
delayed_insertin theCommandcolumn. It is killed if you execute aFLUSH TABLESstatement or kill it withKILL. However, before exiting, it first stores all queued rows into the table. During this time it does not accept any newthread_idINSERTstatements from other threads. If you execute anINSERT DELAYEDstatement after this, a new handler thread is created.Note that this means that
INSERT DELAYEDstatements have higher priority than normalINSERTstatements if there is anINSERT DELAYEDhandler running. Other update statements have to wait until theINSERT DELAYEDqueue is empty, someone terminates the handler thread (withKILL), or someone executes athread_idFLUSH TABLES.The following status variables provide information about
INSERT DELAYEDstatements.Status Variable Meaning Delayed_insert_threadsNumber of handler threads Delayed_writesNumber of rows written with INSERT DELAYEDNot_flushed_delayed_rowsNumber of rows waiting to be written You can view these variables by issuing a
SHOW STATUSstatement or by executing a mysqladmin extended-status command.
If you specify ON DUPLICATE KEY UPDATE (added
in MySQL 4.1.0), and a row is inserted that would cause a
duplicate value in a UNIQUE index or
PRIMARY KEY, an
UPDATE of the old row is
performed. For example, if column a is
declared as UNIQUE and contains the value
1, the following two statements have
identical effect:
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;
With ON DUPLICATE KEY UPDATE, the
affected-rows value per row is 1 if the row is inserted as a new
row and 2 if an existing row is updated.
If column b is also unique, the
INSERT is equivalent to this
UPDATE statement instead:
UPDATE table SET c=c+1 WHERE a=1 OR b=2 LIMIT 1;
If a=1 OR b=2 matches several rows, only
one row is updated. In general, you should
try to avoid using an ON DUPLICATE KEY UPDATE
clause on tables with multiple unique indexes.
The ON DUPLICATE KEY UPDATE clause can
contain multiple column assignments, separated by commas.
As of MySQL 4.1.1, you can use the
VALUES(
function in the col_name)UPDATE clause to
refer to column values from the
INSERT portion of the
INSERT ...
ON DUPLICATE KEY UPDATE statement. In other words,
VALUES(
in the col_name)ON DUPLICATE KEY UPDATE clause refers
to the value of col_name that would
be inserted, had no duplicate-key conflict occurred. This
function is especially useful in multiple-row inserts. The
VALUES() function is meaningful
only in INSERT ... UPDATE statements and
returns NULL otherwise. Example:
INSERT INTO table (a,b,c) VALUES (1,2,3),(4,5,6) ON DUPLICATE KEY UPDATE c=VALUES(a)+VALUES(b);
That statement is identical to the following two statements:
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;
If a table contains an AUTO_INCREMENT column
and INSERT
... ON DUPLICATE KEY UPDATE inserts a row, the
LAST_INSERT_ID() function returns
the AUTO_INCREMENT value. If the statement
updates a row instead,
LAST_INSERT_ID() is not
meaningful. However, you can work around this by using
LAST_INSERT_ID(.
Suppose that expr)id is the
AUTO_INCREMENT column. To make
LAST_INSERT_ID() meaningful for
updates, insert rows as follows:
INSERT INTO table (a,b,c) VALUES (1,2,3) ON DUPLICATE KEY UPDATE id=LAST_INSERT_ID(id), c=3;
The DELAYED option is ignored when you use
ON DUPLICATE KEY UPDATE.
LOAD DATA [LOW_PRIORITY | CONCURRENT] [LOCAL] INFILE 'file_name' [REPLACE | IGNORE] INTO TABLEtbl_name[{FIELDS | COLUMNS} [TERMINATED BY 'string'] [[OPTIONALLY] ENCLOSED BY 'char'] [ESCAPED BY 'char'] ] [LINES [STARTING BY 'string'] [TERMINATED BY 'string'] ] [IGNOREnumberLINES] [(col_name,...)]
The LOAD DATA
INFILE statement reads rows from a text file into a
table at a very high speed. The file name must be given as a
literal string.
LOAD DATA
INFILE is the complement of
SELECT ... INTO
OUTFILE. (See Section 12.2.7, “SELECT Syntax”.) To write data
from a table to a file, use
SELECT ... INTO
OUTFILE. To read the file back into a table, use
LOAD DATA
INFILE. The syntax of the FIELDS and
LINES clauses is the same for both statements.
Both clauses are optional, but FIELDS must
precede LINES if both are specified.
For more information about the efficiency of
INSERT versus
LOAD DATA
INFILE and speeding up
LOAD DATA
INFILE, see Section 7.2.14, “Speed of INSERT Statements”.
As of MySQL 4.1, the character set indicated by the
character_set_database system
variable is used to interpret the information in the file.
SET NAMES and the setting of the
character_set_client system
variable do not affect interpretation of input.
LOAD DATA
INFILE interprets all fields in the file as having the
same character set, regardless of the data types of the columns
into which field values are loaded. For proper interpretation of
file contents, you must ensure that it was written with the
correct character set. For example, if you write a data file with
mysqldump -T or by issuing a
SELECT ... INTO
OUTFILE statement in mysql, be sure
to use a --default-character-set option with
mysqldump or mysql so that
output is written in the character set to be used when the file is
loaded with LOAD DATA
INFILE.
Note that it is currently not possible to load data files that use
the ucs2 character set.
You can also load data files by using the
mysqlimport utility; it operates by sending a
LOAD DATA
INFILE statement to the server. The
--local option causes
mysqlimport to read data files from the client
host. You can specify the
--compress option to get
better performance over slow networks if the client and server
support the compressed protocol. See
Section 4.5.5, “mysqlimport — A Data Import Program”.
If you use LOW_PRIORITY, execution of the
LOAD DATA statement is delayed
until no other clients are reading from the table. This affects
only storage engines that use only table-level locking
(MyISAM, MEMORY,
MERGE).
If you specify CONCURRENT with a
MyISAM table that satisfies the condition for
concurrent inserts (that is, it contains no free blocks in the
middle), other threads can retrieve data from the table while
LOAD DATA is executing. Using this
option affects the performance of LOAD
DATA a bit, even if no other thread is using the table
at the same time.
CONCURRENT is not replicated. See
Section 14.7, “Replication Features and Known Problems”, for more information.
The LOCAL keyword, if specified, is interpreted
with respect to the client end of the connection:
If
LOCALis specified, the file is read by the client program on the client host and sent to the server. The file can be given as a full path name to specify its exact location. If given as a relative path name, the name is interpreted relative to the directory in which the client program was started.LOCALis available in MySQL 3.22.6 or later.If
LOCALis not specified, the file must be located on the server host and is read directly by the server. The server uses the following rules to locate the file:If the file name is an absolute path name, the server uses it as given.
If the file name is a relative path name with one or more leading components, the server searches for the file relative to the server's data directory.
If a file name with no leading components is given, the server looks for the file in the database directory of the default database.
Note that, in the non-LOCAL case, these rules
mean that a file named as ./myfile.txt is
read from the server's data directory, whereas the file named as
myfile.txt is read from the database
directory of the default database. For example, if
db1 is the default database, the following
LOAD DATA statement reads the file
data.txt from the database directory for
db1, even though the statement explicitly loads
the file into a table in the db2 database:
LOAD DATA INFILE 'data.txt' INTO TABLE db2.my_table;
Windows path names are specified using forward slashes rather than backslashes. If you do use backslashes, you must double them.
For security reasons, when reading text files located on the
server, the files must either reside in the database directory or
be readable by all. Also, to use
LOAD DATA
INFILE on server files, you must have the
FILE privilege. See
Section 5.5.1, “Privileges Provided by MySQL”.
Using LOCAL is a bit slower than letting the
server access the files directly, because the contents of the file
must be sent over the connection by the client to the server. On
the other hand, you do not need the
FILE privilege to load local files.
With LOCAL, the default behavior is the same as
if IGNORE is specified; this is because the
server has no way to stop transmission of the file in the middle
of the operation. IGNORE is explained further
later in this section.
As of MySQL 3.23.49 and MySQL 4.0.2 (4.0.13 on Windows),
LOCAL works only if your server and your client
both have been enabled to allow it. For example, if
mysqld was started with
--local-infile=0,
LOCAL does not work. See
Section 5.4.4, “Security Issues with LOAD
DATA LOCAL”.
On Unix, if you need LOAD DATA to
read from a pipe, you can use the following technique (here we
load the listing of the / directory into a
table):
mkfifo /mysql/db/x/x chmod 666 /mysql/db/x/x find / -ls > /mysql/db/x/x & mysql -e "LOAD DATA INFILE 'x' INTO TABLE x" x
Note that you must run the command that generates the data to be loaded and the mysql commands either on separate terminals, or run the data generation process in the background (as shown in the preceding example). If you do not do this, the pipe will block until data is read by the mysql process.
If you are using a version of MySQL older than 3.23.25, you can
use this technique only with
LOAD DATA LOCAL
INFILE.
If you are using MySQL before version 3.23.24, you cannot read
from a FIFO with LOAD
DATA INFILE. If you need to read from a FIFO (for
example, the output from gunzip), use
LOAD DATA LOCAL
INFILE instead.
The REPLACE and
IGNORE keywords control handling of input rows
that duplicate existing rows on unique key values:
If you specify
REPLACE, input rows replace existing rows. In other words, rows that have the same value for a primary key or unique index as an existing row. See Section 12.2.6, “REPLACESyntax”.If you specify
IGNORE, input rows that duplicate an existing row on a unique key value are skipped. If you do not specify either option, the behavior depends on whether theLOCALkeyword is specified. WithoutLOCAL, an error occurs when a duplicate key value is found, and the rest of the text file is ignored. WithLOCAL, the default behavior is the same as ifIGNOREis specified; this is because the server has no way to stop transmission of the file in the middle of the operation.
If you want to ignore foreign key constraints during the load
operation, you can issue a SET foreign_key_checks =
0 statement before executing LOAD
DATA.
If you use LOAD DATA
INFILE on an empty MyISAM table, all
nonunique indexes are created in a separate batch (as for
REPAIR TABLE). Normally, this makes
LOAD DATA
INFILE much faster when you have many indexes. In some
extreme cases, you can create the indexes even faster by turning
them off with ALTER TABLE ... DISABLE KEYS
before loading the file into the table and using ALTER
TABLE ... ENABLE KEYS to re-create the indexes after
loading the file. See Section 7.2.14, “Speed of INSERT Statements”.
For both the LOAD DATA
INFILE and
SELECT ... INTO
OUTFILE statements, the syntax of the
FIELDS and LINES clauses is
the same. Both clauses are optional, but FIELDS
must precede LINES if both are specified.
If you specify a FIELDS clause, each of its
subclauses (TERMINATED BY,
[OPTIONALLY] ENCLOSED BY, and ESCAPED
BY) is also optional, except that you must specify at
least one of them.
If you specify no FIELDS clause, the defaults
are the same as if you had written this:
FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\'
If you specify no LINES clause, the defaults
are the same as if you had written this:
LINES TERMINATED BY '\n' STARTING BY ''
In other words, the defaults cause
LOAD DATA
INFILE to act as follows when reading input:
Look for line boundaries at newlines.
Do not skip over any line prefix.
Break lines into fields at tabs.
Do not expect fields to be enclosed within any quoting characters.
Interpret occurrences of tab, newline, or “
\” preceded by “\” as literal characters that are part of field values.
Conversely, the defaults cause
SELECT ... INTO
OUTFILE to act as follows when writing output:
Write tabs between fields.
Do not enclose fields within any quoting characters.
Use “
\” to escape instances of tab, newline, or “\” that occur within field values.Write newlines at the ends of lines.
Backslash is the MySQL escape character within strings, so to
write FIELDS ESCAPED BY '\\', you must specify
two backslashes for the value to be interpreted as a single
backslash.
Note
If you have generated the text file on a Windows system, you
might have to use LINES TERMINATED BY '\r\n'
to read the file properly, because Windows programs typically
use two characters as a line terminator. Some programs, such as
WordPad, might use \r as a
line terminator when writing files. To read such files, use
LINES TERMINATED BY '\r'.
If all the lines you want to read in have a common prefix that you
want to ignore, you can use LINES STARTING BY
' to skip over
the prefix, and anything before it. If a line
does not include the prefix, the entire line is skipped. Suppose
that you issue the following statement:
prefix_string'
LOAD DATA INFILE '/tmp/test.txt' INTO TABLE test FIELDS TERMINATED BY ',' LINES STARTING BY 'xxx';
If the data file looks like this:
xxx"abc",1 something xxx"def",2 "ghi",3
The resulting rows will be ("abc",1) and
("def",2). The third row in the file is skipped
because it does not contain the prefix.
The IGNORE option can be used to ignore lines at the start of
the file. For example, you can use number
LINESIGNORE 1
LINES to skip over an initial header line containing
column names:
LOAD DATA INFILE '/tmp/test.txt' INTO TABLE test IGNORE 1 LINES;
When you use SELECT ...
INTO OUTFILE in tandem with
LOAD DATA
INFILE to write data from a database into a file and
then read the file back into the database later, the field- and
line-handling options for both statements must match. Otherwise,
LOAD DATA
INFILE will not interpret the contents of the file
properly. Suppose that you use
SELECT ... INTO
OUTFILE to write a file with fields delimited by commas:
SELECT * INTO OUTFILE 'data.txt' FIELDS TERMINATED BY ',' FROM table2;
To read the comma-delimited file back in, the correct statement would be:
LOAD DATA INFILE 'data.txt' INTO TABLE table2 FIELDS TERMINATED BY ',';
If instead you tried to read in the file with the statement shown
following, it wouldn't work because it instructs
LOAD DATA
INFILE to look for tabs between fields:
LOAD DATA INFILE 'data.txt' INTO TABLE table2 FIELDS TERMINATED BY '\t';
The likely result is that each input line would be interpreted as a single field.
LOAD DATA
INFILE can be used to read files obtained from external
sources. For example, many programs can export data in
comma-separated values (CSV) format, such that lines have fields
separated by commas and enclosed within double quotes. If lines in
such a file are terminated by newlines, the statement shown here
illustrates the field- and line-handling options you would use to
load the file:
LOAD DATA INFILE 'data.txt' INTO TABLE tbl_name
FIELDS TERMINATED BY ',' ENCLOSED BY '"'
LINES TERMINATED BY '\n';
If the input values are not necessarily enclosed within quotes,
use OPTIONALLY before the ENCLOSED
BY keywords.
Any of the field- or line-handling options can specify an empty
string (''). If not empty, the FIELDS
[OPTIONALLY] ENCLOSED BY and FIELDS ESCAPED
BY values must be a single character. The
FIELDS TERMINATED BY, LINES STARTING
BY, and LINES TERMINATED BY values
can be more than one character. For example, to write lines that
are terminated by carriage return/linefeed pairs, or to read a
file containing such lines, specify a LINES TERMINATED BY
'\r\n' clause.
To read a file containing jokes that are separated by lines
consisting of %%, you can do this
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 controls
quoting of fields. For output
(SELECT ... INTO
OUTFILE), if you omit the word
OPTIONALLY, all fields are enclosed by the
ENCLOSED BY character. An example of such
output (using a comma as the field delimiter) is shown here:
"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"
If you specify OPTIONALLY, the
ENCLOSED BY character is used only to enclose
values from columns that have a string data type (such as
CHAR,
BINARY,
TEXT, or
ENUM):
1,"a string",100.20 2,"a string containing a , comma",102.20 3,"a string containing a \" quote",102.20 4,"a string containing a \", quote and comma",102.20
Note that occurrences of the ENCLOSED BY
character within a field value are escaped by prefixing them with
the ESCAPED BY character. Also note that if you
specify an empty ESCAPED BY value, it is
possible to inadvertently generate output that cannot be read
properly by LOAD DATA
INFILE. For example, the preceding output just shown
would appear as follows if the escape character is empty. Observe
that the second field in the fourth line contains a comma
following the quote, which (erroneously) appears to terminate the
field:
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
For input, the ENCLOSED BY character, if
present, is stripped from the ends of field values. (This is true
regardless of whether OPTIONALLY is specified;
OPTIONALLY has no effect on input
interpretation.) Occurrences of the ENCLOSED BY
character preceded by the ESCAPED BY character
are interpreted as part of the current field value.
If the field begins with the ENCLOSED BY
character, instances of that character are recognized as
terminating a field value only if followed by the field or line
TERMINATED BY sequence. To avoid ambiguity,
occurrences of the ENCLOSED BY character within
a field value can be doubled and are interpreted as a single
instance of the character. For example, if ENCLOSED BY
'"' is specified, quotes are handled as shown here:
"The ""BIG"" boss" -> The "BIG" boss The "BIG" boss -> The "BIG" boss The ""BIG"" boss -> The ""BIG"" boss
FIELDS ESCAPED BY controls how to write or read
special characters. If the FIELDS ESCAPED BY
character is not empty, it is used to prefix the following
characters on output:
The
FIELDS ESCAPED BYcharacterThe
FIELDS [OPTIONALLY] ENCLOSED BYcharacterThe first character of the
FIELDS TERMINATED BYandLINES TERMINATED BYvaluesASCII
0(what is actually written following the escape character is ASCII “0”, not a zero-valued byte)
If the FIELDS ESCAPED BY character is empty, no
characters are escaped and NULL is output as
NULL, not \N. It is probably
not a good idea to specify an empty escape character, particularly
if field values in your data contain any of the characters in the
list just given.
For input, if the FIELDS ESCAPED BY character
is not empty, occurrences of that character are stripped and the
following character is taken literally as part of a field value.
Some two-character sequences that are exceptions, where the first
character is the escape character. These sequences are shown in
the following table (using “\” for
the escape character). The rules for NULL
handling are described later in this section.
\0
| An ASCII NUL (0x00) character |
\b
| A backspace character |
\n
| A newline (linefeed) character |
\r
| A carriage return character |
\t
| A tab character. |
\Z
| ASCII 26 (Control-Z) |
\N
| NULL |
For more information about
“\”-escape syntax, see
Section 8.1, “Literal Values”.
In certain cases, field- and line-handling options interact:
If
LINES TERMINATED BYis an empty string andFIELDS TERMINATED BYis nonempty, lines are also terminated withFIELDS TERMINATED BY.If the
FIELDS TERMINATED BYandFIELDS ENCLOSED BYvalues are both empty (''), a fixed-row (nondelimited) format is used. With fixed-row format, no delimiters are used between fields (but you can still have a line terminator). Instead, column values are read and written using a field width wide enough to hold all values in the field. ForTINYINT,SMALLINT,MEDIUMINT,INT, andBIGINT, the field widths are 4, 6, 8, 11, and 20, respectively, no matter what the declared display width is.LINES TERMINATED BYis still used to separate lines. If a line does not contain all fields, the rest of the columns are set to their default values. If you do not have a line terminator, you should set this to''. In this case, the text file must contain all fields for each row.Fixed-row format also affects handling of
NULLvalues, as described later. Note that fixed-size format does not work if you are using a multi-byte character set.Note
Before MySQL 4.1.12, fixed-row format used the display width of the column. For example,
INT(4)was read or written using a field with a width of 4. However, if the column contained wider values, they were dumped to their full width, leading to the possibility of a “ragged” field holding values of different widths. Using a field wide enough to hold all values in the field prevents this problem. However, data files written before this change was made might not be reloaded correctly withLOAD DATA INFILEfor MySQL 4.1.12 and up. This change also affects data files read by mysqlimport and written by mysqldump --tab, which useLOAD DATA INFILEandSELECT ... INTO OUTFILE.
Handling of NULL values varies according to the
FIELDS and LINES options in
use:
For the default
FIELDSandLINESvalues,NULLis written as a field value of\Nfor output, and a field value of\Nis read asNULLfor input (assuming that theESCAPED BYcharacter is “\”).If
FIELDS ENCLOSED BYis not empty, a field containing the literal wordNULLas its value is read as aNULLvalue. This differs from the wordNULLenclosed withinFIELDS ENCLOSED BYcharacters, which is read as the string'NULL'.If
FIELDS ESCAPED BYis empty,NULLis written as the wordNULL.With fixed-row format (which is used when
FIELDS TERMINATED BYandFIELDS ENCLOSED BYare both empty),NULLis written as an empty string. Note that this causes bothNULLvalues and empty strings in the table to be indistinguishable when written to the file because both are written as empty strings. If you need to be able to tell the two apart when reading the file back in, you should not use fixed-row format.
An attempt to load NULL into a NOT
NULL column causes assignment of the implicit default
value for the column's data type and a warning. Implicit default
values are discussed in Section 10.1.4, “Data Type Default Values”.
Some cases are not supported by
LOAD DATA
INFILE:
Fixed-size rows (
FIELDS TERMINATED BYandFIELDS ENCLOSED BYboth empty) andBLOBorTEXTcolumns.If you specify one separator that is the same as or a prefix of another,
LOAD DATA INFILEcannot interpret the input properly. For example, the followingFIELDSclause would cause problems:FIELDS TERMINATED BY '"' ENCLOSED BY '"'
If
FIELDS ESCAPED BYis empty, a field value that contains an occurrence ofFIELDS ENCLOSED BYorLINES TERMINATED BYfollowed by theFIELDS TERMINATED BYvalue causesLOAD DATA INFILEto stop reading a field or line too early. This happens becauseLOAD DATA INFILEcannot properly determine where the field or line value ends.
The following example loads all columns of the
persondata table:
LOAD DATA INFILE 'persondata.txt' INTO TABLE persondata;
By default, when no column list is provided at the end of the
LOAD DATA
INFILE statement, input lines are expected to contain a
field for each table column. If you want to load only some of a
table's columns, specify a column list:
LOAD DATA INFILE 'persondata.txt' INTO TABLE persondata (col1,col2,...);
You must also specify a column list if the order of the fields in the input file differs from the order of the columns in the table. Otherwise, MySQL cannot tell how to match input fields with table columns.
If an input line has too many fields, the extra fields are ignored and the number of warnings is incremented.
If an input line has too few fields, the table columns for which input fields are missing are set to their default values. Default value assignment is described in Section 10.1.4, “Data Type Default Values”.
An empty field value is interpreted differently than if the field value is missing:
For string types, the column is set to the empty string.
For numeric types, the column is set to
0.For date and time types, the column is set to the appropriate “zero” value for the type. See Section 10.3, “Date and Time Types”.
These are the same values that result if you assign an empty
string explicitly to a string, numeric, or date or time type
explicitly in an INSERT or
UPDATE statement.
TIMESTAMP columns are set to the
current date and time only if there is a NULL
value for the column (that is, \N) and the
column is not declared to allow NULL values, or
if the TIMESTAMP column's default
value is the current timestamp and it is omitted from the field
list when a field list is specified.
LOAD DATA
INFILE regards all input as strings, so you cannot use
numeric values for ENUM or
SET columns the way you can with
INSERT statements. All
ENUM and
SET values must be specified as
strings.
When the LOAD DATA
INFILE statement finishes, it returns an information
string in the following format:
Records: 1 Deleted: 0 Skipped: 0 Warnings: 0
If you are using the C API, you can get information about the
statement by calling the
mysql_info() function. See
Section 17.7.3.33, “mysql_info()”.
Warnings occur under the same circumstances as when values are
inserted via the INSERT statement
(see Section 12.2.4, “INSERT Syntax”), except that
LOAD DATA
INFILE also generates warnings when there are too few or
too many fields in the input row. The warnings are not stored
anywhere; the number of warnings can be used only as an indication
of whether everything went well.
From MySQL 4.1.1 on, you can use SHOW
WARNINGS to get a list of the first
max_error_count warnings as
information about what went wrong. See
Section 12.5.5.26, “SHOW WARNINGS Syntax”.
Before MySQL 4.1.1, only a warning count is available to indicate
that something went wrong. If you get warnings and want to know
exactly why you got them, one way to do this is to dump the table
into another file using
SELECT ... INTO
OUTFILE and compare the file to your original input
file.
REPLACE [LOW_PRIORITY | DELAYED]
[INTO] tbl_name [(col_name,...)]
{VALUES | VALUE} ({expr | DEFAULT},...),(...),...
Or:
REPLACE [LOW_PRIORITY | DELAYED]
[INTO] tbl_name
SET col_name={expr | DEFAULT}, ...
Or:
REPLACE [LOW_PRIORITY | DELAYED]
[INTO] tbl_name [(col_name,...)]
SELECT ...
REPLACE works exactly like
INSERT, except that if an old row
in the table has the same value as a new row for a
PRIMARY KEY or a UNIQUE
index, the old row is deleted before the new row is inserted. See
Section 12.2.4, “INSERT Syntax”.
REPLACE is a MySQL extension to the
SQL standard. It either inserts, or deletes
and inserts. For another MySQL extension to standard SQL —
that either inserts or updates — see
Section 12.2.4.3, “INSERT ... ON
DUPLICATE KEY UPDATE Syntax”.
INSERT ... ON
DUPLICATE KEY UPDATE is available as of MySQL 4.1.0.
Note that unless the table has a PRIMARY KEY or
UNIQUE index, using a
REPLACE statement makes no sense.
It becomes equivalent to INSERT,
because there is no index to be used to determine whether a new
row duplicates another.
Values for all columns are taken from the values specified in the
REPLACE statement. Any missing
columns are set to their default values, just as happens for
INSERT. You cannot refer to values
from the current row and use them in the new row. If you use an
assignment such as SET
, the reference
to the column name on the right hand side is treated as
col_name =
col_name + 1DEFAULT(,
so the assignment is equivalent to col_name)SET
.
col_name =
DEFAULT(col_name) + 1
To use REPLACE, you must have both
the INSERT and
DELETE privileges for the table.
The REPLACE statement returns a
count to indicate the number of rows affected. This is the sum of
the rows deleted and inserted. If the count is 1 for a single-row
REPLACE, a row was inserted and no
rows were deleted. If the count is greater than 1, one or more old
rows were deleted before the new row was inserted. It is possible
for a single row to replace more than one old row if the table
contains multiple unique indexes and the new row duplicates values
for different old rows in different unique indexes.
The affected-rows count makes it easy to determine whether
REPLACE only added a row or whether
it also replaced any rows: Check whether the count is 1 (added) or
greater (replaced).
If you are using the C API, the affected-rows count can be
obtained using the
mysql_affected_rows() function.
Currently, you cannot replace into a table and select from the same table in a subquery.
MySQL uses the following algorithm for
REPLACE (and LOAD DATA ...
REPLACE):
Try to insert the new row into the table
While the insertion fails because a duplicate-key error occurs for a primary key or unique index:
Delete from the table the conflicting row that has the duplicate key value
Try again to insert the new row into the table
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
[WHERE where_condition]
[GROUP BY {col_name | expr | position}
[ASC | DESC], ... [WITH ROLLUP]]
[HAVING where_condition]
[ORDER BY {col_name | expr | position}
[ASC | DESC], ...]
[LIMIT {[offset,] row_count | row_count OFFSET offset}]
[PROCEDURE procedure_name(argument_list)]
[INTO OUTFILE 'file_name' export_options
| INTO DUMPFILE 'file_name'
| INTO @var_name [, @var_name]]
[FOR UPDATE | LOCK IN SHARE MODE]]
SELECT is used to retrieve rows
selected from one or more tables. Support for
UNION statements and subqueries is
available as of MySQL 4.0 and 4.1, respectively. See
Section 12.2.7.3, “UNION Syntax”, and Section 12.2.8, “Subquery Syntax”.
The most commonly used clauses of
SELECT statements are these:
Each
select_exprindicates a column that you want to retrieve. There must be at least oneselect_expr.table_referencesindicates the table or tables from which to retrieve rows. Its syntax is described in Section 12.2.7.1, “JOINSyntax”.The
WHEREclause, if given, indicates the condition or conditions that rows must satisfy to be selected.where_conditionis an expression that evaluates to true for each row to be selected. The statement selects all rows if there is noWHEREclause.In the
WHEREclause, you can use any of the functions and operators that MySQL supports, except for aggregate (summary) functions. See Chapter 11, Functions and Operators.
SELECT can also be used to retrieve
rows computed without reference to any table.
For example:
mysql> SELECT 1 + 1;
-> 2
From MySQL 4.1.0 on, you are allowed to specify
DUAL as a dummy table name in situations where
no tables are referenced:
mysql> SELECT 1 + 1 FROM DUAL;
-> 2
DUAL is purely for the convenience of people
who require that all SELECT
statements should have FROM and possibly other
clauses. MySQL may ignore the clauses. MySQL does not require
FROM DUAL if no tables are referenced.
In general, clauses used must be given in exactly the order shown
in the syntax description. For example, a
HAVING clause must come after any
GROUP BY clause and before any ORDER
BY clause. The exception is that the
INTO clause can appear either as shown in the
syntax description or immediately following the
select_expr list.
The list of select_expr terms comprises
the select list that indicates which columns to retrieve. Terms
specify a column or expression or can use
*-shorthand:
A select list consisting only of a single unqualified
*can be used as shorthand to select all columns from all tables:SELECT * FROM t1 INNER JOIN t2 ...
can be used as a qualified shorthand to select all columns from the named table:tbl_name.*SELECT t1.*, t2.* FROM t1 INNER JOIN t2 ...
Use of an unqualified
*with other items in the select list may produce a parse error. To avoid this problem, use a qualifiedreferencetbl_name.*SELECT AVG(score), t1.* FROM t1 ...
The following list provides additional information about other
SELECT clauses:
A
select_exprcan be given an alias usingAS. The alias is used as the expression's column name and can be used inalias_nameGROUP BY,ORDER BY, orHAVINGclauses. For example:SELECT CONCAT(last_name,', ',first_name) AS full_name FROM mytable ORDER BY full_name;
The
ASkeyword is optional when aliasing aselect_expr. The preceding example could have been written like this:SELECT CONCAT(last_name,', ',first_name) full_name FROM mytable ORDER BY full_name;
However, because the
ASis optional, a subtle problem can occur if you forget the comma between twoselect_exprexpressions: MySQL interprets the second as an alias name. For example, in the following statement,columnbis treated as an alias name:SELECT columna columnb FROM mytable;
For this reason, it is good practice to be in the habit of using
ASexplicitly when specifying column aliases.It is not allowable to refer to a column alias in a
WHEREclause, because the column value might not yet be determined when theWHEREclause is executed. See Section A.1.5.4, “Problems with Column Aliases”.The
FROMclause indicates the table or tables from which to retrieve rows. If you name more than one table, you are performing a join. For information on join syntax, see Section 12.2.7.1, “table_referencesJOINSyntax”. For each table specified, you can optionally specify an alias.tbl_name[[AS]alias] [index_hint)]The use of index hints provides the optimizer with information about how to choose indexes during query processing. For a description of the syntax for specifying these hints, see Section 12.2.7.2, “Index Hint Syntax”.
In MySQL 4.0.14, you can use
SET max_seeks_for_key=as an alternative way to force MySQL to prefer key scans instead of table scans. See Section 5.1.3, “Server System Variables”.valueYou can refer to a table within the default database as
tbl_name, or asdb_name.tbl_nameto specify a database explicitly. You can refer to a column ascol_name,tbl_name.col_name, ordb_name.tbl_name.col_name. You need not specify atbl_nameordb_name.tbl_nameprefix for a column reference unless the reference would be ambiguous. See Section 8.2.1, “Identifier Qualifiers”, for examples of ambiguity that require the more explicit column reference forms.A table reference can be aliased using
ortbl_nameASalias_nametbl_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;
Columns selected for output can be referred to in
ORDER BYandGROUP BYclauses using column names, column aliases, or column positions. Column positions are integers and begin with 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;
To sort in reverse order, add the
DESC(descending) keyword to the name of the column in theORDER BYclause that you are sorting by. The default is ascending order; this can be specified explicitly using theASCkeyword.If
ORDER BYoccurs within a subquery and also is applied in the outer query, the outermostORDER BYtakes precedence. For example, results for the following statement are sorted in descending order, not ascending order:(SELECT ... ORDER BY a) ORDER BY a DESC;
Use of column positions is deprecated because the syntax has been removed from the SQL standard.
If you use
GROUP BY, output rows are sorted according to theGROUP BYcolumns as if you had anORDER BYfor the same columns. To avoid the overhead of sorting thatGROUP BYproduces, addORDER BY NULL:SELECT a, COUNT(b) FROM test_table GROUP BY a ORDER BY NULL;
MySQL extends the
GROUP BYclause as of version 3.23.34 so that you can also specifyASCandDESCafter columns named in the clause:SELECT a, COUNT(b) FROM test_table GROUP BY a DESC;
MySQL extends the use of
GROUP BYto allow selecting fields that are not mentioned in theGROUP BYclause. If you are not getting the results that you expect from your query, please read the description ofGROUP BYfound in Section 11.11, “Functions and Modifiers for Use withGROUP BYClauses”.As of MySQL 4.1.1,
GROUP BYallows aWITH ROLLUPmodifier. See Section 11.11.2, “GROUP BYModifiers”.The
HAVINGclause is applied nearly last, just before items are sent to the client, with no optimization. (LIMITis applied afterHAVING.)A
HAVINGclause can refer to any column or alias named in aselect_exprin theSELECTlist or in outer subqueries, and to aggregate functions. (Standard SQL requires thatHAVINGmust reference only columns in theGROUP BYclause or columns used in aggregate functions.)Do not use
HAVINGfor items that should be in theWHEREclause. For example, do not write the following:SELECT
col_nameFROMtbl_nameHAVINGcol_name> 0;Write this instead:
SELECT
col_nameFROMtbl_nameWHEREcol_name> 0;The
HAVINGclause can refer to aggregate functions, which theWHEREclause cannot:SELECT user, MAX(salary) FROM users GROUP BY user HAVING MAX(salary) > 10;
However, that does not work in older MySQL servers (before version 3.22.5). In those versions, you can use a column alias in the select list and refer to the alias in the
HAVINGclause:SELECT user, MAX(salary) AS max_salary FROM users GROUP BY user HAVING max_salary>10;
MySQL allows duplicate column names. That is, there can be more than one
select_exprwith the same name. This is an extension to standard SQL. Because MySQL also allowsGROUP BYandHAVINGto refer toselect_exprvalues, this can result in an ambiguity:SELECT 12 AS a, a FROM t GROUP BY a;
In that statement, both columns have the name
a. To ensure that the correct column is used for grouping, use different names for eachselect_expr.When MySQL resolves an unqualified column or alias reference in an
ORDER BY,GROUP BY, orHAVINGclause, it first searches for the name in theselect_exprvalues. If the name is not found, it looks in the columns of the tables named in theFROMclause.The
LIMITclause can be used to constrain the number of rows returned by theSELECTstatement.LIMITtakes one or two numeric arguments, which must both be nonnegative integer constants (except when using prepared statements).With two arguments, the first argument specifies the offset of the first row to return, and the second specifies the maximum number of rows to return. The offset of the initial row is 0 (not 1):
SELECT * FROM tbl LIMIT 5,10; # Retrieve rows 6-15
To retrieve all rows from a certain offset up to the end of the result set, you can use some large number for the second parameter. This statement retrieves all rows from the 96th row to the last:
SELECT * FROM tbl LIMIT 95,18446744073709551615;
With one argument, the value specifies the number of rows to return from the beginning of the result set:
SELECT * FROM tbl LIMIT 5; # Retrieve first 5 rows
In other words,
LIMITis equivalent torow_countLIMIT 0,.row_countFor prepared statements, you can use placeholders (supported as of MySQL version 5.0.7). The following statements will return one row from the
tbltable:SET @a=1; PREPARE STMT FROM 'SELECT * FROM tbl LIMIT ?'; EXECUTE STMT USING @a;
The following statements will return the second to sixth row from the
tbltable:SET @skip=1; SET @numrows=5; PREPARE STMT FROM 'SELECT * FROM tbl LIMIT ?, ?'; EXECUTE STMT USING @skip, @numrows;
For compatibility with PostgreSQL, MySQL also supports the
LIMITsyntax.row_countOFFSEToffsetIf
LIMIToccurs within a subquery and also is applied in the outer query, the outermostLIMITtakes precedence. For example, the following statement produces two rows, not one:(SELECT ... LIMIT 1) LIMIT 2;
A
PROCEDUREclause names a procedure that should process the data in the result set. For an example, see Section 18.3.1, “PROCEDURE ANALYSE”.The
SELECT ... INTO OUTFILE 'form offile_name'SELECTwrites the selected rows to a file. The file is created on the server host, so you must have theFILEprivilege to use this syntax.file_namecannot be an existing file, which among other things prevents files such as/etc/passwdand database tables from being destroyed.The
SELECT ... INTO OUTFILEstatement is intended primarily to let you very quickly dump a table to a text file on the server machine. If you want to create the resulting file on some client host other than the server host, you cannot useSELECT ... INTO OUTFILE. In that case, you should instead use a command such asmysql -e "SELECT ..." >to generate the file on the client host.file_nameSELECT ... INTO OUTFILEis the complement ofLOAD DATA INFILE; the syntax for theexport_optionspart of the statement consists of the sameFIELDSandLINESclauses that are used with theLOAD DATA INFILEstatement. See Section 12.2.5, “LOAD DATA INFILESyntax”.Column values are dumped using the
binarycharacter set. In effect, there is no character set conversion. If a table contains columns in several character sets, the output data file will as well and you may not be able to reload the file correctly.FIELDS ESCAPED BYcontrols how to write special characters. If theFIELDS ESCAPED BYcharacter is not empty, it is used as a prefix that precedes following characters on output:The
FIELDS ESCAPED BYcharacterThe
FIELDS [OPTIONALLY] ENCLOSED BYcharacterThe first character of the
FIELDS TERMINATED BYandLINES TERMINATED BYvaluesASCII
NUL(the zero-valued byte; what is actually written following the escape character is ASCII “0”, not a zero-valued byte)
The
FIELDS TERMINATED BY,ENCLOSED BY,ESCAPED BY, orLINES TERMINATED BYcharacters must be escaped so that you can read the file back in reliably. ASCIINULis escaped to make it easier to view with some pagers.The resulting file does not have to conform to SQL syntax, so nothing else need be escaped.
If the
FIELDS ESCAPED BYcharacter is empty, no characters are escaped andNULLis output asNULL, not\N. It is probably not a good idea to specify an empty escape character, particularly if field values in your data contain any of the characters in the list just given.Here is an example that produces a file in the comma-separated values (CSV) format used by many programs:
SELECT a,b,a+b INTO OUTFILE '/tmp/result.txt' FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' LINES TERMINATED BY '\n' FROM test_table;
If you use
INTO DUMPFILEinstead ofINTO OUTFILE, MySQL writes only one row into the file, without any column or line termination and without performing any escape processing. This is useful if you want to store aBLOBvalue in a file.Note
Any file created by
INTO OUTFILEorINTO DUMPFILEis writable by all users on the server host. The reason for this is that the MySQL server cannot create a file that is owned by anyone other than the user under whose account it is running. (You should never run mysqld asrootfor this and other reasons.) The file thus must be world-writable so that you can manipulate its contents.As of MySQL 4.1, the
INTOclause can name a list of one or more user-defined variables. The selected values are assigned to the variables. The number of variables must match the number of columns. The query should return a single row. If the query returns no rows, error 1065 occurs (Query was empty). If the query returns multiple rows, error 1172 occurs (Result consisted of more than one row).The
SELECTsyntax description at the beginning this section shows theINTOclause near the end of the statement. It is also possible to useINTOimmediately following theselect_exprlist.An
INTOclause should not be used in a nestedSELECTbecause such aSELECTmust return its result to the outer context.If you use
FOR UPDATEwith a storage engine that uses page or row locks, rows examined by the query are write-locked until the end of the current transaction. UsingLOCK IN SHARE MODEsets a shared lock that allows other transactions to read the examined rows but not to update or delete them. See Section 13.2.9.3, “SELECT ... FOR UPDATEandSELECT ... LOCK IN SHARE MODELocking Reads”.
Following the SELECT keyword, you
can use a number of options that affect the operation of the
statement.
The ALL, DISTINCT, and
DISTINCTROW options specify whether duplicate
rows should be returned. If none of these options are given, the
default is ALL (all matching rows are
returned). DISTINCT and
DISTINCTROW are synonyms and specify removal of
duplicate rows from the result set.
HIGH_PRIORITY,
STRAIGHT_JOIN, and options beginning with
SQL_ are MySQL extensions to standard SQL.
HIGH_PRIORITYgives theSELECThigher priority than a statement that updates a table. You should use this only for queries that are very fast and must be done at once. ASELECT HIGH_PRIORITYquery that is issued while the table is locked for reading runs even if there is an update statement waiting for the table to be free. This affects only storage engines that use only table-level locking (MyISAM,MEMORY,MERGE).HIGH_PRIORITYcannot be used withSELECTstatements that are part of aUNION.STRAIGHT_JOINforces the optimizer to join the tables in the order in which they are listed in theFROMclause. You can use this to speed up a query if the optimizer joins the tables in nonoptimal order.STRAIGHT_JOINalso can be used in thetable_referenceslist. See Section 12.2.7.1, “JOINSyntax”.STRAIGHT_JOINdoes not apply to any table that the optimizer treats as aconstorsystemtable. Such a table produces a single row, is read during the optimization phase of query execution, and references to its columns are replaced with the appropriate column values before query execution proceeds. These tables will appear first in the query plan displayed byEXPLAIN. See Section 7.2.1, “Optimizing Queries withEXPLAIN”. This exception may not apply toconstorsystemtables that are used on theNULL-complemented side of an outer join (that is, the right-side table of aLEFT JOINor the left-side table of aRIGHT JOIN.SQL_BIG_RESULTcan be used withGROUP BYorDISTINCTto tell the optimizer that the result set has many rows. In this case, MySQL directly uses disk-based temporary tables if needed, and prefers sorting to using a temporary table with a key on theGROUP BYelements.SQL_BUFFER_RESULTforces the result to be put into a temporary table. This helps MySQL free the table locks early and helps in cases where it takes a long time to send the result set to the client. This option can be used only for top-levelSELECTstatements, not for subqueries or followingUNION.SQL_SMALL_RESULTcan be used withGROUP BYorDISTINCTto tell the optimizer that the result set is small. In this case, MySQL uses fast temporary tables to store the resulting table instead of using sorting. In MySQL 3.23 and up, this should not normally be needed.SQL_CALC_FOUND_ROWS(available in MySQL 4.0.0 and up) tells MySQL to calculate how many rows there would be in the result set, disregarding anyLIMITclause. The number of rows can then be retrieved withSELECT FOUND_ROWS(). See Section 11.10.3, “Information Functions”.Before MySQL 4.1.0, this option does not work with
LIMIT 0, which is optimized to return instantly (resulting in a row count of 0). See Section 7.2.12, “LIMITOptimization”.The
SQL_CACHEandSQL_NO_CACHEoptions affect caching of query results in the query cache (see Section 7.5.4, “The MySQL Query Cache”).SQL_CACHEtells MySQL to store the result in the query cache if it is cacheable and the value of thequery_cache_typesystem variable is2orDEMAND.SQL_NO_CACHEtells MySQL not to store the result in the query cache. For a query that usesUNIONor subqueries, the following rules apply:
MySQL supports the following JOIN syntaxes
for the table_references part of
SELECT statements and
multiple-table DELETE and
UPDATE statements:
table_references:table_reference,table_reference|table_reference[INNER | CROSS] JOINtable_reference[join_condition] |table_referenceSTRAIGHT_JOINtable_reference|table_reference{LEFT|RIGHT} [OUTER] JOINtable_referencejoin_condition|table_referenceNATURAL [{LEFT|RIGHT} [OUTER]] JOINtable_reference| { OJtable_referenceLEFT OUTER JOINtable_referenceONconditional_expr}table_reference:tbl_name[[AS]alias] [index_hint)] |table_subquery[AS]aliasjoin_condition: ONconditional_expr| USING (column_list)index_hint: USE {INDEX|KEY} (index_list)] | IGNORE {INDEX|KEY} (index_list)] | FORCE {INDEX|KEY} (index_list)]index_list:index_name[,index_name] ...
Index hints can be specified to affect how the MySQL optimizer makes use of indexes. For more information, see Section 12.2.7.2, “Index Hint Syntax”.
Note that several changes in join processing were made in MySQL
5.0.12 to make MySQL more compliant with standard SQL. These
changes include the ability to handle nested joins (including
outer joins) according to the standard. If a nested join returns
results that are not what you expect, please consider upgrading
to MySQL 5.0. Further details about the changes in join
processing can be found at JOIN Syntax.
You should generally not have any conditions in the
ON part that are used to restrict which rows
you want in the result set, but rather specify these conditions
in the WHERE clause. There are exceptions to
this rule.
Note that INNER JOIN syntax allows a
join_condition only from MySQL 3.23.17 on.
The same is true for JOIN and CROSS
JOIN only as of MySQL 4.0.11.
A table reference can be aliased using
ortbl_nameASalias_nametbl_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;
A
table_subqueryis also known as a subquery in theFROMclause. Such subqueries must include an alias to give the subquery result a table name. A trivial example follows; see also Section 12.2.8.8, “Subqueries in theFROMclause”.SELECT * FROM (SELECT 1, 2, 3) AS t1;
The
conditional_exprused withONis any conditional expression of the form that can be used in aWHEREclause.If there is no matching row for the right table in the
ONorUSINGpart in aLEFT JOIN, a row with all columns set toNULLis used for the right table. You can use this fact to find rows in a table that have no counterpart in another table:SELECT left_tbl.* FROM left_tbl LEFT JOIN right_tbl ON left_tbl.id = right_tbl.id WHERE right_tbl.id IS NULL;
This example finds all rows in
left_tblwith anidvalue that is not present inright_tbl(that is, all rows inleft_tblwith no corresponding row inright_tbl). This assumes thatright_tbl.idis declaredNOT NULL. See Section 7.2.7, “LEFT JOINandRIGHT JOINOptimization”.The
USING(clause names a list of columns that must exist in both tables. The following two clauses are semantically identical:column_list)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
The
NATURAL [LEFT] JOINof two tables is defined to be semantically equivalent to anINNER JOINor aLEFT JOINwith aUSINGclause that names all columns that exist in both tables.INNER JOINand,(comma) are semantically equivalent in the absence of a join condition: both produce a Cartesian product between the specified tables (that is, each and every row in the first table is joined to each and every row in the second table).RIGHT JOINworks analogously toLEFT JOIN. To keep code portable across databases, it is recommended that you useLEFT JOINinstead ofRIGHT JOIN.The
{ OJ ... LEFT OUTER JOIN ...}syntax shown in the preceding list exists only for compatibility with ODBC. The curly braces in the syntax should be written literally; they are not metasyntax as used elsewhere in syntax descriptions.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;STRAIGHT_JOINis similar toJOIN, except that the left table is always read before the right table. This can be used for those (few) cases for which the join optimizer puts the tables in the wrong order.
Some join examples:
SELECT * FROM table1,table2 WHERE table1.id=table2.id; SELECT * FROM table1 LEFT JOIN table2 ON table1.id=table2.id; SELECT * FROM table1 LEFT JOIN table2 USING (id); SELECT * FROM table1 LEFT JOIN table2 ON table1.id=table2.id LEFT JOIN table3 ON table2.id=table3.id;
As of MySQL 3.23.12, you can provide hints to give the optimizer
information about how to choose indexes during query processing.
Section 12.2.7.1, “JOIN Syntax”, describes the general syntax for
specifying tables in a SELECT
statement. The syntax for an individual table, including that
for index hints, looks like this:
tbl_name[[AS]alias] [index_hint)]index_hint: USE {INDEX|KEY} (index_list)] | IGNORE {INDEX|KEY} (index_list)] | FORCE {INDEX|KEY} (index_list)]index_list:index_name[,index_name] ...
By specifying USE INDEX
(, you can tell
MySQL to use only one of the named indexes to find rows in the
table. The alternative syntax index_list)IGNORE INDEX
( can be used to
tell MySQL to not use some particular index or indexes. These
hints are useful if index_list)EXPLAIN shows
that MySQL is using the wrong index from the list of possible
indexes.
From MySQL 4.0.9 on, you can also use FORCE
INDEX, which acts like USE INDEX
( but with the
addition that a table scan is assumed to be
very expensive. In other words, a table
scan is used only if there is no way to use one of the given
indexes to find rows in the table.
index_list)
Each hint requires the names of indexes,
not the names of columns. The name of a PRIMARY
KEY is PRIMARY. To see the index
names for a table, use SHOW
INDEX.
An index_name value need not be a
full index name. It can be an unambiguous prefix of an index
name. If a prefix is ambiguous, an error occurs.
Index hints do not work for FULLTEXT indexes.
USE INDEX, IGNORE INDEX,
and FORCE INDEX affect only which indexes are
used when MySQL decides how to find rows in the table and how to
do the join. They do not affect whether an index is used when
resolving an ORDER BY or GROUP
BY clause.
Examples:
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;
Index hints are accepted but ignored for
UPDATE statements.
SELECT ... UNION [ALL | DISTINCT] SELECT ... [UNION [ALL | DISTINCT] SELECT ...]
UNION is used to combine the
result from multiple SELECT
statements into a single result set.
UNION is available from MySQL
4.0.0 on.
The column names from the first
SELECT statement are used as the
column names for the results returned. Selected columns listed
in corresponding positions of each
SELECT statement should have the
same data type. (For example, the first column selected by the
first statement should have the same type as the first column
selected by the other statements.)
As of MySQL 4.1.1, if the data types of corresponding
SELECT columns do not match, the
types and lengths of the columns in the
UNION result take into account
the values retrieved by all of the
SELECT statements. For example,
consider the following:
mysql> SELECT REPEAT('a',1) UNION SELECT REPEAT('b',10);
+---------------+
| REPEAT('a',1) |
+---------------+
| a |
| bbbbbbbbbb |
+---------------+
Before MySQL 4.1.1, only the type and length from the first
SELECT would have been used and
the second row would have been truncated to a length of 1:
mysql> SELECT REPEAT('a',1) UNION SELECT REPEAT('b',10);
+---------------+
| REPEAT('a',1) |
+---------------+
| a |
| b |
+---------------+
The SELECT statements are normal
select statements, but with the following restrictions:
Only the last
SELECTstatement can useINTO OUTFILE. (However, the entireUNIONresult is written to the file.)HIGH_PRIORITYcannot be used withSELECTstatements that are part of aUNION. If you specify it for the firstSELECT, it has no effect. If you specify it for any subsequentSELECTstatements, a syntax error results.
The default behavior for UNION is
that duplicate rows are removed from the result. The optional
DISTINCT keyword (introduced in MySQL 4.0.17)
has no effect other than the default because it also specifies
duplicate-row removal. With the optional ALL
keyword, duplicate-row removal does not occur and the result
includes all matching rows from all the
SELECT statements.
Before MySQL 4.1.2, you cannot mix
UNION ALL and
UNION DISTINCT
in the same query. If you use ALL for one
UNION, it is used for all of
them. As of MySQL 4.1.2, mixed
UNION types are treated such that
a DISTINCT union overrides any
ALL union to its left. A
DISTINCT union can be produced explicitly by
using UNION
DISTINCT or implicitly by using
UNION with no following
DISTINCT or ALL keyword.
To use an ORDER BY or
LIMIT clause to sort or limit the entire
UNION result, parenthesize the
individual SELECT statements and
place the ORDER BY or
LIMIT after the last one. The following
example uses both clauses:
(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;
This kind of ORDER BY cannot use column
references that include a table name (that is, names in
tbl_name.col_name
format). Instead, provide a column alias in the first
SELECT statement and refer to the
alias in the ORDER BY. (Alternatively, refer
to the column in the ORDER BY using its
column position. However, use of column positions is
deprecated.)
Also, if a column to be sorted is aliased, the ORDER
BY clause must refer to the
alias, not the column name. The first of the following
statements will work, but the second will fail with an
Unknown column 'a' in 'order clause' error:
(SELECT a AS b FROM t) UNION (SELECT ...) ORDER BY b; (SELECT a AS b FROM t) UNION (SELECT ...) ORDER BY a;
To apply ORDER BY or LIMIT
to an individual SELECT, place
the clause inside the parentheses that enclose the
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);
However, use of ORDER BY for individual
SELECT statements implies nothing
about the order in which the rows appear in the final result
because UNION by default produces
an unordered set of rows. Therefore, the use of ORDER
BY in this context is typically in conjunction with
LIMIT, so that it is used to determine the
subset of the selected rows to retrieve for the
SELECT, even though it does not
necessarily affect the order of those rows in the final
UNION result. If ORDER
BY appears without LIMIT in a
SELECT, it is optimized away
because it will have no effect anyway.
To cause rows in a UNION result
to consist of the sets of rows retrieved by each
SELECT one after the other,
select an additional column in each
SELECT to use as a sort column
and add an ORDER BY following the last
SELECT:
(SELECT 1 AS sort_col, col1a, col1b, ... FROM t1) UNION (SELECT 2, col2a, col2b, ... FROM t2) ORDER BY sort_col;
To additionally maintain sort order within individual
SELECT results, add a secondary
column to the ORDER BY clause:
(SELECT 1 AS sort_col, col1a, col1b, ... FROM t1) UNION (SELECT 2, col2a, col2b, ... FROM t2) ORDER BY sort_col, col1a;
Use of an additional column also enables you to determine which
SELECT each row comes from. Extra
columns can provide other identifying information as well, such
as a string that indicates a table name.
- 12.2.8.1. The Subquery as Scalar Operand
- 12.2.8.2. Comparisons Using Subqueries
- 12.2.8.3. Subqueries with
ANY,IN, andSOME - 12.2.8.4. Subqueries with
ALL - 12.2.8.5. Row Subqueries
- 12.2.8.6.
EXISTSandNOT EXISTS - 12.2.8.7. Correlated Subqueries
- 12.2.8.8. Subqueries in the
FROMclause - 12.2.8.9. Subquery Errors
- 12.2.8.10. Optimizing Subqueries
- 12.2.8.11. Rewriting Subqueries as Joins for Earlier MySQL Versions
A subquery is a SELECT statement
within another statement.
Starting with MySQL 4.1, all subquery forms and operations that the SQL standard requires are supported, as well as a few features that are MySQL-specific.
With MySQL versions prior to 4.1, it was necessary to work around or avoid the use of subqueries. In many cases, subqueries can successfully be rewritten using joins and other methods. See Section 12.2.8.11, “Rewriting Subqueries as Joins for Earlier MySQL Versions”.
Here is an example of a subquery:
SELECT * FROM t1 WHERE column1 = (SELECT column1 FROM t2);
In this example, SELECT * FROM t1 ... is the
outer query (or outer
statement), and (SELECT column1 FROM
t2) is the subquery. We say that
the subquery is nested within the outer
query, and in fact it is possible to nest subqueries within other
subqueries, to a considerable depth. A subquery must always appear
within parentheses.
The main advantages of subqueries are:
They allow queries that are structured so that it is possible to isolate each part of a statement.
They provide alternative ways to perform operations that would otherwise require complex joins and unions.
They are, in many people's opinion, more readable than complex joins or unions. Indeed, it was the innovation of subqueries that gave people the original idea of calling the early SQL “Structured Query Language.”
Here is an example statement that shows the major points about subquery syntax as specified by the SQL standard and supported in MySQL:
DELETE FROM t1
WHERE s11 > ANY
(SELECT COUNT(*) /* no hint */ FROM t2
WHERE NOT EXISTS
(SELECT * FROM t3
WHERE ROW(5*t2.s1,77)=
(SELECT 50,11*s1 FROM t4 UNION SELECT 50,77 FROM
(SELECT * FROM t5) AS t5)));
A subquery can return a scalar (a single value), a single row, a single column, or a table (one or more rows of one or more columns). These are called scalar, column, row, and table subqueries. Subqueries that return a particular kind of result often can be used only in certain contexts, as described in the following sections.
There are few restrictions on the type of statements in which
subqueries can be used. A subquery can contain any of the keywords
or clauses that an ordinary SELECT
can contain: DISTINCT, GROUP
BY, ORDER BY,
LIMIT, joins, index hints,
UNION constructs, comments,
functions, and so on.
One restriction is that a subquery's outer statement must be one
of: SELECT,
INSERT,
UPDATE,
DELETE,
SET, or
DO. Another restriction is that
currently you cannot modify a table and select from the same table
in a subquery. This applies to statements such as
DELETE,
INSERT,
REPLACE, and
UPDATE.
A more comprehensive discussion of restrictions on subquery use, including performance issues for certain forms of subquery syntax, is given in Section C.1, “Restrictions on Subqueries”.
In its simplest form, a subquery is a scalar subquery that
returns a single value. A scalar subquery is a simple operand,
and you can use it almost anywhere a single column value or
literal is legal, and you can expect it to have those
characteristics that all operands have: a data type, a length,
an indication whether it can be NULL, and so
on. For example:
CREATE TABLE t1 (s1 INT, s2 CHAR(5) NOT NULL); INSERT INTO t1 VALUES(100, 'abcde'); SELECT (SELECT s2 FROM t1);
The subquery in this SELECT
returns a single value ('abcde') that has a
data type of CHAR, a length of 5,
a character set and collation equal to the defaults in effect at
CREATE TABLE time, and an
indication that the value in the column can be
NULL. In fact, almost all subqueries can be
NULL. If the table used in the example were
empty, the value of the subquery would be
NULL.
There are a few contexts in which a scalar subquery cannot be
used. If a statement allows only a literal value, you cannot use
a subquery. For example, LIMIT requires
literal integer arguments, and
LOAD DATA
INFILE requires a literal string file name. You cannot
use subqueries to supply these values.
When you see examples in the following sections that contain the
rather spartan construct (SELECT column1 FROM
t1), imagine that your own code contains much more
diverse and complex constructions.
Suppose that we make two tables:
CREATE TABLE t1 (s1 INT); INSERT INTO t1 VALUES (1); CREATE TABLE t2 (s1 INT); INSERT INTO t2 VALUES (2);
Then perform a SELECT:
SELECT (SELECT s1 FROM t2) FROM t1;
The result is 2 because there is a row in
t2 containing a column s1
that has a value of 2.
A scalar subquery can be part of an expression, but remember the parentheses, even if the subquery is an operand that provides an argument for a function. For example:
SELECT UPPER((SELECT s1 FROM t1)) FROM t2;
The most common use of a subquery is in the form:
non_subquery_operandcomparison_operator(subquery)
Where comparison_operator is one of
these operators:
= > < >= <= <> != <=>
For example:
... 'a' = (SELECT column1 FROM t1)
At one time the only legal place for a subquery was on the right side of a comparison, and you might still find some old DBMSs that insist on this.
Here is an example of a common-form subquery comparison that you
cannot do with a join. It finds all the rows in table
t1 for which the column1
value is equal to a maximum value in table
t2:
SELECT * FROM t1 WHERE column1 = (SELECT MAX(column2) FROM t2);
Here is another example, which again is impossible with a join
because it involves aggregating for one of the tables. It finds
all rows in table t1 containing a value that
occurs twice in a given column:
SELECT * FROM t1 AS t WHERE 2 = (SELECT COUNT(*) FROM t1 WHERE t1.id = t.id);
For a comparison of the subquery to a scalar, the subquery must return a scalar. For a comparison of the subquery to a row constructor, the subquery must be a row subquery that returns a row with the same number of values as the row constructor. See Section 12.2.8.5, “Row Subqueries”.
Syntax:
operandcomparison_operatorANY (subquery)operandIN (subquery)operandcomparison_operatorSOME (subquery)
The ANY keyword, which must follow a
comparison operator, means “return TRUE
if the comparison is TRUE for
ANY of the values in the column that the
subquery returns.” For example:
SELECT s1 FROM t1 WHERE s1 > ANY (SELECT s1 FROM t2);
Suppose that there is a row in table t1
containing (10). The expression is
TRUE if table t2 contains
(21,14,7) because there is a value
7 in t2 that is less than
10. The expression is
FALSE if table t2 contains
(20,10), or if table t2 is
empty. The expression is unknown if table
t2 contains
(NULL,NULL,NULL).
When used with a subquery, the word IN is an
alias for = ANY. Thus, these two statements
are the same:
SELECT s1 FROM t1 WHERE s1 = ANY (SELECT s1 FROM t2); SELECT s1 FROM t1 WHERE s1 IN (SELECT s1 FROM t2);
IN and = ANY are not
synonyms when used with an expression list.
IN can take an expression list, but
= ANY cannot. See
Section 11.2.3, “Comparison Functions and Operators”.
NOT IN is not an alias for <>
ANY, but for <> ALL. See
Section 12.2.8.4, “Subqueries with ALL”.
The word SOME is an alias for
ANY. Thus, these two statements are the same:
SELECT s1 FROM t1 WHERE s1 <> ANY (SELECT s1 FROM t2); SELECT s1 FROM t1 WHERE s1 <> SOME (SELECT s1 FROM t2);
Use of the word SOME is rare, but this
example shows why it might be useful. To most people's ears, the
English phrase “a is not equal to any b” means
“there is no b which is equal to a,” but that is
not what is meant by the SQL syntax. The syntax means
“there is some b to which a is not equal.” Using
<> SOME instead helps ensure that
everyone understands the true meaning of the query.
Syntax:
operandcomparison_operatorALL (subquery)
The word ALL, which must follow a comparison
operator, means “return TRUE if the
comparison is TRUE for ALL
of the values in the column that the subquery returns.”
For example:
SELECT s1 FROM t1 WHERE s1 > ALL (SELECT s1 FROM t2);
Suppose that there is a row in table t1
containing (10). The expression is
TRUE if table t2 contains
(-5,0,+5) because 10 is
greater than all three values in t2. The
expression is FALSE if table
t2 contains
(12,6,NULL,-100) because there is a single
value 12 in table t2 that
is greater than 10. The expression is
unknown (that is, NULL)
if table t2 contains
(0,NULL,1).
Finally, if table t2 is empty, the result is
TRUE. So, the following statement is
TRUE when table t2 is
empty:
SELECT * FROM t1 WHERE 1 > ALL (SELECT s1 FROM t2);
But this statement is NULL when table
t2 is empty:
SELECT * FROM t1 WHERE 1 > (SELECT s1 FROM t2);
In addition, the following statement is NULL
when table t2 is empty:
SELECT * FROM t1 WHERE 1 > ALL (SELECT MAX(s1) FROM t2);
In general, tables containing NULL
values and empty tables are
“edge cases.” When writing subquery code, always
consider whether you have taken those two possibilities into
account.
NOT IN is an alias for <>
ALL. Thus, these two statements are the same:
SELECT s1 FROM t1 WHERE s1 <> ALL (SELECT s1 FROM t2); SELECT s1 FROM t1 WHERE s1 NOT IN (SELECT s1 FROM t2);
The discussion to this point has been of scalar or column subqueries; that is, subqueries that return a single value or a column of values. A row subquery is a subquery variant that returns a single row and can thus return more than one column value. Legal operators for row subquery comparisons are:
= > < >= <= <> != <=>
Here are two examples:
SELECT * FROM t1 WHERE (1,2) = (SELECT column1, column2 FROM t2); SELECT * FROM t1 WHERE ROW(1,2) = (SELECT column1, column2 FROM t2);
The queries here are both TRUE if table
t2 has a row where column1 =
1 and column2 = 2.
The expressions (1,2) and
ROW(1,2) are sometimes called row
constructors. The two are equivalent. The row
constructor and the row returned by the subquery must contain
the same number of values.
Row constructors are legal in other contexts as well. For example, the following two statements are semantically equivalent (although in MySQL 4.1 only the second one can be optimized):
SELECT * FROM t1 WHERE (column1,column2) = (1,1); SELECT * FROM t1 WHERE column1 = 1 AND column2 = 1;
The normal use of row constructors is for comparisons with
subqueries that return two or more columns. For example, the
following query answers the request, “find all rows in
table t1 that also exist in table
t2”:
SELECT column1,column2,column3
FROM t1
WHERE (column1,column2,column3) IN
(SELECT column1,column2,column3 FROM t2);
If a subquery returns any rows at all, EXISTS
is
subqueryTRUE, and NOT EXISTS
is
subqueryFALSE. For example:
SELECT column1 FROM t1 WHERE EXISTS (SELECT * FROM t2);
Traditionally, an EXISTS subquery starts with
SELECT *, but it could begin with
SELECT 5 or SELECT column1
or anything at all. MySQL ignores the
SELECT list in such a subquery,
so it makes no difference.
For the preceding example, if t2 contains any
rows, even rows with nothing but NULL values,
the EXISTS condition is
TRUE. This is actually an unlikely example
because a [NOT] EXISTS subquery almost always
contains correlations. Here are some more realistic examples:
What kind of store is present in one or more cities?
SELECT DISTINCT store_type FROM stores WHERE EXISTS (SELECT * FROM cities_stores WHERE cities_stores.store_type = stores.store_type);What kind of store is present in no cities?
SELECT DISTINCT store_type FROM stores WHERE NOT EXISTS (SELECT * FROM cities_stores WHERE cities_stores.store_type = stores.store_type);What kind of store is present in all cities?
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));
The last example is a double-nested NOT
EXISTS query. That is, it has a NOT
EXISTS clause within a NOT EXISTS
clause. Formally, it answers the question “does a city
exist with a store that is not in
Stores”? But it is easier to say that
a nested NOT EXISTS answers the question
“is x TRUE
for all y?”
A correlated subquery is a subquery that contains a reference to a table that also appears in the outer query. For example:
SELECT * FROM t1 WHERE column1 = ANY
(SELECT column1 FROM t2 WHERE t2.column2 = t1.column2);
Notice that the subquery contains a reference to a column of
t1, even though the subquery's
FROM clause does not mention a table
t1. So, MySQL looks outside the subquery, and
finds t1 in the outer query.
Suppose that table t1 contains a row where
column1 = 5 and column2 =
6; meanwhile, table t2 contains a
row where column1 = 5 and column2 =
7. The simple expression ... WHERE column1 =
ANY (SELECT column1 FROM t2) would be
TRUE, but in this example, the
WHERE clause within the subquery is
FALSE (because (5,6) is
not equal to (5,7)), so the subquery as a
whole is FALSE.
Scoping rule: MySQL evaluates from inside to outside. For example:
SELECT column1 FROM t1 AS x
WHERE x.column1 = (SELECT column1 FROM t2 AS x
WHERE x.column1 = (SELECT column1 FROM t3
WHERE x.column2 = t3.column1));
In this statement, x.column2 must be a column
in table t2 because SELECT column1
FROM t2 AS x ... renames t2. It is
not a column in table t1 because
SELECT column1 FROM t1 ... is an outer query
that is farther out.
For subqueries in HAVING or ORDER
BY clauses, MySQL also looks for column names in the
outer select list.
For certain cases, a correlated subquery is optimized. For example:
valIN (SELECTkey_valFROMtbl_nameWHEREcorrelated_condition)
Otherwise, they are inefficient and likely to be slow. Rewriting the query as a join might improve performance.
Aggregate functions in correlated subqueries may contain outer references, provided the function contains nothing but outer references, and provided the function is not contained in another function or expression.
Subqueries are legal in a SELECT
statement's FROM clause. The actual syntax
is:
SELECT ... FROM (subquery) [AS]name...
The [AS]
clause is mandatory, because every table in a
nameFROM clause must have a name. Any columns in
the subquery select list must have
unique names.
For the sake of illustration, assume that you have this table:
CREATE TABLE t1 (s1 INT, s2 CHAR(5), s3 FLOAT);
Here is how to use a subquery in the FROM
clause, using the example table:
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;
Result: 2, '2', 4.0.
Here is another example: Suppose that you want to know the average of a set of sums for a grouped table. This does not work:
SELECT AVG(SUM(column1)) FROM t1 GROUP BY column1;
However, this query provides the desired information:
SELECT AVG(sum_column1)
FROM (SELECT SUM(column1) AS sum_column1
FROM t1 GROUP BY column1) AS t1;
Notice that the column name used within the subquery
(sum_column1) is recognized in the outer
query.
Subqueries in the FROM clause can return a
scalar, column, row, or table. Subqueries in the
FROM clause cannot be correlated subqueries.
Subqueries in the FROM clause are executed
even for the EXPLAIN statement
(that is, derived temporary tables are built). This occurs
because upper-level queries need information about all tables
during the optimization phase, and the table represented by a
subquery in the FROM clause is unavailable
unless the subquery is executed.
It is possible under certain circumstances to modify table data
using EXPLAIN
SELECT. This can occur if the outer query accesses any
tables and an inner query invokes a stored function that changes
one or more rows of a table. For example, suppose there are two
tables t1 and t2 in
database d1, created as shown here:
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)
Now we create a stored function f1 which
modifies t2:
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 ;
Referencing the function directly in an
EXPLAIN
SELECT does not have any effect on
t2, as shown here:
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)
This is because the SELECT
statement did not reference any tables, as can be seen in the
table and Extra columns of
the output. This is also true of the following nested
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)
However, if the outer SELECT
references any tables, then the optimizer executes the statement
in the subquery as well:
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)
This also means that an
EXPLAIN
SELECT statement such as the one shown here may take a
long time to execute:
EXPLAIN SELECT * FROM t1 AS a1, (SELECT BENCHMARK(1000000, MD5(NOW())));
This is because the BENCHMARK()
function is executed once for each row in t1.
There are some errors that apply only to subqueries. This section describes them.
Unsupported subquery syntax:
ERROR 1235 (ER_NOT_SUPPORTED_YET) SQLSTATE = 42000 Message = "This version of MySQL does not yet support 'LIMIT & IN/ALL/ANY/SOME subquery'"
This means that statements of the following form do not work yet:
SELECT * FROM t1 WHERE s1 IN (SELECT s2 FROM t2 ORDER BY s1 LIMIT 1)
Incorrect number of columns from subquery:
ERROR 1241 (ER_OPERAND_COL) SQLSTATE = 21000 Message = "Operand should contain 1 column(s)"
This error occurs in cases like this:
SELECT (SELECT column1, column2 FROM t2) FROM t1;
You may use a subquery that returns multiple columns, if the purpose is comparison. In other contexts, the subquery must be a scalar operand. See Section 12.2.8.5, “Row Subqueries”.
Incorrect number of rows from subquery:
ERROR 1242 (ER_SUBSELECT_NO_1_ROW) SQLSTATE = 21000 Message = "Subquery returns more than 1 row"
This error occurs for statements where the subquery returns more than one row. Consider the following example:
SELECT * FROM t1 WHERE column1 = (SELECT column1 FROM t2);
If
SELECT column1 FROM t2returns just one row, the previous query will work. If the subquery returns more than one row, error 1242 will occur. In that case, the query should be rewritten as:SELECT * FROM t1 WHERE column1 = ANY (SELECT column1 FROM t2);
Incorrectly used table in subquery:
Error 1093 (ER_UPDATE_TABLE_USED) SQLSTATE = HY000 Message = "You can't specify target table 'x' for update in FROM clause"
This error occurs in cases such as the following:
UPDATE t1 SET column2 = (SELECT MAX(column1) FROM t1);
You can use a subquery for assignment within an
UPDATEstatement because subqueries are legal inUPDATEandDELETEstatements as well as inSELECTstatements. However, you cannot use the same table (in this case, tablet1) for both the subquery'sFROMclause and the update target.
For transactional storage engines, the failure of a subquery causes the entire statement to fail. For nontransactional storage engines, data modifications made before the error was encountered are preserved.
Development is ongoing, so no optimization tip is reliable for the long term. The following list provides some interesting tricks that you might want to play with:
Use subquery clauses that affect the number or order of the rows in the subquery. For example:
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);
Replace a join with a subquery. For example, try this:
SELECT DISTINCT column1 FROM t1 WHERE t1.column1 IN ( SELECT column1 FROM t2);
Instead of this:
SELECT DISTINCT t1.column1 FROM t1, t2 WHERE t1.column1 = t2.column1;
Some subqueries can be transformed to joins for compatibility with older versions of MySQL before 4.1 that do not support subqueries. However, in some cases, converting a subquery to a join may also improve performance. See Section 12.2.8.11, “Rewriting Subqueries as Joins for Earlier MySQL Versions”.
Move clauses from outside to inside the subquery. For example, use this query:
SELECT * FROM t1 WHERE s1 IN (SELECT s1 FROM t1 UNION ALL SELECT s1 FROM t2);
Instead of this query:
SELECT * FROM t1 WHERE s1 IN (SELECT s1 FROM t1) OR s1 IN (SELECT s1 FROM t2);
For another example, use this query:
SELECT (SELECT column1 + 5 FROM t1) FROM t2;
Instead of this query:
SELECT (SELECT column1 FROM t1) + 5 FROM t2;
Use a row subquery instead of a correlated subquery. For example, use this query:
SELECT * FROM t1 WHERE (column1,column2) IN (SELECT column1,column2 FROM t2);
Instead of this query:
SELECT * FROM t1 WHERE EXISTS (SELECT * FROM t2 WHERE t2.column1=t1.column1 AND t2.column2=t1.column2);
Use
NOT (a = ANY (...))rather thana <> ALL (...).Use
x = ANY (rather thantable containing (1,2))x=1 OR x=2.Use
= ANYrather thanEXISTS.For uncorrelated subqueries that always return one row,
INis always slower than=. For example, use this query:SELECT * FROM t1 WHERE t1.
col_name= (SELECT a FROM t2 WHERE b =some_const);Instead of this query:
SELECT * FROM t1 WHERE t1.
col_nameIN (SELECT a FROM t2 WHERE b =some_const);
These tricks might cause programs to go faster or slower. Using
MySQL facilities like the
BENCHMARK() function, you can get
an idea about what helps in your own situation. See
Section 11.10.3, “Information Functions”.
Some optimizations that MySQL itself makes are:
MySQL executes uncorrelated subqueries only once. Use
EXPLAINto make sure that a given subquery really is uncorrelated.MySQL rewrites
IN,ALL,ANY, andSOMEsubqueries in an attempt to take advantage of the possibility that the select-list columns in the subquery are indexed.MySQL replaces subqueries of the following form with an index-lookup function, which
EXPLAINdescribes as a special join type (unique_subqueryorindex_subquery):... IN (SELECT
indexed_columnFROMsingle_table...)MySQL enhances expressions of the following form with an expression involving
MIN()orMAX(), unlessNULLvalues or empty sets are involved:value{ALL|ANY|SOME} {> | < | >= | <=} (uncorrelated subquery)For example, this
WHEREclause:WHERE 5 > ALL (SELECT x FROM t)
might be treated by the optimizer like this:
WHERE 5 > (SELECT MAX(x) FROM t)
See also the MySQL Internals Manual chapter How MySQL Transforms Subqueries.
Before MySQL 4.1, only nested queries of the form
INSERT ... SELECT ... and REPLACE
... SELECT ... are supported. The
IN() construct can be used in other contexts
to test membership in a set of values.
It is often possible to rewrite a query without a subquery:
SELECT * FROM t1 WHERE id IN (SELECT id FROM t2);
This can be rewritten as:
SELECT DISTINCT t1.* FROM t1, t2 WHERE t1.id=t2.id;
The queries:
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);
Can be rewritten as:
SELECT table1.* FROM table1 LEFT JOIN table2 ON table1.id=table2.id WHERE table2.id IS NULL;
A LEFT [OUTER] JOIN can be faster than an
equivalent subquery because the server might be able to optimize
it better — a fact that is not specific to MySQL Server
alone. Prior to SQL-92, outer joins did not exist, so subqueries
were the only way to do certain things. Today, MySQL Server and
many other modern database systems offer a wide range of outer
join types.
For more complicated subqueries, you can often create temporary
tables to hold the subquery. In some cases, however, this option
does not work. The most frequently encountered of these cases
arises with DELETE statements,
for which standard SQL does not support joins (except in
subqueries). For this situation, there are three options
available:
The first option is to upgrade to MySQL 4.1, which does support subqueries in
DELETEstatements.The second option is to use a procedural programming language (such as Perl or PHP) to submit a
SELECTquery which obtains the primary keys for the rows to be deleted, and then use these values to construct the appropriateDELETEstatement (DELETE FROM ... WHERE key_col IN (key1, key2,...)).The third option is to use interactive SQL to construct a set of
DELETEstatements automatically, using the MySQL extensionCONCAT()(in lieu of the standard||operator). For example:SELECT CONCAT('DELETE FROM tab1 WHERE pkid = ', "'", tab1.pkid, "'", ';') FROM tab1, tab2 WHERE tab1.col1 = tab2.col2;You can place this query in a script file, use the file as input to one instance of the mysql program, and use the program output as input to a second instance of mysql:
shell>
mysql --skip-column-names mydb < myscript.sql | mysql mydb
MySQL Server 4.0 supports multiple-table
DELETE statements that can be
used to efficiently delete rows based on information from one
table or even from many tables at the same time. Multiple-table
UPDATE statements are also
supported as of MySQL 4.0.
TRUNCATE [TABLE] tbl_name
TRUNCATE TABLE
empties a table completely. Logically, this is equivalent to a
DELETE statement that deletes all
rows, but there are practical differences under some
circumstances.
For InnoDB,
TRUNCATE TABLE
is mapped to DELETE, so there is no
difference.
For other storage engines,
TRUNCATE TABLE
differs from DELETE in the
following ways from MySQL 4.0 onward:
Truncate operations drop and re-create the table, which is much faster than deleting rows one by one, particularly for large tables.
Truncate operations are not transaction-safe; an error occurs when attempting one in the course of an active transaction or active table lock.
Truncation operations do not return the number of deleted rows.
As long as the table format file
is valid, the table can be re-created as an empty table withtbl_name.frmTRUNCATE TABLE, even if the data or index files have become corrupted.The table handler does not remember the last used
AUTO_INCREMENTvalue, but starts counting from the beginning. This is true even forMyISAMandInnoDB, which normally do not reuse sequence values. (Some older versions may not reset theAUTO_INCREMENTvalue. In this case, you can useALTER TABLEafter thetbl_nameAUTO_INCREMENT=1TRUNCATE TABLEstatement.)
In MySQL 3.23, TRUNCATE
TABLE is mapped to COMMIT; DELETE FROM
, so it behaves like
tbl_nameDELETE. See
Section 12.2.1, “DELETE Syntax”.
TRUNCATE TABLE
was added in MySQL 3.23.28, although from 3.23.28 to 3.23.32, the
keyword TABLE must be omitted.
Single-table syntax:
UPDATE [LOW_PRIORITY] [IGNORE]table_referenceSETcol_name1={expr1|DEFAULT} [,col_name2={expr2|DEFAULT}] ... [WHEREwhere_condition] [ORDER BY ...] [LIMITrow_count]
Multiple-table syntax:
UPDATE [LOW_PRIORITY] [IGNORE]table_referencesSETcol_name1={expr1|DEFAULT} [,col_name2={expr2|DEFAULT}] ... [WHEREwhere_condition]
For the single-table syntax, the
UPDATE statement updates columns of
existing rows in the named table with new values. The
SET clause indicates which columns to modify
and the values they should be given. Each value can be given as an
expression, or the keyword DEFAULT to set a
column explicitly to its default value. The
WHERE clause, if given, specifies the
conditions that identify which rows to update. With no
WHERE clause, all rows are updated. If the
ORDER BY clause is specified, the rows are
updated in the order that is specified. The
LIMIT clause places a limit on the number of
rows that can be updated.
For the multiple-table syntax,
UPDATE updates rows in each table
named in table_references that satisfy
the conditions. In this case, ORDER BY and
LIMIT cannot be used.
where_condition is an expression that
evaluates to true for each row to be updated.
table_references and
where_condition are is specified as
described in Section 12.2.7, “SELECT Syntax”.
The UPDATE statement supports the
following modifiers:
If you use the
LOW_PRIORITYkeyword, execution of theUPDATEis delayed until no other clients are reading from the table. This affects only storage engines that use only table-level locking (MyISAM,MEMORY,MERGE).If you use the
IGNOREkeyword, the update statement does not abort even if errors occur during the update. Rows for which duplicate-key conflicts occur are not updated. Rows for which columns are updated to values that would cause data conversion errors are updated to the closest valid values instead.
If you access a column from the table to be updated in an
expression, UPDATE uses the current
value of the column. For example, the following statement sets the
age column to one more than its current value:
UPDATE persondata SET age=age+1;
Single-table UPDATE assignments are
generally evaluated from left to right. For multiple-table
updates, there is no guarantee that assignments are carried out in
any particular order.
If you set a column to the value it currently has, MySQL notices this and does not update it.
If you update a column that has been declared NOT
NULL by setting to NULL, the column
is set to the default value appropriate for the data type and the
warning count is incremented. The default value is
0 for numeric types, the empty string
('') for string types, and the
“zero” value for date and time types.
UPDATE returns the number of rows
that were actually changed. In MySQL 3.22 or later, the
mysql_info() C API function
returns the number of rows that were matched and updated and the
number of warnings that occurred during the
UPDATE.
Starting from MySQL 3.23, you can use LIMIT
to restrict the
scope of the row_countUPDATE. A
LIMIT clause works as follows:
Before MySQL 4.0.13,
LIMITis a rows-affected restriction. The statement stops as soon as it has changedrow_countrows that satisfy theWHEREclause.From 4.0.13 on,
LIMITis a rows-matched restriction. The statement stops as soon as it has foundrow_countrows that satisfy theWHEREclause, whether or not they actually were changed.
If an UPDATE statement includes an
ORDER BY clause, the rows are updated in the
order specified by the clause. ORDER BY can be
used from MySQL 4.0.0. This can be useful in certain situations
that might otherwise result in an error. Suppose that a table
t contains a column id that
has a unique index. The following statement could fail with a
duplicate-key error, depending on the order in which rows are
updated:
UPDATE t SET id = id + 1;
For example, if the table contains 1 and 2 in the
id column and 1 is updated to 2 before 2 is
updated to 3, an error occurs. To avoid this problem, add an
ORDER BY clause to cause the rows with larger
id values to be updated before those with
smaller values:
UPDATE t SET id = id + 1 ORDER BY id DESC;
Starting with MySQL 4.0.4, you can also perform
UPDATE operations covering multiple
tables. However, you cannot use ORDER BY or
LIMIT with a multiple-table
UPDATE. The
table_references clause lists the
tables involved in the join. Its syntax is described in
Section 12.2.7.1, “JOIN Syntax”. Here is an example:
UPDATE items,month SET items.price=month.price WHERE items.id=month.id;
The preceding example shows an inner join that uses the comma
operator, but multiple-table UPDATE
statements can use any type of join allowed in
SELECT statements, such as
LEFT JOIN.
Before MySQL 4.0.18, you need the
UPDATE privilege for all tables
used in a multiple-table UPDATE,
even if they were not updated. As of MySQL 4.0.18, you need only
the SELECT privilege for any
columns that are read but not modified.
If you use a multiple-table UPDATE
statement involving InnoDB tables for which
there are foreign key constraints, the MySQL optimizer might
process tables in an order that differs from that of their
parent/child relationship. In this case, the statement fails and
rolls back. Instead, update a single table and rely on the
ON UPDATE capabilities that
InnoDB provides to cause the other tables to be
modified accordingly. See
Section 13.2.5.4, “FOREIGN KEY Constraints”.
Currently, you cannot update a table and select from the same table in a subquery.
Index hints (see Section 12.2.7.2, “Index Hint Syntax”) are accepted but
ignored for UPDATE statements.
{DESCRIBE | DESC} tbl_name [col_name | wild]
DESCRIBE provides information about
the columns in a table. It is a shortcut for SHOW COLUMNS
FROM. (See Section 12.5.5.5, “SHOW COLUMNS Syntax”.)
col_name can be a column name, or a
string containing the SQL “%” and
“_” wildcard characters to obtain
output only for the columns with names matching the string. There
is no need to enclose the string within quotes unless it contains
spaces or other special characters.
mysql> DESCRIBE City;
+------------+----------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+----------+------+-----+---------+----------------+
| Id | int(11) | | PRI | NULL | auto_increment |
| Name | char(35) | | | | |
| Country | char(3) | | UNI | | |
| District | char(20) | YES | MUL | | |
| Population | int(11) | | | 0 | |
+------------+----------+------+-----+---------+----------------+
5 rows in set (0.00 sec)
The description for SHOW COLUMNS
provides more information about the output columns (see
Section 12.5.5.5, “SHOW COLUMNS Syntax”).
If the data types differ from what you expect them to be based on
a CREATE TABLE statement, note that
MySQL sometimes changes data types when you create or alter a
table. The conditions under which this occurs are described in
Section 12.1.5.1, “Silent Column Specification Changes”.
The DESCRIBE statement is provided
for compatibility with Oracle.
The SHOW CREATE TABLE,
SHOW TABLE STATUS, and
SHOW INDEX statements also provide
information about tables. See Section 12.5.5, “SHOW Syntax”.
EXPLAIN tbl_name
Or:
EXPLAIN [EXTENDED] SELECT select_options
The EXPLAIN statement can be used
either as a synonym for DESCRIBE or
as a way to obtain information about how MySQL executes a
SELECT statement:
EXPLAINis synonymous withtbl_nameDESCRIBEortbl_nameSHOW COLUMNS FROM.tbl_nameFor a description of the
DESCRIBEandSHOW COLUMNSstatements, see Section 12.3.1, “DESCRIBESyntax”, and Section 12.5.5.5, “SHOW COLUMNSSyntax”.When you precede a
SELECTstatement with the keywordEXPLAIN, MySQL displays information from the optimizer about the query execution plan. That is, MySQL explains how it would process theSELECT, including information about how tables are joined and in which order.EXPLAIN EXTENDEDcan be used to provide additional information.For information regarding the use of
EXPLAINandEXPLAIN EXTENDEDfor obtaining query execution plan information, see Section 7.2.1, “Optimizing Queries withEXPLAIN”.
HELP 'search_string'
The HELP statement returns online
information from the MySQL Reference manual. Its proper operation
requires that the help tables in the mysql
database be initialized with help topic information (see
Section 5.1.8, “Server-Side Help”).
The HELP statement searches the
help tables for the given search string and displays the result of
the search. The search string is not case sensitive.
The HELP statement understands several types of search strings:
At the most general level, use
contentsto retrieve a list of the top-level help categories:HELP 'contents'
For a list of topics in a given help category, such as
Data Types, use the category name:HELP 'data types'
For help on a specific help topic, such as the
ASCII()function or theCREATE TABLEstatement, use the associated keyword or keywords:HELP 'ascii' HELP 'create table'
In other words, the search string matches a category, many topics,
or a single topic. You cannot necessarily tell in advance whether
a given search string will return a list of items or the help
information for a single help topic. However, you can tell what
kind of response HELP returned by
examining the number of rows and columns in the result set.
The following descriptions indicate the forms that the result set
can take. Output for the example statements is shown using the
familiar “tabular” or “vertical” format
that you see when using the mysql client, but
note that mysql itself reformats
HELP result sets in a different
way.
Empty result set
No match could be found for the search string.
Result set containing a single row with three columns
This means that the search string yielded a hit for the help topic. The result has three columns:
name: The topic name.description: Descriptive help text for the topic.example: Usage example or examples. This column might be blank.
Example:
HELP 'replace'Yields:
name: REPLACE description: Syntax: REPLACE(str,from_str,to_str) Returns the string str with all occurrences of the string from_str replaced by the string to_str. REPLACE() performs a case-sensitive match when searching for from_str. example: mysql> SELECT REPLACE('www.mysql.com', 'w', 'Ww'); -> 'WwWwWw.mysql.com'Result set containing multiple rows with two columns
This means that the search string matched many help topics. The result set indicates the help topic names:
name: The help topic name.is_it_category:Yif the name represents a help category,Nif it does not. If it does not, thenamevalue when specified as the argument to theHELPstatement should yield a single-row result set containing a description for the named item.
Example:
HELP 'status'Yields:
+-----------------------+----------------+ | name | is_it_category | +-----------------------+----------------+ | SHOW | N | | SHOW ENGINE | N | | SHOW INNODB STATUS | N | | SHOW MASTER STATUS | N | | SHOW SLAVE STATUS | N | | SHOW STATUS | N | | SHOW TABLE STATUS | N | +-----------------------+----------------+
Result set containing multiple rows with three columns
This means the search string matches a category. The result set contains category entries:
source_category_name: The help category name.name: The category or topic nameis_it_category:Yif the name represents a help category,Nif it does not. If it does not, thenamevalue when specified as the argument to theHELPstatement should yield a single-row result set containing a description for the named item.
Example:
HELP 'functions'Yields:
+----------------------+-------------------------+----------------+ | source_category_name | name | is_it_category | +----------------------+-------------------------+----------------+ | Functions | CREATE FUNCTION | N | | Functions | DROP FUNCTION | N | | Functions | Bit Functions | Y | | Functions | Comparison operators | Y | | Functions | Control flow functions | Y | | Functions | Date and Time Functions | Y | | Functions | Encryption Functions | Y | | Functions | Information Functions | Y | | Functions | Logical operators | Y | | Functions | Miscellaneous Functions | Y | | Functions | Numeric Functions | Y | | Functions | String Functions | Y | +----------------------+-------------------------+----------------+
If you intend to use the HELP
statement while other tables are locked with
LOCK TABLES, you must also lock the
required
mysql.help_
tables.
xxx
The HELP statement was added in
MySQL 4.1.
USE db_name
The USE
statement tells MySQL to use the
db_namedb_name database as the default
(current) database for subsequent statements. The database remains
the default until the end of the session or another
USE statement is issued:
USE db1; SELECT COUNT(*) FROM mytable; # selects from db1.mytable USE db2; SELECT COUNT(*) FROM mytable; # selects from db2.mytable
Making a particular database the default by means of the
USE statement does not preclude you
from accessing tables in other databases. The following example
accesses the author table from the
db1 database and the editor
table from the db2 database:
USE db1; SELECT author_name,editor_name FROM author,db2.editor WHERE author.editor_id = db2.editor.editor_id;
The USE statement is provided for
compatibility with Sybase.
MySQL supports local transactions (within a given client session)
through statements such as
SET autocommit,
START TRANSACTION,
COMMIT, and
ROLLBACK. See
Section 12.4.1, “START TRANSACTION,
COMMIT, and
ROLLBACK Syntax”.
START TRANSACTION [WITH CONSISTENT SNAPSHOT] | BEGIN [WORK]
COMMIT
ROLLBACK
SET autocommit = {0 | 1}
The START
TRANSACTION or
BEGIN statement
begins a new transaction. COMMIT
commits the current transaction, making its changes permanent.
ROLLBACK rolls
back the current transaction, canceling its changes. The
SET autocommit
statement disables or enables the default autocommit mode for the
current session.
By default, MySQL runs with autocommit mode enabled. This means that as soon as you execute a statement that updates (modifies) a table, MySQL stores the update on disk to make it permanent. To disable autocommit mode, use the following statement:
If you are using a transaction-safe storage engine (such as
InnoDB, BDB, or
NDBCLUSTER), you can disable
autocommit mode with the following statement:
SET autocommit=0;
After disabling autocommit mode by setting the
autocommit variable to zero,
changes to transaction-safe tables (such as those for
InnoDB or
NDBCLUSTER) are not made permanent
immediately. You must use COMMIT to
store your changes to disk or
ROLLBACK to
ignore the changes.
To disable autocommit mode for a single series of statements, use
the START
TRANSACTION statement:
START TRANSACTION; SELECT @A:=SUM(salary) FROM table1 WHERE type=1; UPDATE table2 SET summary=@A WHERE type=1; COMMIT;
With START
TRANSACTION, autocommit remains disabled until you end
the transaction with COMMIT or
ROLLBACK. The
autocommit mode then reverts to its previous state.
BEGIN and
BEGIN WORK are
supported as aliases of
START
TRANSACTION for initiating a transaction.
START
TRANSACTION was added in MySQL 4.0.11. This is standard
SQL syntax and is the recommended way to start an ad-hoc
transaction.
BEGIN and
BEGIN WORK are
available from MySQL 3.23.17 and 3.23.19, respectively.
Important
Many APIs used for writing MySQL client applications (such as
JDBC) provide their own methods for starting transactions that
can (and sometimes should) be used instead of sending a
START
TRANSACTION statement from the client. See
Chapter 17, Connectors and APIs, or the documentation for your
AP