13.1. 数据定义声明
13.1.1.ALTER DATABASE句法
ALTER {DATABASE | SCHEMA} [db_name]
alter_specification [, alter_specification] ...
alter_specification:
[DEFAULT] CHARACTER SET charset_name
| [DEFAULT] COLLATE collation_name
ALTER DATABASE允许你改变一个数据库的全部特征。这些特征存储在数据库文件夹里的db.opt文件中,要使用ALTER DATABASE,你需要对数据库有ALTER的权限。
CHARACTER SET分句用来改变数据库的默认字符集,COLLATE分句用来改变数据库的默认检验方式。字符集和检验名称在第十章“字符集支持”中讨论。
数据库的名称可以忽略,在这种情况下,声明应用于默认数据库。自MySQL5.0.2之后版本中可以使用ALTER SCHEMA。
13.1.2. ALTER TABLE句法
ALTER [IGNORE] TABLE tbl_name
alter_specification [, alter_specification] ...
alter_specification:
ADD [COLUMN] column_definition [FIRST | AFTER col_name ]
| ADD [COLUMN] (column_definition,...)
| ADD INDEX [index_name] [index_type] (index_col_name,...)
| ADD [CONSTRAINT [symbol]]
PRIMARY KEY [index_type] (index_col_name,...)
| ADD [CONSTRAINT [symbol]]
UNIQUE [index_name] [index_type] (index_col_name,...)
| ADD [FULLTEXT|SPATIAL] [index_name] (index_col_name,...)
| ADD [CONSTRAINT [symbol]]
FOREIGN KEY [index_name] (index_col_name,...)
[reference_definition]
| ALTER [COLUMN] col_name {SET DEFAULT literal | DROP DEFAULT}
| CHANGE [COLUMN] old_col_name column_definition
[FIRST|AFTER col_name]
| MODIFY [COLUMN] column_definition [FIRST | AFTER col_name]
| DROP [COLUMN] col_name
| DROP PRIMARY KEY
| DROP INDEX index_name
| DROP FOREIGN KEY fk_symbol
| DISABLE KEYS
| ENABLE KEYS
| RENAME [TO] new_tbl_name
| ORDER BY col_name
| CONVERT TO CHARACTER SET charset_name [COLLATE collation_name]
| [DEFAULT] CHARACTER SET charset_name [COLLATE collation_name]
| DISCARD TABLESPACE
| IMPORT TABLESPACE
| table_options
ALTER TABLE允许你改变一个现存数据表的结构。例如,你可以添加或者删除数据列,建立或者销毁索引,改变现存数据列的类型,或者重命名数据列甚至数据表本身。你也可以改变数据表的注释和数据表的类型。
可做的改变的句法和CREATE TABLE声明的分句是类似的。这包括了table_options修改,选项诸如ENGINE,AUTO_INCREMENT,和AVG_ROW_LENGH。见13.1.5,"CREATE TABLE Syntax"部分。
如果试图在数据表上执行存储引擎不支持的一些操作将可能导致产生警告。这些警告可以用SHOW WARNINGS查看。见13.5.4.22,"SHOW WARNINGS Syntax"部分。
如果你使用ALTER TABLE来改变一个数据列规格,但是DESCRIBE tbl_name表明你的数据列没有改变,可能是MySQL忽略了你的修改,可能的原因在13.1.5.1,"Silent Column Specification Changes"部分中有描述。例如,如果你试图将一个VARCHAR列改变为CHAR,MySQL会仍然使用VARCHAR如果数据表包含其它可变长的数据列。
ALTER TABLE是通过生成原数据表的临时拷贝来工作的。改变是在拷贝上执行的,然后删除原数据表同时改变新数据表的名称。当ALTER TABLE执行时,原数据表仍然可以被其它用户读取。对原数据表更新和写操作将缓存直到新数据表可用,这时它们自动重定向到新数据表而不会有任何失败的更新。
注意如果你在ALTER TABLE中使用除RENAME的任何选项,MySQL总是建立一个临时数据表,即使数据并不是直接需要拷贝的(例如当你重命名一个数据列)。对MyISAM数据表,你可以通过设置myisam_sort_buffer_size系统变量为一个较高的值来加速索引的重生成操作(这是alteration过程中最慢的部分)。
●要使用ALTER TABLE,你需要对数据表有ALTER,INSERT,和CREATE的权限
●IGNORE是MySQL从标准SQL扩展出来的。当在新数据表中有唯一键的复制或者当STRICT模式启用后如果有警告产生时,它控制ALTER TABLE怎样工作。如果IGNORE没有定,当有复制键错误产生时,拷贝将被丢弃并且执行回滚。如果IGNORE被指定,对于有一个唯一键的复制数据行,只保留第一个数据行。其它冲突的数据行将被删除。错误值会缩短到可接受值的最接近匹配。
●你可以在一个ALTER TABLE声明中发出多重ADD,ALTER,DROP,和CHANGE分句,使用逗号分隔。这是对标准SQL的一个MySQL扩展,它允许在每个ALTER TABLE声明中只能有一个这些分句。例如,要在一个声明中丢弃多个数据列:
mysql> ALTER TABLE t2 DROP COLUMN c, DROP COLUMN d;
●CHANGE col_name,DROP col_name,和DROP INDEX是标准SQL的MySQL扩展
●MODIFY是对ALTER TABLE的一个Oracle扩展
●关键字COLUMN是纯可选的,可以忽略
●如果你使用ALTER TABLE tbl_name RENAME TO new_tbl_name而不带其它选项,MySQL就简单的改变所有符合数据表tbl_name的文件。这就没有必要创建一个临时的数据表了。(你也可以使用RENAME TABLE声明来重命名数据表。见13.1.9,"RENAME TABLE Syntax"部分)
●column_definition分句使用和CREATE TABLE相同的ADD和CHANGE句法。注意这个句法包含数据列的名称,而不仅仅是数据列类型。见13.1.9,"CREATE TABLE Syntax"部分
●你可以使用CHANGE old_col_name column_definition分句来重命名一个数据列。要达到目的,需要指定旧的和新的数据列名称和数据列当前的类型。例如,要重命名一个INTEGER数据列a为b,你可以这样做:
mysql> ALTER TABLE t1 CHANGE a b INTEGER;
如果你想改变一个数据列的类型而不是名称,CHANGE句法仍然需要旧的和新的数据列的名称,即使他们是一样的,例如:
mysql> ALTER TABLE t1 CHANGE b b BIGINT NOT NULL;
你也可以MODIFY来改变一个数据列的类型而不重命名它:
mysql> ALTER TABLE t1 MODIFY b BIGINT NOT NULL;
●如果你使用CHANGE或者MODIFY来缩短一个已存在索引的数据列,而得到的数据列长度比索引长度短,MySQL会自动缩短索引。
●当你使用CHAGNE或者MODIFY来改变一个数据列的类型时,如果可能,MySQL会试图将现存的数据列中的值转换为新类型的值。
●你可以使用FIRST或AFTER col_name来在指定位置增加一个数据列。默认值是在最后增加这个数据列。你也可以在CHAGNE或MODIFY操作中使用FIRST和AFTER。
●ALTER COLUMN为一个数据列指定一个新的默认值或者去掉旧的德默认值。如果旧的默认值去掉了,数据列的默认值可以是NULL,新的默认值是NULL。如果数据列不能是NULL,MySQL指定一个默认值,如在13.1.5,"CREATE TABLE Syntax"部分中描述的。
●DROP INDEX去掉一个索引,这是标准SQL的一个MySQL扩展。见13.1.7,"DROP INDEX Syntax"部分。
●如果从数据表删除了一些数据列,那么这些数据列也从任何包含它们的索引中去掉了。如果一个索引的所有数据列都删除了,那么这个索引也会被删除了。
●如果一个数据表只包含一个数据列,数据列不能够被删除。如果你想要删除这个数据表,请使用DROP TABLE来替代。
●DROP PRIMARY KEY将删除主索引。注意:在老版本的MySQL中,如果不存在主索引,则DROP PRIMARY KEY会删除数据表中的第一个唯一性索引。在MySQL5.0中不会这样,在这里试图对一个不存在主键的数据表执行DROP PRIMARY KEY将会产生错误。
如果你向一个数据表增加一个UNIQUE INDEX或者PRIMARY KEY,它会在任何非唯一性索引之前存储,这样MySQL就可以尽早检测到复制键。
●ORDER BY允许你使用数据行以指定的顺序创建一个新的数据表。注意在插入和删除操作之后数据表不会再保持这个顺序。在你知道你会很可能要使用一个特定的顺序来查询时,这个选项是很有用的,在对数据表有大的改变之后,通过使用这个选项你可以的到更好的表现。在一些情况下,当某个数据表已经按照某个列的顺序排序了而你也要在之后使用这个列来排序时,对MySQL来说排序会简单些。
●如果你在一个MyISAM数据表上使用ALTER TABLE,所有非唯一性索引会在另一批中生成(就像REPAIR TABLE做的一样)。当你有很多索引时这会使ALTER TABLE更快。
这个特性可以显式的激活。ALTER TABLE ... DISABLE KEYS告诉MySQL停止为一个MyISAM数据表更新非唯一性索引。MySQL使用一个特殊算法来达到这个目的,它要比一个一个的插入键快的多,所以在大批量插入操作之前使键失效应该会得到一个显著的速度提升。使用ALTER TABLE ... DISABLE KEYS需要在之前提到的权限中加入INDEX权限。
●InnoDB存储引擎支持FOREIGN KEY和REFERENCE分句,它实现了ADD [CONSTRAINT[symbol]] FOREIGN KEY (...) REFERENCES ... (...)。见14.2.6.4,"FOREIGN KEY Constraint"部分。对于其他存储引擎,这些分句会解析但会被忽略。CHECK分句会被所有存储引擎解析但被忽略。见13.1.5,"CREATE TABLE Syntax"部分。接受这些句法分句但是忽略它们的原因是为了保持兼容性,使从其他SQL服务器引入代码更容易,同时也使使用引用创建数据表的应用程序更容易运行。见1.8.5,"MySQL Differences from Standard SQL"部分。
你不能在一个ALTER TABLE声明中使用多个分句添加一个外键又删除一个外键。你必须使用不同的声明。
●InnoDB支持使用ALTER TABLE来删除外键:
ALTER TABLE yourtablename DROP FOREIGN KEY fk_symbol;
你不能在一个ALTER TABLE声明中使用多个分句添加一个外键又删除一个外键。你必须使用不同的声明。
要得到更多信息,见14.2.6.4,"FOREIGN KEY Constraints"部分。
●ALTER TABLE忽略DATA DIRECTORY和INDEX DIRECTORY数据表选项。
●如果你想要改变数据表的默认字符集和所有字符数据列(CHAR,VARCHAR,TEXT)为一个新的字符集,请使用声明如下:
ALTER TABLE tbl_name CONVERT TO CHARACTER SET charset_name;
警告:前面的操作将数据列的值在两个字符集之间进行转换。如果你有一个数据列使用一个字符集(如latin1),但实际上存的数据使用另一个不兼容的字符集(如utf8)。在这种情况下,你应该对每个这样的数据列操作如下:
ALTER TABLE t1 CHANGE c1 c1 BLOB;
ALTER TABLE t1 CHANGE c1 c1 TEXT CHARACTER SET utf8;
这样做的原因是,在你将数据列转换到BLOB或从BLOB转换过来的时候数据不会发生转换。
如果你指定CONVERT TO CHARACTER SET binary,那些CHAR,VARCHAR,和TEXT数据列都转换为它们相应的二进制字符串类型(BINARY,VARBINARY,BLOB)。这表明这些数据列不再可以拥有一个字符集而且以后的CONVERT TO操作将不会对它们产生影响。
只是要改变一个数据表的默认字符集,使用这个声明:
ALTER TABLE tbl_name DEFAULT CHARACTER SET charset_name;
关键字DEFAULT是可选的。默认字符集是指在你没有指定你添加到数据表的一个新数据列的字符集时,它使用的字符集(例如,使用ALTER TABLE ... ADD column)。
警告:ALTER TABLE ... DEFAULT CHARACTER SET和ALTER TABLE ... CHARACTER SET是等价的,而且只改变数据表的默认字符集。
●对于一个在.idb文件中它自己的表空间中创建InnoDB数据表,这个文件可以丢弃和导入的。要丢弃这个.idb文件,使用这个声明:
ALTER TABLE tbl_name DISCARD TABLESPACE;
这会删除当前的.idb文件,所以确保你事先有一个备份。当表空间文件丢弃后试图存取这个数据表的操作将引发错误。
要导入备份的.idb文件到数据表,拷贝它到数据库文件加,然后发布这个声明:
ALTER TABLE tbl_name IMPORT TABLESPACE;
见14.2.6.6,"Using Per-Table Tablespaces"。
●使用mysql_info() C API函数,你可以知道有多少记录拷贝了,而且(当使用了IGNORE)有多少记录因为复制唯一键而删除了。见22.2.3.34,"mysql_info()"部分。
下面是一些演示怎样使用ALTER TABLE的例子。首先演示建立一个数据表t1如下:
mysql> CREATE TABLE t1 (a INTEGER,b CHAR(10));
要重命名数据表t1为t2:
mysql> ALTER TABLE t1 RENAME t2;
要改变数据列a类型从INTEGER为TINYINT NOT NULL(名字不变),同时改变数据列b的类型从CHAR(10)为CHAR(20),同时把列名从b改为c:
mysql> ALTER TABLE t2 MODIFY a TINYINT NOT NULL, CHANGE b c CHAR(20);
要增加一个新的名称为d的实践戳列:
mysql> ALTER TABLE t2 ADD d TIMESTAMP;
要在数据列d和数据列a上增加索引:
mysql> ALTER TABLE t2 ADD INDEX (d), ADD INDEX (a);
要删除数据列c:
mysql> ALTER TABLE t2 DROP COLUMN c;
要增加一个名称为c的自增整数类型的数据列:
mysql> ALTER TABLE t2 ADD c INT UNSIGNED NOT NULL AUTO_INCREMENT,
-> ADD PRIMARY KEY (c);
注意,我们把c设为索引(作为主键),因为AUTO_INCREMENT列必须是索引的,而且我们声明c是NOT NULL的,因为逐渐列必须非空。
当你增加自增列时,列值会被自动填入后续的数值。对于MyISAM数据表,你可以通过在ALTER TABLE之前执行SET INSERT_ID=value,或者通过使用AUTO_INCREMENT=value数据表选项来设置第一个后续数值。见13.5.3,"SET Syntax"部分。
从MySQL5.0.3开始,对于InnoDB数据表,如果值已经超过自增列的最大值,你可以使用ALTER TABLE ... AUTO_INCREMENT=value数据表选项来对新数据行设置后续数值。如果这个值小于数据列当前最大值,就不会产生错误而且当前值也不会改变。
对于MyISAM数据表,如果你没有改变自增列,后续数值将不会受到影响。如果你删除了一个自增列,而后又增加了另一个自增列,列值将自动从一开始增加。
见A7.1,"Problem with ALTER TABLE"部分。
13.1.3 CREATE DATABASE句法
CREATE {DATABASE | SCHEMA} [IF NOT EXISTS] db_name
[create_specification [, create_specification] ...]
create_specification:
[DEFAULT] CHARACTER SET charset_name
| [DEFAULT] COLLATE collation_name
CREATE DATABASE使用给定名字创建一个数据库。要使用CREATE DATABASE,你需要对数据库有CREATE权限。
对允许的数据库名称的规则在9.2,"Database,Table,Index,Column,and Alias Names"部分给出。如果数据库已存在,而你没有指定IF NOT EXISTS,将产生错误信息。
create_specification选项指定数据库的特性,数据库特性存储在数据库文件加里的db.opt文件中。CHARACTER SET分句指定默认数据库字符集,COLLATE分局制定默认数据库排序方式。字符集和排序方式名称在第十章Character Set Support中讨论。
MySQL中的数据库是做为文件夹实现的,包含着与数据库中的数据表对应的文件。因为在最初创建一个数据库时里面没有数据表,CREATE DATABASE声明只是在MySQL的data文件加里创建一个文件夹和一个db.opt文件。
如果你在data文件加里手动创建一个文件夹(例如叫mkdir),服务器将认为它是一个数据库文件夹,而且将在SHOW DATABASES命令的输出中显示出来。
你也可以使用mysqladmin程序来创建数据库,见8.5,"mysqladmin--Client for Administering a MySQL Server"部分。
13.1.4.CREATE INDEX句法
CREATE [UNIQUE|FULLTEXT|SPATIAL] INDEX index_name
[USING index_type]
ON tbl_name (index_col_name,...)
index_col_name:
col_name [(length)] [ASC | DESC]
CREATE INDEX分配一个ALTER TABLE声明来创建索引。见13.1.2,"ALTER TABLE Syntax"部分。
通常情况下,你在数据表通过CREATE TABLE创建时创建所有索引。见13.1.5,"CREATE TABLE Syntax"部分。CREATE INDEX允许你向一个已存在数据表中添加索引。
一个型如(col1,col2,...)的数据列列表创建了一个多列索引。索引的值的形式通过连接给定的数据列的值来确定。
对于CHAR和VARCHAR数据列,可以创建之使用数据列的一部分的索引,使用col_name(length)句法来索引由每个数据列值的前面length个字符组成的前缀。BLOB和TEXT数据列也可以被索引,但一个前缀长度必须给定。
如下所示的声明创建了一个索引,它使用name数据列的前十个字符来索引:
CREATE INDEX part_of_name ON customer (name(10));
因为多数名字可以在前十个字符区分,这个索引应该不会比一个使用完整name数据列的索引更慢的。而且,为索引使用部分数据列可以使索引文件更小,这可以节省很多的硬盘空间,而且也可以加速INSERT操作。
前缀可以最高达到1000字节长度(对于InnoDB数据表是767字节)。注意前缀限制是用字节衡量的,而CREATE INDEX声明中的前缀长度是以字符的数目表示的。当为一个使用多字节字符集的数据列指定一个前缀长度时,要把这个考虑在内。
在MySQL 5.0中:
●只有在你使用的是MyISAM,InnoDB,或者BDB数据表类型时,你才可以往数据列中添加一个含有NULL值的索引
●只有在你使用的是MyISAM,InnoDB,或者BDB数据表类型时,你才可以往BLOB或TEXT数据列添加一个索引。
一个index_col_name指定可以以ASC或DESC结束。这些关键字允许在以后对索引值按指定的升序或者降序扩展。当前它们可以解析但被忽略,索引值通常都是升序存储。
一些存储引擎允许你在创建一个索引时指定一个索引类型。指定index_type的句法是USING type_name。不同存储引擎支持的可用type_name值在下面的表格中列出。列出多个索引类型的地方,第一个是当没有指定index_type值时默认的值。
---------------------------------------------
Storage Engine | Allowable Index Types
---------------------------------------------
MyISAM | BTREE
InnoDB | BTREE
MEMORY/HEAP| HASH, BTREE
---------------------------------------------
例子:
CREATE TABLE lookup (id INT) ENGINE = MEMORY;
CREATE INDEX id_index USING BTREE ON lookup (id);
TYPE type_name可以用来替换USING type_name来指定一个索引的类型。然而,USING是更好的形式。另外,在索引指定句法中索引名称在索引类型之前对于TYPE来说不是可选的。这是因为,和USING不同,TYPE不是保留字,因而它被解释为一个索引名称。
如果你指定一个索引类型对于一个给定存储引擎是不合法的,而又存在另一个引擎可以使用又不会影响查询结果可用的索引类型,引擎将使用这个可用的类型。
要得到更多怎样使用索引的信息,见7.4.5,"How MySQL Uses Indexes"部分。
FULLTEXT索引只可以索引CHAR,VARCHAR,和TEXT数据列,而且只用在MyISAM数据表中,见12.7,"Full-Text Search Functions"部分。
SPATIAL索引只可以索引空间(spatial)数据列,而且只用在MyISAM数据表中。空间数据列类型在第十六章,Spatial Extensions in MySQL有描述。
13.1.5. CREATE TABLE Syntax
CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name
[(create_definition,...)]
[table_options] [select_statement]
Or:
CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name
[(] LIKE old_tbl_name [)];
create_definition:
column_definition
| [CONSTRAINT [symbol]] PRIMARY KEY [index_type] (index_col_name,...)
| KEY [index_name] [index_type] (index_col_name,...)
| INDEX [index_name] [index_type] (index_col_name,...)
| [CONSTRAINT [symbol]] UNIQUE [INDEX]
[index_name] [index_type] (index_col_name,...)
| [FULLTEXT|SPATIAL] [INDEX] [index_name] (index_col_name,...)
| [CONSTRAINT [symbol]] FOREIGN KEY
[index_name] (index_col_name,...) [reference_definition]
| CHECK (expr)
column_definition:
col_name type [NOT NULL | NULL] [DEFAULT default_value]
[AUTO_INCREMENT] [UNIQUE [KEY] | [PRIMARY] KEY]
[COMMENT 'string'] [reference_definition]
type:
TINYINT[(length)] [UNSIGNED] [ZEROFILL]
| SMALLINT[(length)] [UNSIGNED] [ZEROFILL]
| MEDIUMINT[(length)] [UNSIGNED] [ZEROFILL]
| INT[(length)] [UNSIGNED] [ZEROFILL]
| INTEGER[(length)] [UNSIGNED] [ZEROFILL]
| BIGINT[(length)] [UNSIGNED] [ZEROFILL]
| REAL[(length,decimals)] [UNSIGNED] [ZEROFILL]
| DOUBLE[(length,decimals)] [UNSIGNED] [ZEROFILL]
| FLOAT[(length,decimals)] [UNSIGNED] [ZEROFILL]
| DECIMAL(length,decimals) [UNSIGNED] [ZEROFILL]
| NUMERIC(length,decimals) [UNSIGNED] [ZEROFILL]
| DATE
| TIME
| TIMESTAMP
| DATETIME
| CHAR(length) [BINARY | ASCII | UNICODE]
| VARCHAR(length) [BINARY]
| TINYBLOB
| BLOB
| MEDIUMBLOB
| LONGBLOB
| TINYTEXT [BINARY]
| TEXT [BINARY]
| MEDIUMTEXT [BINARY]
| LONGTEXT [BINARY]
| ENUM(value1,value2,value3,...)
| SET(value1,value2,value3,...)
| spatial_type
index_col_name:
col_name [(length)] [ASC | DESC]
reference_definition:
REFERENCES tbl_name [(index_col_name,...)]
[MATCH FULL | MATCH PARTIAL | MATCH SIMPLE]
[ON DELETE reference_option]
[ON UPDATE reference_option]
reference_option:
RESTRICT | CASCADE | SET NULL | NO ACTION
table_options: table_option [table_option] ...
table_option:
{ENGINE|TYPE} = engine_name
| AUTO_INCREMENT = value
| AVG_ROW_LENGTH = value
| [DEFAULT] CHARACTER SET charset_name [COLLATE collation_name]
| CHECKSUM = {0 | 1}
| COMMENT = 'string'
| CONNECTION = 'connect_string'
| MAX_ROWS = value
| MIN_ROWS = value
| PACK_KEYS = {0 | 1 | DEFAULT}
| PASSWORD = 'string'
| DELAY_KEY_WRITE = {0 | 1}
| ROW_FORMAT = {DEFAULT|DYNAMIC|FIXED|COMPRESSED|REDUNDANT|COMPACT}
| UNION = (tbl_name[,tbl_name]...)
| INSERT_METHOD = { NO | FIRST | LAST }
| DATA DIRECTORY = 'absolute path to directory'
| INDEX DIRECTORY = 'absolute path to directory'
select_statement:
[IGNORE | REPLACE] [AS] SELECT ... (Some legal select statement)
CREATE TABLE使用给定名字创建一个表格。你必须拥有对数据表的CREATE权限。
数据表名称可以以db_name.tbl_name来指定,它的意思是在指定数据库中创建这个数据表。不管数据库存在与否,这样的表示都会工作。如果你使用引用标识符,要分别引用数据库和数据表名称。例如,'mydb'.'mytbl'适合法的,但'mydb.mytbl'则不是。
你可以使用TEMPORARY关键字来创建一个数据表,一个TEMPORARY数据表支队当前连接是可见的,而且会在连接关闭后自动删除。
在数据表已存在时,关键字IF NOT EXISTS可以阻止产生一个错误。注意,系统不会验证已存在的数据表和通过CREATE TABLE声明创建的数据表是否有相同的结构。注意:如果你在一句CREATE TABLE ... SELECT声明中使用了IF NOT EXISTS,任何通过SELECT部分被选择的记录都被插入,不论数据表是否已经存在。
MySQL将每一个数据表用一个存储在数据库文件加内的.frm数据表结构(定义)文件来表示。存储引擎可能会为这个数据表创建同时其他文件。在使用MyISAM数据表的情况下,存储引擎会创建数据和索引文件。这样的话,每个MyISAM的数据表tbl_name,会有三个磁盘文件:
--------------------------------------------------
File |Purpose
--------------------------------------------------
tbl_name.frm |Table format (definition) file
tbl_name.MYD |Data file
tbl_name.MYI |Index file
--------------------------------------------------
●如果NULL和NOT NULL都没有指定,则处理数据列是将按NULL已指定处理
●一个整型数据列可以有一个额外属性AUTO_INCREMENT。当你插入一个NULL值(推荐)或者0到一个索引AUTO_INCREMENT数据列中,数据列将被设置为下一个序列值。通常这是value+1,其中value是数据列的当前最大值。AUTO_INCREMENT序列从1开始。
为sql-mode服务器选项或者系统变量指定NO_AUTO_VALUE_ON_ZERO标志允许你在AUTO_INCREMENT数据列中存储0值,而不产生新的序列值。
注意:在一个数据表中只能有一个AUTO_INCREMENT数据列,它必须被索引,而且它不能有默认值。一个AUTO_INCREMENT数据列只有在它只包含正值时才能正确的工作。插入一个负数相当于插入一个非常大的正数。这样做的目的是为了避免当从正数包装为负数时的精确性问题,而且也可以保证你不会误使一个AUTO_INCREMENT数据列包含0值。
对于MyISAM和BDB数据表,你可以在一个多列键中指定第二个AUTO_INCREMENT列,见3.6.9,"Using AUTO_INCREMENT"部分。
为了让MySQL与ODBC应用程序兼容,你可以使用下面的查询找到最后一次插入的行的AUTO_INCREMENT值:
SELECT * FROM tbl_name WHERE auto_col IS NULL
●字符列定义可以包含一个字符集属性来指定字符集,并且,可选的,可以检验这个数据列。
CREATE TABLE t (c CHAR(20) CHARACTER SET utf8 COLLATE utf8_bin);
MySQL5.0使用字符数来表示一个字符列的长度。()一些较早的版本使用字节数来表示它们。
●DEFAULT分句为一个数据列指定一个默认值。除一个例外之外,默认值必须是一个常数,它不能使一个方法或者一个表达式。这说明,例如,你不能设置一个日期列的默认值为一个形如NOW()的方法的值或者CURRENT_DATE。这个例外是你可以指定CURRENT_TIMESTAMP为一个TIMESTAMP列的默认值。See Section 11.3.1.1, “TIMESTAMP Properties as of MySQL 4.1”.
在MySQL5.0.2之前,如果一个数据列定义不包含明确的默认值,MySQL通过如下显示来确定默认值:
如果数据列可以设置NULL值,数据列就由一个显式的DEFAULT NULL分句定义。
如果数据列不能使用NULL值,MySQL使用一个显式DEFAULT分句定义数据列,为属剧烈的数据类型使用隐式默认值。隐式默认值由下列步骤定义:
▲除使用AUTO_INCREMENT属性声明的数据列外,对于数字类型默认值是0。对于一个AUTO_INCREMENT列,默认值是序列中的下一个值。
▲除使用TIMESTAMP类型以外,对于日期和时间类型,默认值是该类型的合适的"zero"值。对于数据表中的第一个TIMESTAMP列,默认值是当前的日期和时间。See Section 11.3, “Date and Time Types”.
▲除使用ENUM类型以外,对于字符串类型,默认值是空串。对于ENUM类型,默认值是第一个枚举值。
BLOB和TEXT数据列不能指定一个默认值。
在MySQL5.0.2中,如果一个数据列定义不包含明确的默认值,MySQL通过如下显示来确定默认值:
自5.0.2版本开始,如果这个数据列可以设置NULL值,数据列就由一个显式的DEFAULT NULL分句定义。
如果这个数据列不能使用NULL作为默认值,MySQL定义数据列时不包含明确的DEFAULT分句。对于数据输入,如果一个INSERT或REPLACE声明不包含这个数据列的值,MySQL根据当时SQL的模式来处理这个数据列:
▲如果严格模式没有激活,MySQL设置为数据列数据类型设置隐式默认值。
▲如果严格模式被激活,将为相应的数据表产生一个错误,然后回滚这个声明。对于没有作用的数据表,产生一个错误,但如果这是在一个多行声明的第二行或后面的行中发生的,正在处理的数据行将会被插入。
假设一个数据表是如下定义的:
CREATE TABLE t (i INT NOT NULL);
在这个情况下,i没有明确的默认值,所以在严格模式下,后面的每个声明产生一个错误,并且不会插入数据行。当没有使用严格模式的情况下,只有第三个声明产生错误,前两个声明的隐式默认值被插入进去了,但第三个失败了,因为DEFAULT(i)不能产生一个值。
INSERT INTO t VALUES();
INSERT INTO t VALUES(DEFAULT);
INSERT INTO t VALUES(DEFAULT(i));
See Section 5.3.2, “The Server SQL Mode”.
对一个给定的数据表,你可以使用SHOW CREATE TABLE声明来查看哪些列有一个显式DEFAULT分句。
●一个UNIQUE索引是一个其中所有值都必须不同的索引。如果你尝试在增加一个与已存在的数据行的键值相匹配的数据行,将产生一个错误。有一个例外,就是如果这个索引中的一个列允许包含NULL值,它可以包含多NULL值。这个例外对于BDB不适用,因为其中一个索引的列只能允许一个NULL值。
●一个主键(PRIMARY KEY)是一个唯一键,其中所有键列都必须定义为NOT NULL。如果它们没有显式声明为NOT NULL,MySQL声明它们为隐式的(并且是沉默的(silently))。一个数据表只能有一个主键.如果你的数据列没有主键而一个应用程序要求访问主键,MySQL返回第一个UNIQUE不包含NULL列的索引作为主键。
●在一个已创建的数据表,PRIMARY KEY排在第一位,后面跟着UNIQUE索引,再后面是非唯一性索引。这帮助MySQL优化器可以安排使用索引的优先顺序,并且可以更快的检测到有没有复制的唯一键。
●一个主键可以是一个多列索引。然而,你不能使用一个数据列定义中的主键属性来创建一个多列索引。这么做的结果是使那个列成为主键。你必须使用一个PRIMARY KEY(index_col_name,...)分句。
●在MySQL5.0中,只有MyISAM,InnoDB,DBD,和MEMORY存储引擎支持在空值列上使用索引。其他情况下,你必须声明索引的数据列为非空的,否则将产生一个错误。
●在指定一个索引时使用col_name(length)句法,你可以创建一个只使用CHAR或VARCHAR数据列的前length个字符的索引。只索引数据列值的前缀可以使这个索引文件小得多。See Section 7.4.3, “Column Indexes”.
MyISAM和InnoDB存储引擎也支持对BLOB和TEXT数据列的索引。当索引一个BLOB或TEXT数据列时,你必须指定该索引一个前缀长度。例如:
CREATE TABLE test (blob_col BLOB, INDEX(blob_col(10)));
前缀可以最高达到1000字节长(InnoDB数据列是767字节)。注意,前缀限制是用字节衡量的,然而CREATE TABLE声明中的前缀长度表示为一个字符个数。当指定一个使用多字节字符集的数据列的前缀长度时要确保把这个考虑在内。
●一个index_col_name指定可以以ASC或DESC结尾。这些关键字允许为未来的扩展指定升序或降序索引值存储。当前它们可以解析但被忽略,索引值通常是升序排列的。
●当你在一个TEXT或BLOB列上使用的SELECT语句中使用ORDER BY或者GROUP BY,服务器只使用max_sort_length系统变量中的初始字节数对值进行排序。
●你可以创建特殊的FULLTEXT索引,它可以用于全文索引搜索。只有MyISAM数据表类型支持FULLTEXT索引。它们只可以从CHAR,VARCHAR,和TEXT数据列创建。索引总是在整个数据列中发生;部分索引没有被支持,而且任何指定的前缀长度都被忽略。See Section 12.7, “Full-Text Search Functions” for details of operation.
●InnoDB数据表支持检察外间约束。See Section 14.2, “The InnoDB Storage Engine”. 注意InnoDB中的FOREIGN KEY句法要比这部分开始时的CREATE TABLE声明给出的句法更受约束:相关数据表的数据列必须是显式命名的。InnoDB支持对外键的ON DELETE和ON UPDATE操作。For the precise syntax, see Section 14.2.6.4, “FOREIGN KEY Constraints”.
对于其他存储引擎,MySQL解析CREATE TABLE声明中的FOREIGN KEY和REFERENCES句法,但不会采取更多的操作。所有存储引擎都解析但是忽略CHECK分句。See Section 1.8.5.5, “Foreign Keys”.
其他数据表选项用来优化对数据表的操作。在多数情况下,你不必指定它们中的任何一个。这些选项可以为所有存贮引擎工作,除非另外说明。
(略)
通过在CREATE TABLE声明尾部添加一个SELECT声明,你可以从另一个数据表创建一个数据表:
CREATE TABLE new_tbl SELECT * FROM orig_tbl;
MySQL为SELECT中的所有元素创建新的数据列。例如:
mysql> CREATE TABLE test (a INT NOT NULL AUTO_INCREMENT,
-> PRIMARY KEY (a), KEY(b))
-> ENGINE=MyISAM SELECT b,c FROM test2;
着创建一个三列的MyISAM数据表,a,b,和c。注意SELECT声明中的数据列示附加到数据表的右侧的,不适重叠到其中。看看下面的例子:
mysql> SELECT * FROM foo;
+----+
| n |
+----+
| 1 |
+----+
mysql> CREATE TABLE bar (m INT) SELECT n FROM foo;
Query OK, 1 row affected (0.02 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> SELECT * FROM bar;
+------+---+
| m | n |
+------+---+
| NULL | 1 |
+------+---+
1 row in set (0.00 sec)
对数据表foo中的每行,使用从foo中选择的值在bar中插入了一行,并且为新列添加了默认值。
在一个从CREATE TABLE ... SELECT得到的数据表中,先使用只在CREATE TABLE部分中为数据列定义的名称。再使用同时在两个部分中或者只在CREATE TABLE部分中为数据列定义的名称。SELECT数据列的列类型可以在CREATE TABLE部分指定的数据列重写。
如果在拷贝期间引发了任何错误,它会自动丢弃数据并且不再创建数据表。
CREATE TABLE ... SELECT不会自动为你创建索引。有意这样做的目的是使声明尽量灵活。如果你希望在创建的数据表中拥有索引,你应该在SELECT声明之前指定这些:
mysql> CREATE TABLE bar (UNIQUE (n)) SELECT n FROM foo;
对一些数据列类型可能会引发类型转换。例如,AUTO_INCREMENT属性不会保留,而且VARCHAR列可能会变成CHAR列。
当使用CREATE ... SELECT来创建一个数据表时,确保对查询中的任何方法调用或表达式使用别名。如果你没有,CREATE声明可能会失败或者产生不希望得到的列名。
CREATE TABLE artists_and_works
SELECT artist.name, COUNT(work.artist_id) AS number_of_works
FROM artist LEFT JOIN work ON artist.id = work.artist_id
GROUP BY artist.id;
你也可以显式指定一个声称列的类型:
CREATE TABLE foo (a TINYINT NOT NULL) SELECT b+1 AS a FROM bar;
使用LIKE来根据其他数据表创建一个空的数据表,包含在原始表中定义的任何数据列属性和索引:
CREATE TABLE new_tbl LIKE orig_tbl;
CREATE TABLE ... LIKE不会拷贝在原始表中指定的任何DATA DIRECTORY或INDEX DIRECTORY表选项,或者任何外键定义。
你可以在SELECT之前使用IGNORE或REPLACE来说明怎样处理复制唯一键值的记录。使用IGNORE,复制已存在含有唯一键值的记录的新记录将被丢弃。使用REPLACE,新记录将替换含有相同的唯一键值的记录。如果没有指定IGNORE或REPLACE,复制唯一键值将产生一个错误。
为了确保更新日志和二进制日志(update log/binary log)可以用来重建原始数据表,在CREATE TABLE ... SELECT期间,MySQL不允许同时进行插入操作。
13.1.5.1. 沉默(Silent)列设置改变
在一些情况下,MySQL沉默的改变了那些在CREATE TABLE或ALTER TABLE声明中指定的列设置。这可能是改变一个列的数据类型,或者改变与一个数据列相关的属性,又或者改变一个索引设置。
下面列出了可能的对数据类型的改变。这些发生在MySQL5.0.3之前的版本。对于MySQL5.0.3,如果一个数据列不能用给定的数据类型创建,则引发一个错误。
●长度小于4的VARCHAR数据列自动转换为CHAR类型。
●如果一个数据表中的任何一个列为可变长度,则整个数据行都是可变长度。因此,如果一个数据表包含任何可变长度的列(VARCHAR,TEXT,或BLOB),所有长度大于3的CHAR列都转换为VARCHAR列。这不会影响你使用这些数据列,在MySQL中,VARCHAR只是存储字符的另一个方法罢了。MySQL作这样的转换的目的是节省空间并且使数据表操作更快。See Chapter 14, Storage Engines and Table Types.
●在MySQL5.0.3之前的版本中,一个指定长度大于255的CHAR或VARCHAR列会被转换成TEXT类型来保存给定的长度。例如,VARCHAR(500)会被转换成TEXT,而VARCHAR(200000)会被转换成MEDIUMTEXT。注意这个转换将导致对尾部空间的处理。
相似的转换也发生在BINARY和VARBINARY类型中,除非它们被转换成一个BLOB类型。
从MySQL5.0.3开始,一个指定长度大于255的CHAR或VARCHAR列不会被沉默的转换。而会引发一个错误。从MySQL5.0.6开始,如果不及或严格SQL模式对指定长度大于65,535的VARCHAR和VARBINARY的沉默转换不会发生。而是引发一个错误。
● 对于一个DECIMAL(M,D)指定,如果M不大于D,它会向上调整。例如,DECIMAL(10,10)会变成DECIMAL(11,10)。
其他沉默列设置包括对属性或索引设置的改变:
●TIMESTAMP显示大小被丢弃。注意TIMESTAMP列在最近的MySQL版本(直到5.0)中有很大的改变;要得到这些改变的描述,见MySQL4.1手册。
●作为PRIMARY KEY的一部分的数据列都设为NOT NULL,即使它们没有这样设置。
●当数据表创建时,尾部空间将自动从ENUM和SET成员值删除。
●MysQL设置其他SQL数据库提供商使用的某种列类型为MySQL类型。See Section 11.7, “Using Column Types from Other Database Engines”.
●如果你包含了一个USING分句来指定一个对于一个给定存储引擎不合法的索引类型,但是有其他引擎可用的不会影响查询结果的索引类型,引擎将使用可用的类型。
要想看是否MySQL使用了一个列类型代替了你指定的类型,在创建或修改数据表之后,发出DESCRIBE或SHOW CREATE TABLE声明来查看。
如果你使用myisampack来压缩一个数据表,可能会发生某种其它列类型改变。See Section 14.1.3.3, “Compressed Table Characteristics”.
13.1.6.DROP DATABASE句法
DROP {DATABASE | SCHEMA} [IF EXISTS] db_name
DROP DATABASE删除所有在这个数据库中的数据表并删除这个数据库。使用这个声明时要非常小心!要使用DROP DATABASE,你需要对数据库有DROP权限。
IF EXIST用来在数据库不存在的时候引发一个错误。
自MySQL5.0.2后的版本中可以使用DROP SCHEMA。
如果你在一个连接的数据库上使用DROP DATABASE,连接的和原始的数据库将被同时删除掉。
DROP DATABASE返回被删除的数据表的数目。这和删除.frm文件的数目是对应的。
DROP DATABASE声明从给定数据库文件夹中删除那些文件和文件夹,这些文件和文件夹可能是MySQL自己在正常操作中创建的:
●所有文件包含这些扩展名:.BAK,.DAT,.HSH,.MRG,.MYD,.ISD,.MYI,.db,.frm。
●所有子文件夹的名字都由十六进制数字00-ff组成。这些字文件夹是给RAID数据表用的。(当对RAID数据表的支持删除时,这些文件夹没有像MySQL5.0中那样删除。在升级到MySQL5.0之前,你应该转换已存在的RAID数据表而后手动删除这些文件夹。See Section 2.10.2, “Upgrading from Version 4.1 to 5.0”)
在MySQL删除刚刚列出的文件之后,如果还有其它文件或文件夹存在于数据库文件夹中,数据库文件夹就不能够被删除。在这种情况下,你必须手动删除所有存留的文件或文件夹,然后再发出一次DROP DATABASE声明。
你也可以使用mysqladmin来删除数据库。See Section 8.5, “mysqladmin — Client for Administering a MySQL Server”.
13.1.7.DROP INDEX句法
DROP INDEX index_name ON tbl_name
DROP INDEX从名为tbl_name的数据表中删除名为index_name的索引。这个声明被映射在ALTER TABLE声明中来删除一个索引。See Section 13.1.2, “ALTER TABLE Syntax”.
13.1.8.DROP TABLE句法
DROP [TEMPORARY] TABLE [IF EXISTS]
tbl_name [, tbl_name] ...
[RESTRICT | CASCADE]
DROP TABLE删除一个或多个数据表。你必须有对每个数据表的DROP权限。所有数据表数据和数据表定义都被删除,索引使用这个声明时要小心!
使用IF EXISTS来阻止由于数据表不存在而引发的错误。当时用IF EXISTS时对每个不存在的数据表生成一条记录。 See Section 13.5.4.22, “SHOW WARNINGS Syntax”.
RESTRICT和CASCADE可以允许端口操作(porting)更容易。在目前,它们什么也不做。
注意:DROP TABLE自动地做当前的活动事务处理,除非你使用了TEMPORARY关键字。
TEMPORARY关键字将产生后面的影响:
●这个声明只删除TEMPORARY数据表。
●这个声明不会停止正在运行的事务处理。
●不做存取权限的检查。(一个TEMPORARY数据表只会对创建它的客户端是可见的,所以没必要作存取权限的检查)
使用TEMPOARY是确保你不会误删一个非临时数据表的的好方法。
13.1.9.RENAME TABLE句法
RENAME TABLE tbl_name TO new_tbl_name
[, tbl_name2 TO new_tbl_name2] ...
这个声明重命名一个或多个数据表。
重命名操作是自动完成的,这意味着当重命名正在操作时,其它线程都不能够读取这些数据表中的任何一个。例如,你有一个已存在的数据表old_table,你可以创建另一个结构相同但为空的数据表new_table,而后用空的数据表来替换已存在的数据表如下:
CREATE TABLE new_table (...);
RENAME TABLE old_table TO backup_table, new_table TO old_table;
如果声明重命名超过一个数据表,重命名操作从左到右来完成。如果你希望交换两个数据表名,你可以这样来做(假设没有名为tmp_table的数据表存在):
RENAME TABLE old_table TO tmp_table,
new_table TO old_table,
tmp_table TO new_table;
只要两个数据库存在于一个文件系统中,你也可以重命名一个数据表来把它从一个数据库移动到另一个数据库:
RENAME TABLE current_db.tbl_name TO other_db.tbl_name;
当你执行RENAME时,你不能有任何锁定的数据表或者活动事务处理。你也必须有对原数据表的ALTER和DROP权限,而且有对新数据表的CREATE和INSERT权限。
如果MySQL在一个多数据表重命名中遇到任何错误,它对所有命名的数据表执行一个逆重命名来使所有改变返回它的初始状态。
自MySQL5.0.14开始,RENAME TABLE也在数据视图上工作,只要你不会试图重命名一个数据视图到另一个数据库中。