ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
### 第11章:列类型 MySQL支持多种列类型:数值类型、日期/时间类型和字符串(字符)类型。本章首先对这些列类型进行了概述,然后更加详细地描述了各种列的类型,以及列类型存储需求的总结。概述很简单。关于具体列类型的详细信息应查阅详细的描述,例如指定值时允许使用的格式。 MySQL支持处理空间数据的扩展名。关于空间类型的信息参见[第19章:](#)[_MySQL中的空间扩展_](# "Chapter 19. Spatial Extensions in MySQL")。 几种列类型描述使用了下述惯例: ·         _M_ 表示最大显示宽度。最大有效显示宽度是255。 ·         _D_ 适用于浮点和定点类型,并表示小数点后面的位数。最大可能的值是30,但不应大于_M_-2。 ·         方括号(‘[’和‘]’)表示可选部分。 ### 11.1. 列类型概述 [ 11.1.1. 数值类型概述](#)[ 11.1.2. 日期和时间类型概述](#)[ 11.1.3. 字符串类型概述](#) ### 11.1.1. 数值类型概述 下面为数值列类型的概述。详细信息参见[11.2节,“数值类型”](# "11.2. Numeric Types")。列存储需求参见[11.5节,“列类型存储需求”](# "11.5. Column Type Storage Requirements")。 _M_指示最大显示宽度。最大有效显示宽度是255。显示宽度与存储大小或类型包含的值的范围无关,相关描述见[11.2节,“数值类型”](# "11.2. Numeric Types")。 如果为一个数值列指定ZEROFILL,MySQL自动为该列添加UNSIGNED属性。 SERIAL是BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE的一个别名。 在整数列定义中,SERIAL DEFAULT VALUE是NOT NULL AUTO_INCREMENT UNIQUE的一个别名。 **警告:**应当清楚,当使用在整数值(其中一个是UNSIGNED类型)之间使用减号时,结果是无符号。参见[12.8节,“Cast函数和操作符”](# "12.8. Cast Functions and Operators")。 ·         BIT[(_M_)] 位字段类型。_M_表示每个值的位数,范围为从1到64。如果_M_被省略, 默认为1。 ·         TINYINT[(_M_)] [UNSIGNED] [ZEROFILL] 很小的整数。带符号的范围是-128到127。无符号的范围是0到255。 ·         BOOL,BOOLEAN 是TINYINT(1)的同义词。zero值被视为假。非zero值视为真。 在将来,将根据标准SQL引入完全布尔类型的处理。 ·         SMALLINT[(_M_)] [UNSIGNED] [ZEROFILL] 小的整数。带符号的范围是-32768到32767。无符号的范围是0到65535。 ·         MEDIUMINT[(_M_)] [UNSIGNED] [ZEROFILL] 中等大小的整数。带符号的范围是-8388608到8388607。无符号的范围是0到16777215。 ·         INT[(_M_)] [UNSIGNED] [ZEROFILL] 普通大小的整数。带符号的范围是-2147483648到2147483647。无符号的范围是0到4294967295。 ·         INTEGER[(_M_)] [UNSIGNED] [ZEROFILL] 这是INT的同义词。 ·         BIGINT[(_M_)] [UNSIGNED] [ZEROFILL] 大整数。带符号的范围是-9223372036854775808到9223372036854775807。无符号的范围是0到18446744073709551615。 应清楚BIGINT列的下述内容: o        使用带符号的BIGINT或DOUBLE值进行所有算法,因此除了位函数,不应使用大于9223372036854775807(63位)的无符号的大整数! 如果这样做,结果中的最后几位可能出错,这是由于将BIGINT值转换为DOUBLE进行四舍五入时造成的错误。 MySQL可以在以下情况下处理BIGINT: §         当使用整数在一个BIGINT列保存大的无符号的值时。 §         在MIN(_col_name_)或MAX(_col_name_)中,其中_col_name_指BIGINT列。 §         使用操作符(+,-,*等等)并且两个操作数均为整数时。 o        总是可以使用一个字符串在BIGINT列中保存严格整数值。在这种情况下,MySQL执行字符串-数字转换,其间不存在双精度表示。 o        当两个操作数均为整数值时,-、+和*操作符使用BIGINT算法。这说明如果乘两个大整数(或来自返回整数的函数),当结果大于9223372036854775807时,会得到意想不到的结果。 ·         FLOAT[(_M_,_D_)] [UNSIGNED] [ZEROFILL] 小(单精度)浮点数。允许的值是-3.402823466E+38到-1.175494351E-38、0和1.175494351E-38到3.402823466E+38。这些是理论限制,基于IEEE标准。实际的范围根据硬件或操作系统的不同可能稍微小些。 _M_是小数纵位数,_D_是小数点后面的位数。如果_M_和_D_被省略,根据硬件允许的限制来保存值。单精度浮点数精确到大约7位小数位。 如果指定UNSIGNED,不允许负值。 使用浮点数可能会遇到意想不到的问题,因为在MySQL中的所有计算用双精度完成。参见[A.5.7节,“解决与不匹配行有关的问题”](# "A.5.7. Solving Problems with No Matching Rows")。 ·         DOUBLE[(_M_,_D_)] [UNSIGNED] [ZEROFILL] 普通大小(双精度)浮点数。允许的值是-1.7976931348623157E+308到-2.2250738585072014E-308、0和2.2250738585072014E-308到 1.7976931348623157E+308。这些是理论限制,基于IEEE标准。实际的范围根据硬件或操作系统的不同可能稍微小些。 _M_是小数总位数,_D_是小数点后面的位数。如果_M_和_D_被省略,根据硬件允许的限制来保存值。双精度浮点数精确到大约15位小数位。 如果指定UNSIGNED,不允许负值。 ·         DOUBLE PRECISION[(_M_,_D_)] [UNSIGNED] [ZEROFILL], REAL[(_M_,_D_)] [UNSIGNED] [ZEROFILL] 为DOUBLE的同义词。除了:如果SQL服务器模式包括REAL_AS_FLOAT选项,REAL是FLOAT的同义词而不是DOUBLE的同义词。 ·         FLOAT(_p_) [UNSIGNED] [ZEROFILL] 浮点数。_p_表示精度(以位数表示),但MySQL只使用该值来确定是否结果列的数据类型为FLOAT或DOUBLE。如果_p_为从0到24,数据类型变为没有_M_或_D_值的FLOAT。如果_p_为从25到53,数据类型变为没有_M_或_D_值的DOUBLE。结果列范围与本节前面描述的单精度FLOAT或双精度DOUBLE数据类型相同。 FLOAT(_p_)语法与ODBC兼容。 ·         DECIMAL[(_M_[,_D_])] [UNSIGNED] [ZEROFILL] 压缩的“严格”定点数。_M_是小数位数(精度)的总数,_D_是小数点(标度)后面的位数。小数点和(负数)的‘-’符号不包括在_M_中。如果_D_是0,则值没有小数点或分数部分。DECIMAL整数最大位数(_M_)为65。支持的十进制数的最大位数(_D_)是30。如果_D_被省略, 默认是0。如果_M_被省略, 默认是10。 如果指定UNSIGNED,不允许负值。 所有DECIMAL列的基本计算(+,-,*,/)用65位精度完成。 ·         DEC[(_M_[,_D_])] [UNSIGNED] [ZEROFILL], NUMERIC[(_M_[,_D_])] [UNSIGNED] [ZEROFILL], FIXED[(_M_[,_D_])] [UNSIGNED] [ZEROFILL] 是DECIMAL的同义词。FIXED同义词适用于与其它服务器的兼容性。 ### 11.1.2. 日期和时间类型概述 本节综合讨论了临时列类型。详细信息,参见[11.3节,“日期和时间类型”](# "11.3. Date and Time Types")。列存储需求参见[11.5节,“列类型存储需求”](# "11.5. Column Type Storage Requirements")。 ·         DATE 日期。支持的范围为'1000-01-01'到'9999-12-31'。MySQL以'YYYY-MM-DD'格式显示DATE值,但允许使用字符串或数字为DATE列分配值。 ·         DATETIME 日期和时间的组合。支持的范围是'1000-01-01 00:00:00'到'9999-12-31 23:59:59'。MySQL以'YYYY-MM-DD HH:MM:SS'格式显示DATETIME值,但允许使用字符串或数字为DATETIME列分配值。 ·         TIMESTAMP[(_M_)] 时间戳。范围是'1970-01-01 00:00:00'到2037年。 TIMESTAMP列用于INSERT或UPDATE操作时记录日期和时间。如果你不分配一个值,表中的第一个TIMESTAMP列自动设置为最近操作的日期和时间。也可以通过分配一个NULL值,将TIMESTAMP列设置为当前的日期和时间。 TIMESTAMP值返回后显示为'YYYY-MM-DD HH:MM:SS'格式的字符串,显示宽度固定为19个字符。如果想要获得数字值,应在TIMESTAMP 列添加+0。 **注释:**MySQL 4.1以前使用的TIMESTAMP格式在MySQL 5.1中不支持;关于旧格式的信息参见_MySQL 4.1 参考手册_。 ·         TIME 时间。范围是'-838:59:59'到'838:59:59'。MySQL以'HH:MM:SS'格式显示TIME值,但允许使用字符串或数字为TIME列分配值。 ·         YEAR[(2|4)] 两位或四位格式的年。默认是四位格式。在四位格式中,允许的值是1901到2155和0000。在两位格式中,允许的值是70到69,表示从1970年到2069年。MySQL以YYYY格式显示YEAR值,但允许使用字符串或数字为YEAR列分配值。 ### 11.1.3. 字符串类型概述 本节综合讨论了字符串列类型。详细信息参见[11.4节,“String类型”](# "11.4. String Types")。列存储需求参见[11.5节,“列类型存储需求”](# "11.5. Column Type Storage Requirements")。 在某些情况中,MySQL可以将一个字符串列更改为不同于CREATE TABLE或ALTER TABLE语句中所给出的类型。参见[13.1.5.1节,“沉寂的列规格变更”](# "13.1.5.1. Silent Column Specification Changes")。 MySQL 5.1字符串数据类型包括部分在MySQL 4.1之前的版本中没有的特性: ·         许多字符串数据类型的列定义可以包括指定字符集的CHARACTER SET属性,也可能包括校对规则。(CHARSET是CHARACTER SET的一个同义词)。这些属性适用于CHAR、VARCHAR、TEXT类型、ENUM和SET。例如: ·                CREATE TABLE t ·                ( ·                    c1 CHAR(20) CHARACTER SET utf8, ·                    c2 CHAR(20) CHARACTER SET latin1 COLLATE latin1_bin ·                ); 该表定义创建了一个名为c1的列,具有一个utf8字符集和该字符集的默认 校对规则,和一个名为c2的列以及latin1字符集和该字符集的二元 校对规则。二元校对规则对大小写不敏感。 ·         MySQL 5.1用字符单位解释在字符列定义中的长度规范。(以前的一些MySQL版本以字节解释长度)。 ·         对于CHAR、VARCHAR和TEXT类型,BINARY属性可以为列分配该列字符集的 校对规则。 ·         字符列的排序和比较基于分配给列的字符集。在以前的版本中,排序和比较基于服务器字符集的校对规则。对于CHAR和VARCHAR列,你可以用BINARY属性声明列让排序和 校对规则使用当前的字符代码值而不是词汇顺序。 关于MySQL 5.1中字符集的支持,参见[第10章:](#)[_字符集支持_](# "Chapter 10. Character Set Support")。 ·         [NATIONAL] CHAR(_M_) [BINARY| ASCII | UNICODE] 固定长度字符串,当保存时在右侧填充空格以达到指定的长度。_M_表示列长度。_M_的范围是0到255个字符。 **注释:**当检索CHAR值时尾部空格被删除。 如果想要将某个CHAR的长度设为大于255,执行的CREATE TABLE或ALTER TABLE语句将失败并提示错误: mysql> CREATE TABLE c1 (col1 INT, col2 CHAR(500)); ERROR 1074 (42000): Column length too big for column 'col' (max = 255); use BLOB or TEXT instead mysql> SHOW CREATE TABLE c1; ERROR 1146 (42S02): Table 'test.c1' doesn't exist CHAR是CHARACTER的简写。NATIONAL CHAR(或其等效短形式NCHAR)是标准的定义CHAR列应使用 默认字符集的SQL方法。这在MySQL中为默认值。 BINARY属性是指定列字符集的二元 校对规则的简写。排序和比较基于数值字符值。 列类型CHAR BYTE是CHAR BINARY的一个别名。这是为了保证兼容性。 可以为CHAR指定ASCII属性。它分配latin1字符集。 可以为CHAR指定UNICODE属性。它分配ucs2字符集。 MySQL允许创建类型CHAR(0)的列。这主要用于必须有一个列但实际上不使用值的旧版本的应用程序相兼容。当你需要只能取两个值的列时也很好:没有定义为NOT NULL的一个CHAR(0)列只占用一位,只可以取值NULL和''(空字符串)。 ·         CHAR 这是CHAR(1)的同义词。 ·         [NATIONAL] VARCHAR(_M_) [BINARY] 变长字符串。_M_表示最大列长度。_M_的范围是0到65,535。(VARCHAR的最大实际长度由最长的行的大小和使用的字符集确定。最大_有效_长度是65,532字节)。 **注释:**MySQL 5.1遵从标准SQL规范,并且不删除VARCHAR值的尾部空格。 VARCHAR是字符VARYING的简写。 BINARY属性是指定列的字符集的二元 校对规则的简写。排序和比较基于数值字符值。 VARCHAR保存时用一个字节或两个字节长的前缀+数据。如果VARCHAR列声明的长度大于255,长度前缀是两个字节。 ·         BINARY(_M_) BINARY类型类似于CHAR类型,但保存二进制字节字符串而不是非二进制字符串。 ·         VARBINARY(_M_) VARBINARY类型类似于VARCHAR类型,但保存二进制字节字符串而不是非二进制字符串。 ·         TINYBLOB 最大长度为255(28–1)字节的BLOB列。 ·         TINYTEXT 最大长度为255(28–1)字符的TEXT列。 ·         BLOB[(_M_)] 最大长度为65,535(216–1)字节的BLOB列。 可以给出该类型的可选长度_M_。如果给出,则MySQL将列创建为最小的但足以容纳_M_字节长的值的BLOB类型。 ·         TEXT[(_M_)] 最大长度为65,535(216–1)字符的TEXT列。 可以给出可选长度_M_。则MySQL将列创建为最小的但足以容纳_M_字符长的值的TEXT类型。 ·         MEDIUMBLOB 最大长度为16,777,215(224–1)字节的BLOB列。 ·         MEDIUMTEXT 最大长度为16,777,215(224–1)字符的TEXT列。 ·         LONGBLOB 最大长度为4,294,967,295或4GB(232–1)字节的BLOB列。LONGBLOB列的最大_有效_(允许的)长度取决于客户端/服务器协议中配置最大包大小和可用的内存。 ·         LONGTEXT 最大长度为4,294,967,295或4GB(232–1)字符的TEXT列。LONGTEXT列的最大_有效_(允许的)长度取决于客户端/服务器协议中配置最大包大小和可用的内存。 ·         ENUM('_value1_','_value2_',...) 枚举类型。只能有一个值的字符串,从值列'_value1_','_value2_',...,NULL中或特殊 ''错误值中选出。ENUM列最多可以有65,535个截然不同的值。ENUM值在内部用整数表示。 ·         SET('_value1_','_value2_',...) 一个设置。字符串对象可以有零个或多个值,每个值必须来自列值'_value1_','_value2_',...SET列最多可以有64个成员。SET值在内部用整数表示。 ### 11.2. 数值类型 MySQL支持所有标准SQL数值数据类型。这些类型包括严格数值数据类型(INTEGER、SMALLINT、DECIMAL和NUMERIC),以及近似数值数据类型(FLOAT、REAL和DOUBLE PRECISION)。关键字INT是INTEGER的同义词,关键字DEC是DECIMAL的同义词。 BIT数据类型保存位字段值,并且支持MyISAM、MEMORY、InnoDB和BDB表。 作为SQL标准的扩展,MySQL也支持整数类型TINYINT、MEDIUMINT和BIGINT。下面的表显示了需要的每个整数类型的存储和范围。 <table border="1" cellpadding="0" id="table1"><tr><td> <p><strong><span>类型</span></strong></p></td> <td> <p><strong><span>字节</span></strong></p></td> <td> <p><strong><span>最小值</span></strong></p></td> <td> <p><strong><span>最大值</span></strong></p></td> </tr><tr><td> <p><span> </span></p></td> <td> <p><span> </span></p></td> <td> <p><strong> <span>(</span><span>带符号的<span>/</span>无符号的<span>)</span></span></strong></p></td> <td> <p><strong> <span>(</span><span>带符号的<span>/</span>无符号的<span>)</span></span></strong></p></td> </tr><tr><td> <p> <span>TINYINT</span></p></td> <td> <p><span>1</span></p></td> <td> <p> <span>-128</span></p></td> <td> <p> <span>127</span></p></td> </tr><tr><td> <p><span> </span></p></td> <td> <p><span> </span></p></td> <td> <p> <span>0</span></p></td> <td> <p> <span>255</span></p></td> </tr><tr><td> <p> <span>SMALLINT</span></p></td> <td> <p><span>2</span></p></td> <td> <p> <span>-32768</span></p></td> <td> <p> <span>32767</span></p></td> </tr><tr><td> <p><span> </span></p></td> <td> <p><span> </span></p></td> <td> <p> <span>0</span></p></td> <td> <p> <span>65535</span></p></td> </tr><tr><td> <p> <span>MEDIUMINT</span></p></td> <td> <p><span>3</span></p></td> <td> <p> <span>-8388608</span></p></td> <td> <p> <span>8388607</span></p></td> </tr><tr><td> <p><span> </span></p></td> <td> <p><span> </span></p></td> <td> <p> <span>0</span></p></td> <td> <p> <span>16777215</span></p></td> </tr><tr><td> <p> <span>INT</span></p></td> <td> <p><span>4</span></p></td> <td> <p> <span>-2147483648</span></p></td> <td> <p> <span>2147483647</span></p></td> </tr><tr><td> <p><span> </span></p></td> <td> <p><span> </span></p></td> <td> <p> <span>0</span></p></td> <td> <p> <span>4294967295</span></p></td> </tr><tr><td> <p> <span>BIGINT</span></p></td> <td> <p><span>8</span></p></td> <td> <p> <span>-9223372036854775808</span></p></td> <td> <p> <span>9223372036854775807</span></p></td> </tr><tr><td> <p><span> </span></p></td> <td> <p><span> </span></p></td> <td> <p> <span>0</span></p></td> <td> <p> <span>18446744073709551615</span></p></td> </tr></table> MySQL还支持选择在该类型关键字后面的括号内指定整数值的显示宽度(例如,INT(4))。该可选显示宽度规定用于显示宽度小于指定的列宽度的值时从左侧填满宽度。 显示宽度并不限制可以在列内保存的值的范围,也不限制超过列的指定宽度的值的显示。 当结合可选扩展属性ZEROFILL使用时, 默认补充的空格用零代替。例如,对于声明为INT(5) ZEROFILL的列,值4检索为00004。请注意如果在整数列保存超过显示宽度的一个值,当MySQL为复杂联接生成临时表时会遇到问题,因为在这些情况下MySQL相信数据适合原列宽度。 所有整数类型可以有一个可选(非标准)属性UNSIGNED。当你想要在列内只允许非负数和该列需要较大的上限数值范围时可以使用无符号值。 浮点和定点类型也可以为UNSIGNED。同数类型,该属性防止负值保存到列中。然而,与整数类型不同的是,列值的上范围保持不变。 如果为一个数值列指定ZEROFILL,MySQL自动为该列添加UNSIGNED属性。 对于浮点列类型,在MySQL中单精度值使用4个字节,双精度值使用8个字节。 FLOAT类型用于表示近似数值数据类型。SQL标准允许在关键字FLOAT后面的括号内选择用位指定精度(但不能为指数范围)。MySQL还支持可选的只用于确定存储大小的精度规定。0到23的精度对应FLOAT列的4字节单精度。24到53的精度对应DOUBLE列的8字节双精度。 MySQL允许使用非标准语法:FLOAT(_M_,_D_)或REAL(_M_,_D_)或DOUBLE PRECISION(_M_,_D_)。这里,“(_M_,_D_)”表示该值一共显示_M_位整数,其中_D_位位于小数点后面。例如,定义为FLOAT(7,4)的一个列可以显示为-999.9999。MySQL保存值时进行四舍五入,因此如果在FLOAT(7,4)列内插入999.00009,近似结果是999.0001。 MySQL将DOUBLE视为DOUBLE PRECISION(非标准扩展)的同义词。MySQL还将REAL视为DOUBLE PRECISION(非标准扩展)的同义词,除非SQL服务器模式包括REAL_AS_FLOAT选项。 为了保证最大可能的可移植性,需要使用近似数值数据值存储的代码应使用FLOAT或DOUBLE PRECISION,不规定精度或位数。 DECIMAL和NUMERIC类型在MySQL中视为相同的类型。它们用于保存必须为确切精度的值,例如货币数据。当声明该类型的列时,可以(并且通常要)指定精度和标度;例如: salary DECIMAL(5,2) 在该例子中,5是精度,2是标度。精度表示保存值的主要位数,标度表示小数点后面可以保存的位数。 在MySQL 5.1中以二进制格式保存DECIMAL和NUMERIC值。 标准SQL要求salary列能够用5位整数位和两位小数保存任何值。因此,在这种情况下可以保存在salary列的值的范围是从-999.99到999.99。 在标准SQL中,语法DECIMAL(_M_)等价于DECIMAL(_M_,0)。同样,语法DECIMAL等价于DECIMAL(_M_,0),可以通过计算确定_M_的值。在MySQL 5.1中支持DECIMAL和NUMERIC数据类型的变量形式。_M_默认值是10。 DECIMAL或NUMERIC的最大位数是65,但具体的DECIMAL或NUMERIC列的实际范围受具体列的精度或标度约束。如果此类列分配的值小数点后面的位数超过指定的标度允许的范围,值被转换为该标度。(具体操作与操作系统有关,但一般结果均被截取到允许的位数)。 BIT数据类型可用来保存位字段值。BIT(_M_)类型允许存储_M_位值。_M_范围为1到64。 要指定位值,可以使用b'_value_'符。_value_是一个用0和1编写的二进制值。例如,b'111'和b'100000000'分别表示7和128。参见[9.1.5节,“位字段值”](# "9.1.5. Bit-Field Values")。 如果为BIT(M)列分配的值的长度小于_M_位,在值的左边用0填充。例如,为BIT(6)列分配一个值b'101',其效果与分配b'000101'相同。 当要在一个数值列内保存一个超出该列允许范围的值时,MySQL的操作取决于此时有效的SQL模式。如果模式未设置,MySQL将值裁剪到范围的相应端点,并保存裁减好的值。但是,如果模式设置为traditional(“严格模式”),超出范围的值将被拒绝并提示错误,并且根据SQL标准插入会失败。参见[5.3.2节,“SQL服务器模式”](# "5.3.2. The Server SQL Mode")。 如果INT列是UNSIGNED,列范围的大小相同,但其端点会变为到0和4294967295。如果你试图保存-9999999999和9999999999,以非严格模式保存到列中的值是0和4294967296。 如果在浮点或定点列中分配的值超过指定(或默认)精度和标度规定的范围,MySQL以非严格模式保存表示范围相应端点的值。 当MySQL没有工作在严格模式时,对于ALTER TABLE、LOAD DATA INFILE、UPDATE和多行INSERT语句,由于裁剪发生的转换将报告为警告。当MySQL工作在严格模式时,这些语句将失败,并且部分或全部值不会插入或更改,取决于是否表为事务表和其它因素。详情参见[5.3.2节,“SQL服务器模式”](# "5.3.2. The Server SQL Mode")。 ### 11.3. 日期和时间类型 [ 11.3.1. DATETIME、DATE和TIMESTAMP类型](#)[ 11.3.2. TIME类型](#)[ 11.3.3. YEAR类型](#)[ 11.3.4. Y2K事宜和日期类型](#) 表示时间值的DATE和时间类型为DATETIME、DATE、TIMESTAMP、TIME和YEAR。每个时间类型有一个有效值范围和一个“零”值,当指定不合法的MySQL不能表示的值时使用“零”值。TIMESTAMP类型有专有的自动更新特性,将在后面描述。 如果试图插入一个不合法的日期,MySQL将给出警告或错误。可以使用ALLOW_INVALID_DATES SQL模式让MySQL接受某些日期,例如'1999-11-31'。当你想要保存一个“可能错误的”用户已经在数据库中指定(例如,以web形式)用于将来处理的值时很有用。在这种模式下,MySQL只验证月范围为从0到12,日范围为从0到31。这些范围可以包括零,因为MySQL允许在DATE或DATETIME列保存日/月和日是零的日期。这在应用程序需要保存一个你不知道确切日期的生日时非常有用。在这种情况下,只需要将日期保存为'1999-00-00'或'1999-01-00'。如果保存此类日期,DATE_SUB()或DATE_ADD等需要完整日期的函数不会得到正确的结果。(如果你不想在日期中出现零,可以使用NO_ZERO_IN_DATE SQL模式)。 MySQL还允许将'0000-00-00'保存为“伪日期”(如果不使用NO_ZERO_DATE SQL模式)。这在某些情况下比使用NULL值更方便(并且数据和索引占用的空间更小)。 将sql_mode系统变量设置为相应模式值,可以更确切你想让MySQL支持哪种日期。参见[5.3.2节,“SQL服务器模式”](# "5.3.2. The Server SQL Mode")。 当使用日期和时间类型时应记住以下几点: ·         MySQL以标准输出格式检索给定日期或时间类型的值,但它尽力解释你指定的各种输入值格式(例如,当你指定一个分配给或与日期或时间类型进行比较的值时)。只支持下面章节中描述的格式。期望你能提供有效值。如果你使用其它格式的值会发生意想不到的结果。 ·         包含两位年值的日期会令人模糊,因为世纪不知道。MySQL使用以下规则解释两位年值: o        70-99范围的年值转换为1970-1999。 o        00-69范围的年值转换为2000-2069。 ·         尽管MySQL尝试解释几种格式的值,日期总是以年-月-日顺序(例如,'98-09-04'),而不是其它地方常用的月-日-年或日-月-年顺序(例如,'09-04-98','04-09-98')。 ·         如果值用于数值上下文中,MySQL自动将日期或时间类型的值转换为数字,反之亦然。 ·         当 MySQL遇到一个日期或时间类型的超出范围或对于该类型不合法的值时(如本节开始所描述),它将该值转换为该类的“零”值。一个例外是超出范围的TIME值被裁剪到TIME范围的相应端点。 下面的表显示了各类“零”值的格式。请注意如果启用NO_ZERO_DATE SQL模式,使用这些值会产生警告。 <table border="1" cellpadding="0" id="table2"><tr><td> <p><strong><span>列类型</span></strong></p></td> <td> <p><strong><span>“</span></strong><span class="quote"><b>零</b></span><strong><span>”值</span></strong></p></td> </tr><tr><td> <p> <span>DATETIME</span></p></td> <td> <p> <span>'0000-00-00 00:00:00'</span></p></td> </tr><tr><td> <p> <span>DATE</span></p></td> <td> <p> <span>'0000-00-00'</span></p></td> </tr><tr><td> <p> <span>TIMESTAMP</span></p></td> <td> <p> <span>00000000000000</span></p></td> </tr><tr><td> <p> <span>TIME</span></p></td> <td> <p> <span>'00:00:00'</span></p></td> </tr><tr><td> <p> <span>YEAR</span></p></td> <td> <p> <span>0000</span></p></td> </tr></table> ·         “零”值是特殊值,但你可以使用表内显示的值显式保存或引用它们。你也可以使用值'0'或0来保存或引用,写起来更容易。 ·         MyODBC中使用的“零”日期或时间值在MyODBC 2.50.12和以上版本中被自动转换为NULL,因为ODBC不能处理此类值。 ### 11.3.1. DATETIME、DATE和TIMESTAMP类型 [11.3.1.1. 自MySQL 4.1以来的TIMESTAMP属性](#) DATETIME、DATE和TIMESTAMP类型是相关的。该节描述了它们的特征,它们的相似点和不同点。 当你需要同时包含日期和时间信息的值时则使用DATETIME类型。MySQL以'YYYY-MM-DD HH:MM:SS'格式检索和显示DATETIME值。支持的范围为'1000-01-01 00:00:00'到'9999-12-31 23:59:59'。(“支持”表示尽管先前的值可能工作,但没有保证)。 当你只需要日期值而不需要时间部分时应使用DATE类型。MySQL用'YYYY-MM-DD'格式检索和显示DATE值。支持的范围是'1000-01-01'到 '9999-12-31'。 TIMESTAMP列类型的属性不固定,取决于MySQL版本和服务器运行的SQL模式。这些属性将在本节后面描述。 可以使用任何常见格式指定DATETIME、DATE和TIMESTAMP值: ·         'YYYY-MM-DD HH:MM:SS'或'YY-MM-DD HH:MM:SS'格式的字符串。允许“不严格”语法:任何标点符都可以用做日期部分或时间部分之间的间割符。例如,'98-12-31 11:30:45'、'98.12.31 11+30+45'、'98/12/31 11*30*45'和'98@12@31 11^30^45'是等价的。 ·         'YYYY-MM-DD'或'YY-MM-DD'格式的字符串。这里也允许使用“不严格的”语法。例如,'98-12-31'、'98.12.31'、'98/12/31'和'98@12@31'是等价的。 ·         'YYYYMMDDHHMMSS'或'YYMMDDHHMMSS'格式的没有间割符的字符串,假定字符串对于日期类型是有意义的。例如,'19970523091528'和'970523091528'被解释为'1997-05-23 09:15:28',但'971122129015'是不合法的(它有一个没有意义的分钟部分),将变为'0000-00-00 00:00:00'。 ·         'YYYYMMDD'或'YYMMDD'格式的没有间割符的字符串,假定字符串对于日期类型是有意义的。例如,'19970523'和'970523'被解释为 '1997-05-23',但'971332'是不合法的(它有一个没有意义的月和日部分),将变为'0000-00-00'。 ·         YYYYMMDDHHMMSS或YYMMDDHHMMSS格式的数字,假定数字对于日期类型是有意义的。例如,19830905132800和830905132800被解释为 '1983-09-05 13:28:00'。 ·         YYYYMMDD或YYMMDD格式的数字,假定数字对于日期类型是有意义的。例如,19830905和830905被解释为'1983-09-05'。 ·         函数返回的结果,其值适合DATETIME、DATE或者TIMESTAMP上下文,例如NOW()或CURRENT_DATE。 无效DATETIME、DATE或者TIMESTAMP值被转换为相应类型的“零”值('0000-00-00 00:00:00'、'0000-00-00'或者00000000000000)。 对于包括日期部分间割符的字符串值,如果日和月的值小于10,不需要指定两位数。'1979-6-9'与'1979-06-09'是相同的。同样,对于包括时间部分间割符的字符串值,如果时、分和秒的值小于10,不需要指定两位数。'1979-10-30 1:2:3'与'1979-10-30 01:02:03'相同。 数字值应为6、8、12或者14位长。如果一个数值是8或14位长,则假定为YYYYMMDD或YYYYMMDDHHMMSS格式,前4位数表示年。如果数字 是6或12位长,则假定为YYMMDD或YYMMDDHHMMSS格式,前2位数表示年。其它数字被解释为仿佛用零填充到了最近的长度。 指定为非限定符字符串的值使用给定的长度进行解释。如果字符串为8或14字符长,前4位数表示年。否则,前2位数表示年。从左向右解释字符串内出现的各部分,以发现年、月、日、小时、分和秒值。这说明不应使用少于6字符的字符串。例如,如果你指定'9903',认为它表示1999年3月,MySQL将在你的表内插入一个“零”日期值。这是因为年和月值是99和03,但日部分完全丢失,因此该值不是一个合法的日期。但是,可以明显指定一个零值来代表缺少的月或日部分。例如,可以使用'990300'来插入值'1999-03-00'。 在一定程度上,可以将一个日期类型的值分配给一个不同的日期类型。但是,值可能会更改或丢失一些信息: ·         如果你为一个DATETIME或TIMESTAMP对象分配一个DATE值,结果值的时间部分被设置为'00:00:00',因为DATE值未包含时间信息。 ·         如果你为一个DATE对象分配一个DATETIME或TIMESTAMP值,结果值的时间部分被删除,因为DATE值未包含时间信息。 ·         记住尽管可以使用相同的格式指定DATETIME、DATE和TIMESTAMP值,不同类型的值的范围却不同。例如,TIMESTAMP值不能早于1970或晚于2037。这说明一个日期,例如'1968-01-01',虽然对于DATETIME或DATE值是有效的,但对于TIMESTAMP值却无效,如果分配给这样一个对象将被转换为0。 当指定日期值时请注意某些缺陷: ·         指定为字符串的值允许的非严格格式可能会欺骗。例如,值'10:11:12'由于‘:’间割符看上去可能象时间值,但如果用于日期上下文值则被解释为年'2010-11-12'。值'10:45:15'被转换为'0000-00-00'因为'45'不是合法月。 ·         在非严格模式,MySQL服务器只对日期的合法性进行基本检查:年、月和日的范围分别是1000到9999、00到12和00到31。任何包含超出这些范围的部分的日期被转换成'0000-00-00'。请注意仍然允许你保存非法日期,例如'2002-04-31'。要想确保不使用严格模式时日期有效,应检查应用程序。 在严格模式,非法日期不被接受,并且不转换。 详细信息参见[5.3.2节,“SQL服务器模式”](# "5.3.2. The Server SQL Mode")。 ·         包含两位年值的日期会令人模糊,因为世纪不知道。MySQL使用以下规则解释两位年值: o        00-69范围的年值转换为2000-2069。 o        70-99范围的年值转换为1970-1999。 #### 11.3.1.1. 自MySQL 4.1以来的TIMESTAMP属性 **注释:在**旧版本的MySQL中(4.1之前),TIMESTAMP列类型的属性在许多方面于本节所描述的大大不同。如果你需要对旧的TIMESTAMP数据进行转化以便在MySQL 5.1中工作,详情请参见_MySQL 4.1 参考手册_。 TIMESTAMP列的显示格式与DATETIME列相同。换句话说,显示宽度固定在19字符,并且格式为YYYY-MM-DD HH:MM:SS。 MySQL服务器也可以以MAXDB模式运行。当服务器以该模式运行时,TIMESTAMP与DATETIME相等。也就是说,如果创建表时服务器以MAXDB模式运行,TIMESTAMP列创建为DATETIME列。结果是,该列使用DATETIME显示格式,有相同的值范围,并且没有自动对当前的日期和时间进行初始化或更新。 要想启用MAXDB模式,在启动服务器时使用--sql-mode=MAXDB服务器选项或在运行时通过设置全局sql_mode变量将SQL服务器模式设置为MAXDB: mysql> SET GLOBAL sql_mode=MAXDB; 客户端可以按照下面方法让服务器为它的连接以MAXDB模式运行: mysql> SET SESSION sql_mode=MAXDB;   MySQL不接受在日或月列包括一个零或包含非法日期值的时间戳值。该规则的唯一例外是特殊值'0000-00-00 00:00:00'。 你可以非常灵便地确定什么时候初始化和更新TIMESTAMP和对哪些列进行初始化和更新: ·         你可以将当前的时间戳指定为默认值和自动更新的值。但只能选择一个,或者两者都不选。(不可能一个列选择一个行为而另一个列选择另一个行为)。 ·         你可以指定哪个TIMESTAMP列自动初始化或更新为当前的日期和时间。不再需要为第1个TIMESTAMP列。 请注意下面讨论所信息只适用于创建时未启用MAXDB模式的表的TIMESTAMP列。(如上所述,MAXDB模式使列创建为DATETIME列)。控制TIMESTAMP列的初始化和更新的规则如下所示: ·         如果一个表内的第1个TIMESTAMP列指定为一个DEFAULT值,则不能忽略。 默认值可以为CURRENT_TIMESTAMP或常量日期和时间值。 ·         DEFAULT NULL与第1个_TIMESTAMP_列的DEFAULT CURRENT_TIMESTAMP相同。对于其它TIMESTAMP列,DEFAULT NULL被视为DEFAULT 0。 ·         表内的任何一个TIMESTAMP列可以设置为自动初始化为当前时间戳和/或更新。 ·         在CREATE TABLE语句中,可以用下面的任何一种方式声明第1个TIMESTAMP列: o        用DEFAULT CURRENT_TIMESTAMP和ON UPDATE CURRENT_TIMESTAMP子句,列为默认值使用当前的时间戳,并且自动更新。 o        不使用DEFAULT或ON UPDATE子句,与DEFAULT CURRENT_TIMESTAMP ON UPDATECURRENT_TIMESTAMP相同。 o        用DEFAULT CURRENT_TIMESTAMP子句不用ON UPDATE子句,列为默认值使用当前的时间戳但是不自动更新。 o        不用DEFAULT子句但用ON UPDATE CURRENT_TIMESTAMP子句,列有默认值0并自动更新。 o        用常量DEFAULT值,列有给出的 默认值。如果列有一个ON UPDATE CURRENT_TIMESTAMP子句,它自动更新,否则不。 换句话说,你可以为初始值和自动更新的值使用当前的时间戳,或者其中一个使用,或者两个皆不使用。(例如,你可以指定ON UPDATE来启用自动更新而不让列自动初始化)。 ·         在DEFAULT和ON UPDATE子句中可以使用CURRENT_TIMESTAMP、CURRENT_TIMESTAMP()或者NOW()。它们均具有相同的效果。 两个属性的顺序并不重要。如果一个TIMESTAMP列同时指定了DEFAULT和ON UPDATE,任何一个可以在另一个的前面。 例子,下面这些语句是等效的: CREATE TABLE t (ts TIMESTAMP); CREATE TABLE t (ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP                              ON UPDATE CURRENT_TIMESTAMP); CREATE TABLE t (ts TIMESTAMP ON UPDATE CURRENT_TIMESTAMP                              DEFAULT CURRENT_TIMESTAMP); ·         要为TIMESTAMP列而不是第1列指定自动默认或更新,必须通过将第1个TIMESTAMP列显式分配一个常量DEFAULT值来禁用自动初始化和更新。(例如,DEFAULT 0或DEFAULT'2003-01-01 00:00:00')。然后,对于其它TIMESTAMP列,规则与第1个TIMESTAMP列相同,例外情况是不能忽略DEFAULT和ON UPDATE子句。如果这样做,则不会自动进行初始化或更新。 例如:下面这些语句是等效的: CREATE TABLE t (     ts1 TIMESTAMP DEFAULT 0,     ts2 TIMESTAMP DEFAULT CURRENT_TIMESTAMP                   ON UPDATE CURRENT_TIMESTAMP); CREATE TABLE t (     ts1 TIMESTAMP DEFAULT 0,     ts2 TIMESTAMP ON UPDATE CURRENT_TIMESTAMP                   DEFAULT CURRENT_TIMESTAMP); 可以对每个连接设置当前的时区,相关描述参见[5.10.8节,“MySQL服务器时区支持”](# "5.10.8. MySQL Server Time Zone Support")。TIMESTAMP值以UTC格式保存,存储时对当前的时区进行转换,检索时再转换回当前的时区。只要时区设定值为常量,便可以得到保存时的值。如果保存一个TIMESTAMP值,应更改时区然后检索该值,它与你保存的值不同。这是因为在两个方向的转换中没有使用相同的时区。当前的时区可以用作time_zone系统变量的值。 可以在TIMESTAMP列的定义中包括NULL属性以允许列包含NULL值。例如: CREATE TABLE t (   ts1 TIMESTAMP NULL DEFAULT NULL,   ts2 TIMESTAMP NULL DEFAULT 0,   ts3 TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ); 如果未指定NULL属性,将列设置为NULL设置则会将它设置为当前的时间戳。请注意允许NULL值的TIMESTAMP列不会采用当前的时间戳,除非要么其 默认值定义为CURRENT_TIMESTAMP,或者NOW()或CURRENT_TIMESTAMP被插入到该列内。换句话说,只有使用如下定义创建,定义为 NULL的TIMESTAMP列才会自动更新: CREATE TABLE t (ts NULLDEFAULT CURRENT_TIMESTAMP); 否则-也就是说,如果使用NULL而不是DEFAULT TIMESTAMP来定义TIMESTAMP列,如下所示... CREATE TABLE t1 (ts NULL DEFAULT NULL); CREATE TABLE t2 (ts NULL DEFAULT '0000-00-00 00:00:00'); ...则必须显式插入一个对应当前日期和时间的值。例如: INSERT INTO t1 VALUES (NOW()); INSERT INTO t2 VALUES (CURRENT_TIMESTAMP); ### 11.3.2. TIME类型 MySQL以'HH:MM:SS'格式检索和显示TIME值(或对于大的小时值采用'HHH:MM:SS'格式)。TIME值的范围可以从'-838:59:59'到'838:59:59'。小时部分会因此大的原因是TIME类型不仅可以用于表示一天的时间(必须小于24小时),还可能为某个事件过去的时间或两个事件之间的时间间隔(可以大于24小时,或者甚至为负)。 你可以用各种格式指定TIME值: ·         'D HH:MM:SS.fraction'格式的字符串。还可以使用下面任何一种“非严格”语法:'HH:MM:SS.fraction'、'HH:MM:SS'、'HH:MM'、'D HH:MM:SS'、'D HH:MM'、'D HH'或'SS'。这里D表示日,可以取0到34之间的值。请注意MySQL还不保存分数。 ·         'HHMMSS'格式的没有间割符的字符串,假定是有意义的时间。例如,'101112'被理解为'10:11:12',但'109712'是不合法的(它有一个没有意义的分钟部分),将变为'00:00:00'。 ·         HHMMSS格式的数值,假定是有意义的时间。例如,101112被理解为'10:11:12'。下面格式也可以理解:SS、MMSS、HHMMSS、HHMMSS.fraction。请注意MySQL还不保存分数。 ·         函数返回的结果,其值适合TIME上下文,例如CURRENT_TIME。 对于指定为包括时间部分间割符的字符串的TIME值,如果时、分或者秒值小于10,则不需要指定两位数。'8:3:2'与'08:03:02'相同。 为TIME列分配简写值时应注意。没有冒号,MySQL解释值时假定最右边的两位表示秒。(MySQL解释TIME值为过去的时间而不是当天的时间)。例如,你可能认为'1112'和1112表示'11:12:00'(11点过12分),但MySQL将它们解释为'00:11:12'(11分,12 秒)。同样,'12'和12被解释为 '00:00:12'。相反,TIME值中使用冒号则肯定被看作当天的时间。也就是说,'11:12'表示'11:12:00',而不是'00:11:12'。 超出TIME范围但合法的值被裁为范围最接近的端点。例如,'-850:00:00'和'850:00:00'被转换为'-838:59:59'和'838:59:59'。 无效TIME值被转换为'00:00:00'。请注意由于'00:00:00'本身是一个合法TIME值,只从表内保存的一个'00:00:00'值还不能说出原来的值是 '00:00:00'还是不合法的值。 ### 11.3.3. YEAR类型 YEAR类型是一个单字节类型用于表示年。 MySQL以YYYY格式检索和显示YEAR值。范围是1901到2155。 可以指定各种格式的YEAR值: ·         四位字符串,范围为'1901'到'2155'。 ·         四位数字,范围为1901到2155。 ·         两位字符串,范围为'00'到'99'。'00'到'69'和'70'到'99'范围的值被转换为2000到2069和1970到1999范围的YEAR值。 ·         两位整数,范围为1到99。1到69和70到99范围的值被转换为2001到2069和1970到1999范围的YEAR值。请注意两位整数范围与两位字符串范围稍有不同,因为你不能直接将零指定为数字并将它解释为2000。你必须将它指定为一个字符串'0'或'00'或它被解释为0000。 ·         函数返回的结果,其值适合YEAR上下文,例如NOW()。 非法YEAR值被转换为0000。 ### 11.3.4. Y2K事宜和日期类型 MySQL本身对于2000年(Y2K)是安全的(参见[1.4.5节,“2000年兼容性”](# "1.4.5. Year 2000 Compliance")),但输入给MySQL的值可能不安全。任何包含两位年值的输入都会令人模糊,因为世纪不知道。这些值必须解释为四位形式,因为MySQL内部使用四位来保存年。 对于DATETIME、DATE、TIMESTAMP和YEAR类型,MySQL使用以下规则解释含模糊年值的日期: ·         00-69范围的年值转换为2000-2069。 ·         70-99范围的年值转换为1970-1999。 请记住这些规则只是合理猜测数据值表示什么。如果MySQL使用的启发不能产生正确的值,你应提供包含四位年值的确切输入。 ORDER BY可以正确排序有两位年的TIMESTAMP或YEAR值。 部分函数如MIN()和MAX()将TIMESTAMP或YEAR转换为一个数字。这说明使用有两位年值的值,这些函数不能工作正确。在这种情况下的修复方法是将TIMESTAMP或YEAR转换为四位年格式或使用MIN(DATE_ADD(TIMESTAMP,INTERVAL 0 DAYS))。 ### 11.4. String类型 [ 11.4.1. CHAR和VARCHAR类型](#)[ 11.4.2. BINARY和VARBINARY类型](#)[ 11.4.3. BLOB和TEXT类型``](#)[ 11.4.4. ENUM类型](#)[ 11.4.5. SET类型](#) 字符串类型指CHAR、VARCHAR、BINARY、VARBINARY、BLOB、TEXT、ENUM和SET。该节描述了这些类型如何工作以及如何在查询中使用这些类型。 ### 11.4.1. CHAR和VARCHAR类型 CHAR和VARCHAR类型类似,但它们保存和检索的方式不同。它们的最大长度和是否尾部空格被保留等方面也不同。在存储或检索过程中不进行大小写转换。 CHAR和VARCHAR类型声明的长度表示你想要保存的最大字符数。例如,CHAR(30)可以占用30个字符。 CHAR列的长度固定为创建表时声明的长度。长度可以为从0到255的任何值。当保存CHAR值时,在它们的右边填充空格以达到指定的长度。当检索到CHAR值时,尾部的空格被删除掉。在存储或检索过程中不进行大小写转换。 VARCHAR列中的值为可变长字符串。长度可以指定为0到65,535之间的值。(VARCHAR的最大有效长度由最大行大小和使用的字符集确定。整体最大长度是65,532字节)。 同CHAR对比,VARCHAR值保存时只保存需要的字符数,另加一个字节来记录长度(如果列声明的长度超过255,则使用两个字节)。 VARCHAR值保存时不进行填充。当值保存和检索时尾部的空格仍保留,符合标准SQL。 如果分配给CHAR或VARCHAR列的值超过列的最大长度,则对值进行裁剪以使其适合。如果被裁掉的字符不是空格,则会产生一条警告。如果裁剪非空格字符,则会造成错误(而不是警告)并通过使用严格SQL模式禁用值的插入。参见[5.3.2节,“SQL服务器模式”](# "5.3.2. The Server SQL Mode")。 下面的表显示了将各种字符串值保存到CHAR(4)和VARCHAR(4)列后的结果,说明了CHAR和VARCHAR之间的差别: <table border="1" cellpadding="0" id="table3"><tr><td> <p><strong><span>值</span></strong></p></td> <td> <p> <span>CHAR(4)</span></p></td> <td> <p><strong><span> 存储需求</span></strong></p></td> <td> <p> <span>VARCHAR(4)</span></p></td> <td> <p><strong><span> 存储需求</span></strong></p></td> </tr><tr><td> <p> <span>''</span></p></td> <td> <p><span>'</span><span>    </span><span>'</span></p></td> <td> <p><span>4</span>个字节</p></td> <td> <p> <span>''</span></p></td> <td> <p><span>1</span>个字节</p></td> </tr><tr><td> <p> <span>'ab'</span></p></td> <td> <p><span>'ab</span><span>  </span><span>'</span></p></td> <td> <p><span>4</span>个字节</p></td> <td> <p> <span>'ab '</span></p></td> <td> <p><span>3</span>个字节</p></td> </tr><tr><td> <p> <span>'abcd'</span></p></td> <td> <p> <span>'abcd'</span></p></td> <td> <p><span>4</span>个字节</p></td> <td> <p> <span>'abcd'</span></p></td> <td> <p><span>5</span>个字节</p></td> </tr><tr><td> <p> <span>'abcdefgh'</span></p></td> <td> <p> <span>'abcd'</span></p></td> <td> <p><span>4</span>个字节</p></td> <td> <p> <span>'abcd'</span></p></td> <td> <p><span>5</span>个字节</p></td> </tr></table> 请注意上表中最后一行的值只适用_不使用严格模式_时;如果MySQL运行在严格模式,超过列长度不的值_不_保存__,并且会出现错误。 从CHAR(4)和VARCHAR(4)列检索的值并不总是相同,因为检索时从CHAR列删除了尾部的空格。通过下面的例子说明该差别: mysql> CREATE TABLE vc (v VARCHAR(4), c CHAR(4)); Query OK, 0 rows affected (0.02 sec)   mysql> INSERT INTO vc VALUES ('ab  ', 'ab  '); Query OK, 1 row affected (0.00 sec)   mysql> SELECT CONCAT(v, '+'), CONCAT(c, '+') FROM vc; +----------------+----------------+ | CONCAT(v, '+') | CONCAT(c, '+') | +----------------+----------------+ | ab  +          | ab+            | +----------------+----------------+ 1 row in set (0.00 sec) 根据分配给列的字符集校对规则对CHAR和VARCHAR列中的值进行排序和比较。 请注意所有MySQL校对规则属于PADSPACE类。这说明在MySQL中的所有CHAR和VARCHAR值比较时不需要考虑任何尾部空格。例如: mysql> CREATE TABLE names (myname CHAR(10), yourname VARCHAR(10)); Query OK, 0 rows affected (0.09 sec)   mysql> INSERT INTO names VALUES ('Monty ', 'Monty '); Query OK, 1 row affected (0.00 sec)   mysql> SELECT myname = 'Monty  ', yourname = 'Monty  ' FROM names; +--------------------+----------------------+ | myname = 'Monty  ' | yourname = 'Monty  ' | +--------------------+----------------------+ |                  1 |                    1 | +--------------------+----------------------+ 1 row in set (0.00 sec) 请注意所有MySQL版本均如此,并且它不受SQL服务器模式的影响。 对于尾部填充字符被裁剪掉或比较时将它们忽视掉的情形,如果列的索引需要唯一的值,在列内插入一个只是填充字符数不同的值将会造成复制键值错误。 CHAR BYTE是CHAR BINARY的别名。这是为了保证兼容性。 ASCII属性为CHAR列分配latin1字符集。UNICODE属性分配ucs2字符集。 ### 11.4.2. BINARY和VARBINARY类型 BINARY和VARBINARY类类似于CHAR和VARCHAR,不同的是它们包含二进制字符串而不要非二进制字符串。也就是说,它们包含字节字符串而不是字符字符串。这说明它们没有字符集,并且排序和比较基于列值字节的数值值。 BINARY和VARBINARY允许的最大长度一样,如同CHAR和VARCHAR,不同的是BINARY和VARBINARY的长度是字节长度而不是字符长度。 BINARY和VARBINARY数据类型不同于CHAR BINARY和VARCHAR BINARY数据类型。对于后一种类型,BINARY属性不会将列视为二进制字符串列。相反,它致使使用列字符集的二元 校对规则,并且列自身包含非二进制字符字符串而不是二进制字节字符串。例如CHAR(5) BINARY被视为CHAR(5) CHARACTER SET latin1 COLLATE latin1_bin,假定默认字符集是latin1。这不同于BINARY(5),它保存5字节二进制字符串,没有字符集或 校对规则。 当保存BINARY值时,在它们右边填充值以达到指定长度。填充值是0x00(零字节)。插入值时在右侧添加0x00 on,并且选择时不删除尾部的字节。比较时所有字节很重要,包括ORDER BY和DISTINCT操作。比较时0x00字节和空格是不同的,0x00<空格。 例如:对于一个BINARY(3)列,当插入时 'a' 变为 'a \0'。'a\0'插入时变为'a\0\0'。当选择时两个插入的值均不更改。 对于VARBINARY,插入时不填充字符,选择时不裁剪字节。比较时所有字节很重要,包括ORDER BY和DISTINCT操作。比较时0x00字节和空格是不同的,0x00<空格。 对于尾部填充字符被裁剪掉或比较时将它们忽视掉的情形,如果列的索引需要唯一的值,在列内插入一个只是填充字符数不同的值将会造成复制键值错误。 如果你计划使用这些数据类型来保存二进制数据并且需要检索的值与保存的值完全相同,应考虑前面所述的填充和裁剪特征。下面的例子说明了用0x00填充的BINARY值如何影响列值比较: mysql> CREATE TABLE t (c BINARY(3)); Query OK, 0 rows affected (0.01 sec)   mysql> INSERT INTO t SET c = 'a'; Query OK, 1 row affected (0.01 sec)   mysql> SELECT HEX(c), c = 'a', c = 'a\0\0' from t; +--------+---------+-------------+ | HEX(c) | c = 'a' | c = 'a\0\0' | +--------+---------+-------------+ | 610000 |       0 |           1 | +--------+---------+-------------+ 1 row in set (0.09 sec) 如果检索的值必须与指定进行存储而没有填充的值相同,最好使用BLOB数据类型。 创建表时,MySQL可以默默更改BINARY或VARBINARY列的类型。参见[13.1.5.1节,“沉寂的列规格变更”](# "13.1.5.1. Silent Column Specification Changes")。 ### 11.4.3. BLOB和TEXT类型`` BLOB是一个二进制大对象,可以容纳可变数量的数据。有4种BLOB类型:TINYBLOB、BLOB、MEDIUMBLOB和LONGBLOB。它们只是可容纳值的最大长度不同。 有4种TEXT类型:TINYTEXT、TEXT、MEDIUMTEXT和LONGTEXT。这些对应4种BLOB类型,有相同的最大长度和存储需求。 参见[11.5节,“列类型存储需求”](# "11.5. Column Type Storage Requirements")。 BLOB列被视为二进制字符串(字节字符串)。TEXT列被视为非二进制字符串(字符字符串)。BLOB列没有字符集,并且排序和比较基于列值字节的数值值。TEXT列有一个字符集,并且根据字符集的 校对规则对值进行排序和比较。 在TEXT或BLOB列的存储或检索过程中,不存在大小写转换。 当未运行在严格模式时,如果你为BLOB或TEXT列分配一个超过该列类型的最大长度的值值,值被截取以保证适合。如果截掉的字符不是空格,将会产生一条警告。使用严格SQL模式,会产生错误,并且值将被拒绝而不是截取并给出警告。参见[5.3.2节,“SQL服务器模式”](# "5.3.2. The Server SQL Mode")。 在大多数方面,可以将BLOB列视为能够足够大的VARBINARY列。同样,可以将TEXT列视为VARCHAR列。BLOB和TEXT在以下几个方面不同于VARBINARY和VARCHAR: ·         当保存或检索BLOB和TEXT列的值时不删除尾部空格。(这与VARBINARY和VARCHAR列相同)。 请注意比较时将用空格对TEXT进行扩充以适合比较的对象,正如CHAR和VARCHAR。 ·         对于BLOB和TEXT列的索引,必须指定索引前缀的长度。对于CHAR和VARCHAR,前缀长度是可选的。参见[7.4.3节,“列索引”](# "7.4.3. Column Indexes")。 ·         BLOB和TEXT列不能有 默认值。 LONG和LONG VARCHAR对应MEDIUMTEXT数据类型。这是为了保证兼容性。如果TEXT列类型使用BINARY属性,将为列分配列字符集的二元 校对规则。 MySQL连接程序/ODBC将BLOB值定义为LONGVARBINARY,将TEXT值定义为LONGVARCHAR。 由于BLOB和TEXT值可能会非常长,使用它们时可能遇到一些约束: ·         当排序时只使用该列的前max_sort_length个字节。max_sort_length的 默认值是1024;该值可以在启动**mysqld**服务器时使用--max_sort_length选项进行更改。参见[5.3.3节,“服务器系统变量”](# "5.3.3. Server System Variables")。 运行时增加max_sort_length的值可以在排序或组合时使更多的字节有意义。任何客户端可以更改其会话max_sort_length变量的值: mysql> SET max_sort_length = 2000; mysql> SELECT id, comment FROM tbl_name     -> ORDER BY comment; 当你想要使超过max_sort_length的字节有意义,对含长值的BLOB或TEXT列使用GROUP BY或ORDER BY的另一种方式是将列值转换为固定长度的对象。标准方法是使用SUBSTRING函数。例如,下面的语句对comment列的2000个字节进行排序: mysql> SELECT id, SUBSTRING(comment,1,2000) FROM tbl_name     -> ORDER BY SUBSTRING(comment,1,2000); ·         BLOB或TEXT对象的最大大小由其类型确定,但在客户端和服务器之间实际可以传递的最大值由可用内存数量和通信缓存区大小确定。你可以通过更改max_allowed_packet变量的值更改消息缓存区的大小,但必须同时修改服务器和客户端程序。例如,可以使用 **mysql**和**mysqldump**来更改客户端的max_allowed_packet值。参见[7.5.2节,“调节服务器参数”](# "7.5.2. Tuning Server Parameters")、[8.3节,“mysql:MySQL命令行工具”](# "8.3. mysql — The MySQL Command-Line Tool")和[8.8节,“mysqldump:数据库备份程序”](# "8.8. mysqldump — A Database Backup Program")。 每个BLOB或TEXT值分别由内部分配的对象表示。这与其它列类型形成对比,后者是当打开表时为每1列分配存储引擎。 ### 11.4.4. ENUM类型 ENUM是一个字符串对象,其值来自表创建时在列规定中显式枚举的一列值。 在某些情况下,ENUM值也可以为空字符串('')或NULL: ·         如果你将一个非法值插入ENUM(也就是说,允许的值列之外的字符串),将插入空字符串以作为特殊错误值。该字符串与“普通”空字符串不同,该字符串有数值值0。后面有详细讨论。 ·         如果将ENUM列声明为允许NULL,NULL值则为该列的一个有效值,并且 默认值为NULL。如果ENUM列被声明为NOT NULL,其默认值为允许的值列的第1个元素。 每个枚举值有一个索引: ·         来自列规定的允许的值列中的值从1开始编号。 ·         空字符串错误值的索引值是0。这说明你可以使用下面的SELECT语句来找出分配了非法ENUM值的行: ·                mysql> SELECT * FROM tbl_name WHERE enum_col=0; ·         NULL值的索引是NULL。 例如,定义为ENUM的列('one','two','three')可以有下面所示任何值。还显示了每个值的索引: <table border="1" cellpadding="0" id="table4"><tr><td> <p><strong><span>值</span></strong></p></td> <td> <p><strong><span>索引</span></strong></p></td> </tr><tr><td> <p> <span>NULL</span></p></td> <td> <p> <span>NULL</span></p></td> </tr><tr><td> <p> <span>''</span></p></td> <td> <p><span>0</span></p></td> </tr><tr><td> <p> <span>'one'</span></p></td> <td> <p><span>1</span></p></td> </tr><tr><td> <p> <span>'two'</span></p></td> <td> <p><span>2</span></p></td> </tr><tr><td> <p> <span>'three'</span></p></td> <td> <p><span>3</span></p></td> </tr></table> 枚举最多可以有65,535个元素。 当创建表时,ENUM成员值的尾部空格将自动被删除。 当检索时,保存在ENUM列的值使用列定义中所使用的大小写来显示。请注意可以为ENUM列分配字符集和 校对规则。对于二进制或大小写敏感的校对规则,当为列分配值时应考虑大小写。 如果在数值上下文中检索一个ENUM值,将返回列值的索引。例如,你可以这样从ENUM列搜索数值值: mysql> SELECT enum_col+0 FROM tbl_name; 如果将一个数字保存到ENUM列,数字被视为索引,并且保存的值是该索引对应的枚举成员。(但是,这不适合LOAD DATA,它将所有输入视为字符串)。不建议使用类似数字的枚举值来定义一个ENUM列,因为这很容易引起混淆。例如,下面的列含有字符串值'0'、'1'和'2'的枚举成员,但数值索引值为1、2和3: numbers ENUM('0','1','2') 根据枚举成员在列定义中列出的顺序对ENUM值进行排序。(换句话说,ENUM值根据索引编号进行排序)。例如,对于ENUM('a','b'),'a'排在'b'前面,但对于ENUM('b','a'),'b'排在'a'前面。空字符串排在非空字符串前面,并且NULL值排在所有其它枚举值前面。要想防止意想不到的结果,按字母顺序规定ENUM列。还可以使用GROUP BY  CAST(col AS CHAR)或GROUP BY  CONCAT(col)来确保按照词汇对列进行排序而不是用索引数字。 如果你想要确定一个ENUM列的所有可能的值,使用SHOW COLUMNS FROM _tbl_name_ LIKE _enum_col_,并解析输出中第2列的ENUM定义。 ### 11.4.5. SET类型 SET是一个字符串对象,可以有零或多个值,其值来自表创建时规定的允许的一列值。指定包括多个SET成员的SET列值时各成员之间用逗号(‘,’)间隔开。这样SET成员值本身不能包含逗号。 例如,指定为SET('one', 'two') NOT NULL的列可以有下面的任何值: '' 'one' 'two' 'one,two' SET最多可以有64个不同的成员。 当创建表时,SET成员值的尾部空格将自动被删除。 当检索时,保存在SET列的值使用列定义中所使用的大小写来显示。请注意可以为SET列分配字符集和 校对规则。对于二进制或大小写敏感的校对规则,当为列分配值时应考虑大小写。 MySQL用数字保存SET值,所保存值的低阶位对应第1个SET成员。如果在数值上下文中检索一个SET值,检索的值的位设置对应组成列值的SET成员。例如,你可以这样从一个SET列检索数值值: mysql> SELECT set_col+0 FROM tbl_name; 如果将一个数字保存到SET列中,数字中二进制表示中的位确定了列值中的SET成员。对于指定为SET('a','b','c','d')的列,成员有下面的十进制和二进制值: <table border="1" cellpadding="0" id="table5"><tr><td> <p> <span>SET</span><strong><span>成员</span></strong></p></td> <td> <p><strong><span>十进制值</span></strong></p></td> <td> <p><strong><span>二进制值</span></strong></p></td> </tr><tr><td> <p> <span>'a'</span></p></td> <td> <p> <span>1</span></p></td> <td> <p> <span>0001</span></p></td> </tr><tr><td> <p> <span>'b'</span></p></td> <td> <p> <span>2</span></p></td> <td> <p> <span>0010</span></p></td> </tr><tr><td> <p> <span>'c'</span></p></td> <td> <p> <span>4</span></p></td> <td> <p> <span>0100</span></p></td> </tr><tr><td> <p> <span>'d'</span></p></td> <td> <p> <span>8</span></p></td> <td> <p> <span>1000</span></p></td> </tr></table>   如果你为该列分配一个值9,其二进制形式为1001,因此第1个和第4个SET值成员'a'和'd'被选择,结果值为 'a,d'。 对于包含多个SET元素的值,当插入值时元素所列的顺序并不重要。在值中一个给定的元素列了多少次也不重要。当以后检索该值时,值中的每个元素出现一次,根据表创建时指定的顺序列出元素。例如,假定某个列指定为SET('a','b','c','d'): mysql> CREATE TABLE myset (col SET('a', 'b', 'c', 'd')); 插入值'a,d'、'd,a'、'a,d,d'、'a,d,a'和'd,a,d': mysql> INSERT INTO myset (col) VALUES -> ('a,d'), ('d,a'), ('a,d,a'), ('a,d,d'), ('d,a,d'); Query OK, 5 rows affected (0.01 sec) Records: 5  Duplicates: 0  Warnings: 0 当检索时所有这些值显示为 'a,d': mysql> SELECT col FROM myset; +------+ | col  | +------+ | a,d  | | a,d  | | a,d  | | a,d  | | a,d  | +------+ 5 rows in set (0.04 sec) 如果将SET列设置为一个不支持的值,则该值被忽略并发出警告: mysql> INSERT INTO myset (col) VALUES ('a,d,d,s'); Query OK, 1 row affected, 1 warning (0.03 sec)   mysql> SHOW WARNINGS; +---------+------+------------------------------------------+ | Level   | Code | Message                                  | +---------+------+------------------------------------------+ | Warning | 1265 | Data truncated for column 'col' at row 1 | +---------+------+------------------------------------------+ 1 row in set (0.04 sec)   mysql> SELECT col FROM myset; +------+ | col  | +------+ | a,d  | | a,d  | | a,d  | | a,d  | | a,d  | | a,d  | +------+ 6 rows in set (0.01 sec) SET值按数字顺序排序。NULL值排在非NULLSET值的前面。 通常情况,可以使用FIND_IN_SET()函数或LIKE操作符搜索SET值: mysql> SELECT * FROM tbl_name WHERE FIND_IN_SET('value',set_col)>0; mysql> SELECT * FROM tbl_name WHERE set_col LIKE '%value%'; 第1个语句找出_SET_col_包含_value_ set成员的行。第2个类似,但有所不同:它在其它地方找出_set_col_包含_value_的行,甚至是在另一个SET成员的子字符串中。 下面的语句也是合法的: mysql> SELECT * FROM tbl_name WHERE set_col & 1; mysql> SELECT * FROM tbl_name WHERE set_col = 'val1,val2'; 第1个语句寻找包含第1个set成员的值。第2个语句寻找一个确切匹配的值。应注意第2类的比较。将set值与'_val1_,_val2_'比较返回的结果与同'_val2_,_val1_'比较返回的结果不同。指定值时的顺序应与在列定义中所列的顺序相同。 如果想要为SET列确定所有可能的值,使用SHOW COLUMNS FROM _tbl_name_ LIKE _set_col_并解析输出中第2列的SET定义。 ### 11.5. 列类型存储需求 根据类别列出了MySQL支持的每个列类型的存储需求。 MyISAM表中行的最大大小为65,534字节。每个BLOB和TEXT列 账户只占其中的5至9个字节。 如果MyISAM表包括变长列类型,记录格式也是可变长度。当创建表时,在某些条件下,MySQL可以将一个列从变长类型改为固定长度的类型或反之亦然。详细信息参见[13.1.5.1节,“沉寂的列规格变更”](# "13.1.5.1. Silent Column Specification Changes")。 **数值类型存储需求