MySQL中文参考手册---7 MySQL语言参考(1)
时间:2008-05-14 来源:sdccf
7 MySQL语言参考
7.1 文字:怎么写字符串和数字
7.1.1 字符串
一个字符串是一个字符序列,由单引号(“'”)或双引号(“"”)字符(后者只有你不在ANSI模式运行)包围。例如:
'a string' "another string"
在字符串内,某个顺序有特殊的意义。这些顺序的每一个以一条反斜线(“\”)开始,称为转义字符。MySQL识别下列转义字符: \0 一个ASCII 0 (NUL)字符。 \n 一个新行符。 \t 一个定位符。 \r 一个回车符。 \b 一个退格符。 \' 一个单引号(“'”)符。 \" 一个双引号(“"”)符。 \\ 一个反斜线(“\”)符。 \% 一个“%”符。它用于在正文中搜索“%”的文字实例,否则这里“%”将解释为一个通配符。 \_ 一个“_”符。它用于在正文中搜索“_”的文字实例,否则这里“_”将解释为一个通配符。
注意,如果你在某些正文环境中使用“\%”或“\%_”,这些将返回字符串“\%”和“\_”而不是“%”和“_”。
有几种方法在一个字符串内包括引号:
- 一个字符串内用“'”加引号的“'”可以被写作为“''”。
- 一个字符串内用“"”加引号的“"”可以被写作为“""”。
- 你可以把一个转义字符(“\”)放在引号前面。
- 一个字符串内用“"”加引号的“'”不需要特殊对待而且不必被重复或转义。同理,一个字符串内用“'”加引号的与“"”也不需要特殊对待。
下面显示的SELECT演示引号和转义如何工作:
mysql> SELECT 'hello', '"hello"', '""hello""', 'hel''lo', '\'hello'; +-------+---------+-----------+--------+--------+ | hello | "hello" | ""hello"" | hel'lo | 'hello | +-------+---------+-----------+--------+--------+ mysql> SELECT "hello", "'hello'", "''hello''", "hel""lo", "\"hello"; +-------+---------+-----------+--------+--------+ | hello | 'hello' | ''hello'' | hel"lo | "hello | +-------+---------+-----------+--------+--------+ mysql> SELECT "This\nIs\nFour\nlines"; +--------------------+ | This Is Four lines | +--------------------+
如果你想要把二进制数据插入到一个BLOB列,下列字符必须由转义序列表示: NUL ASCII 0。你应该用'\0'(一个反斜线和一个ASCII '0')表示它。 \ ASCII 92,反斜线。用'\\'表示。 ' ASCII 39,单引号。用“\'”表示。 " ASCII 34,双引号。用“\"”表示。
如果你写C代码,你可以使用C API函数mysql_escape_string()来为INSERT语句转义字符。见20.3 C API 函数概述。在 Perl中,你可以使用DBI包中的quote方法变换特殊的字符到正确的转义序列。见20.5.2 DBI接口。
你应该在任何可能包含上述任何特殊字符的字符串上使用转义函数!
7.1.2 数字
整数表示为一个数字顺序。浮点数使用“.”作为一个十进制分隔符。这两种类型的数字可以前置“-”表明一个负值。
有效整数的例子:
1221 0 -32
有效浮点数的例子:
294.42 -32032.6809e+10 148.00
一个整数可以在浮点上下文使用;它解释为等值的浮点数。
7.1.3 十六进制值
MySQL支持十六进制值。在数字上下文,它们表现类似于一个整数(64位精度)。在字符串上下文,它们表现类似于一个二进制字符串,这里每一对十六进制数字被变换为一个字符。
mysql> SELECT 0xa+0 -> 10 mysql> select 0x5061756c; -> Paul
十六进制字符串经常被ODBC使用,给出BLOB列的值。
7.1.4 NULL值
NULL值意味着“无数据”并且不同于例如数字类型的0为或字符串类型的空字符串。见18.15 NULL值问题。
当使用文本文件导入或导出格式(LOAD DATA INFILE, SELECT ... INTO OUTFILE)时,NULL可以用\N表示。见7.16 LOAD DATA INFILE句法。
7.1.5 数据库、表、索引、列和别名的命名
数据库、表、索引、列和别名的名字都遵守MySQL同样的规则:
注意,从MySQL3.23.6开始规则改变了,此时我们引入了用'引用的标识符(数据库、表和列命名)(如果你以ANSI模式运行,"也将用于引用标识符)。
标识符 | 最大长度 | 允许的字符 |
数据库 | 64 | 在一个目录名允许的任何字符,除了/. |
表 | 64 | 在文件名中允许的任何字符,除了/或. |
列 | 64 | 所有字符 |
别名 | 255 | 所有字符 |
注意,除了以上,你在一个标识符中不能有ASCII(0)或ASCII(255)。
注意,如果标识符是一个限制词或包含特殊字符,当你使用它时,你必须总是用`引用它:
SELECT * from `select` where `select`.id > 100;
在 MySQL的先前版本,命名规则如下:
- 一个名字可以包含来自当前字符集的数字字母的字符和“_”和“$”。缺省字符集是ISO-8859-1 Latin1;这可以通过重新编译MySQL来改变。见9.1.1 用于数据和排序的字符集。
- 一个名字可以以在一个名字中合法的任何字符开始。特别地,一个名字可以以一个数字开始(这不同于许多其他的数据库系统!)。然而,一个名字不能仅仅由数字组成。
- 你不能在名字中使用“.”,因为它被用来扩充格式,你能用它引用列(见下面)。
建议你不使用象1e这样的名字,因为一个表达式如1e+1是二义性的。它可以解释为表达式1e + 1或数字1e+1。
在MySQL中,你能使用下列表格的任何一种引用列:
列引用 | 含义 |
col_name | 来自于任意表的列col_name,用于包含该表的一个列的查询中 |
tbl_name.col_name | 来自当前的数据库的表tbl_name的列col_name |
db_name.tbl_name.col_name | 行列col_name从表格tbl_name数据库db_name。这个形式在MySQL3.22或以后版本可用。 |
`column_name` | 是一个关键词或包含特殊字符的列。 |
在一条语句的列引用中,你不必指定一个tbl_name或db_name.tbl_name前缀,除非引用会有二义性。例如,假定表t1和t2,每个均包含列c,并且你用一个使用t1和t2的SELECT语句检索c。在这种情况下,c有二义性,因为它在使用表的语句中不是唯一的,因此你必须通过写出t1.c或t2.c来指明你想要哪个表。同样,如果你从数据库db1中一个表t和在数据库db2的一个表t检索,你必须用db1.t.col_name和db2.t.col_name引用这些数据表的列。
句法.tbl_name意味着在当前的数据库中的表tbl_name,该句法为了ODBC的兼容性被接受,因为一些ODBC程序用一个“.”字符作为数据库表名的前缀。
7.1.5.1 名字的大小写敏感性
在MySQL中,数据库和表对应于在那些目录下的目录和文件,因而,内在的操作系统的敏感性决定数据库和表命名的大小写敏感性。这意味着数据库和表名在Unix上是区分大小写的,而在Win32上忽略大小写。
注意:在Win32上,尽管数据库和表名是忽略大小写的,你不应该在同一个查询中使用不同的大小写来引用一个给定的数据库和表。下列查询将不工作,因为它作为my_table和作为MY_TABLE引用一个表:
mysql> SELECT * FROM my_table WHERE MY_TABLE.col=1;
列名在所有情况下都是忽略大小写的。
表的别名是区分大小写的。下列查询将不工作,: 因为它用a和A引用别名:
mysql> SELECT col_name FROM tbl_name AS a WHERE a.col_name = 1 OR A.col_name = 2;
列的别名是忽略大小写的。
7.2 用户变量
MySQL支持线程特定的变量,用@variablename句法。一个变量名可以由当前字符集的数字字母字符和“_”、“$”和“.”组成。缺省字符集是ISO-8859-1 Latin1;这可以通过重新编译MySQL改变。见9.1.1 用于数据和排序的字符集。
变量不必被初始化。缺省地,他们包含NULL并能存储整数、实数或一个字符串值。当线程退出时,对于一个线程的所有变量自动地被释放。
你可以用SET句法设置一个变量:
SET @variable= { integer expression | real expression | string expression } [,@variable= ...].
你也可以用@variable:=expr句法在一个表达式中设置一个变量:
select @t1:=(@t2:=1)+@t3:=4,@t1,@t2,@t3; +----------------------+------+------+------+ | @t1:=(@t2:=1)+@t3:=4 | @t1 | @t2 | @t3 | +----------------------+------+------+------+ | 5 | 5 | 1 | 4 | +----------------------+------+------+------+
(这里,我们不得不使用:=句法,因为=是为比较保留的)
7.3 列类型
MySQL支持大量的列类型,它可以被分为3类:数字类型、日期和时间类型以及字符串(字符)类型。本节首先给出可用类型的一个概述,并且总结每个列类型的存储需求,然后提供每个类中的类型性质的更详细的描述。概述有意简化,更详细的说明应该考虑到有关特定列类型的附加信息,例如你能为其指定值的允许格式。
由MySQL支持的列类型列在下面。下列代码字母用于描述中: M 指出最大的显示尺寸。最大的合法的显示尺寸是 255 。 D 适用于浮点类型并且指出跟随在十进制小数点后的数码的数量。最大可能的值是30,但是应该不大于M-2。
方括号(“[”和“]”)指出可选的类型修饰符的部分。
注意,如果你指定一个了为ZEROFILL,MySQL将为该列自动地增加UNSIGNED属性。 TINYINT[(M)] [UNSIGNED] [ZEROFILL] 一个很小的整数。有符号的范围是-128到127,无符号的范围是0到255。 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或DOUBLE值完成,因此你不应该使用大于9223372036854775807(63位)的有符号大整数,除了位函数!注意,当两个参数是INTEGER值时,-、+和*将使用BIGINT运算!这意味着如果你乘2个大整数(或来自于返回整数的函数),如果结果大于9223372036854775807,你可以得到意外的结果。一个浮点数字,不能是无符号的,对一个单精度浮点数,其精度可以是<=24,对一个双精度浮点数,是在25 和53之间,这些类型如FLOAT和DOUBLE类型马上在下面描述。FLOAT(X)有对应的FLOAT和DOUBLE相同的范围,但是显示尺寸和小数位数是未定义的。在MySQL3.23中,这是一个真正的浮点值。在更早的MySQL版本中,FLOAT(precision)总是有2位小数。该句法为了ODBC兼容性而提供。 FLOAT[(M,D)] [ZEROFILL] 一个小(单精密)浮点数字。不能无符号。允许的值是-3.402823466E+38到-1.175494351E-38,0 和1.175494351E-38到3.402823466E+38。M是显示宽度而D是小数的位数。没有参数的FLOAT或有<24 的一个参数表示一个单精密浮点数字。 DOUBLE[(M,D)] [ZEROFILL] 一个正常大小(双精密)浮点数字。不能无符号。允许的值是-1.7976931348623157E+308到-2.2250738585072014E-308、 0和2.2250738585072014E-308到1.7976931348623157E+308。M是显示宽度而D是小数位数。没有一个参数的DOUBLE或FLOAT(X)(25 < = X < = 53)代表一个双精密浮点数字。 DOUBLE PRECISION[(M,D)] [ZEROFILL] REAL[(M,D)] [ZEROFILL] 这些是DOUBLE同义词。 DECIMAL[(M[,D])] [ZEROFILL] 一个未压缩(unpack)的浮点数字。不能无符号。行为如同一个CHAR列:“未压缩”意味着数字作为一个字符串被存储,值的每一位使用一个字符。小数点,并且对于负数,“-”符号不在M中计算。如果D是0,值将没有小数点或小数部分。DECIMAL值的最大范围与DOUBLE相同,但是对一个给定的DECIMAL列,实际的范围可以通过M和D的选择被限制。如果D被省略,它被设置为0。如果M被省掉,它被设置为10。注意,在MySQL3.22里,M参数包括符号和小数点。 NUMERIC(M,D) [ZEROFILL] 这是DECIMAL的一个同义词。 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年的某时。MySQL以YYYYMMDDHHMMSS、YYMMDDHHMMSS、YYYYMMDD或YYMMDD格式来显示TIMESTAMP值,取决于是否M是14(或省略)、12、8或6,但是允许你使用字符串或数字把值赋给TIMESTAMP列。一个TIMESTAMP列对于记录一个INSERT或UPDATE操作的日期和时间是有用的,因为如果你不自己给它赋值,它自动地被设置为最近操作的日期和时间。你以可以通过赋给它一个NULL值设置它为当前的日期和时间。见7.3.6 日期和时间类型。 TIME 一个时间。范围是'-838:59:59'到'838:59:59'。MySQL以'HH:MM:SS'格式来显示TIME值,但是允许你使用字符串或数字把值赋给TIME列。 YEAR[(2|4)] 一个2或4位数字格式的年(缺省是4位)。允许的值是1901到2155,和0000(4位年格式),如果你使用2位,1970-2069( 70-69)。MySQL以YYYY格式来显示YEAR值,但是允许你把使用字符串或数字值赋给YEAR列。(YEAR类型在MySQL3.22中是新类型。) CHAR(M) [BINARY] 一个定长字符串,当存储时,总是是用空格填满右边到指定的长度。M的范围是1 ~ 255个字符。当值被检索时,空格尾部被删除。CHAR值根据缺省字符集以大小写不区分的方式排序和比较,除非给出BINARY关键词。NATIONAL CHAR(短形式NCHAR)是ANSI SQL的方式来定义CHAR列应该使用缺省字符集。这是MySQL的缺省。CHAR是CHARACTER的一个缩写。 [NATIONAL] VARCHAR(M) [BINARY] 一个变长字符串。注意:当值被存储时,尾部的空格被删除(这不同于ANSI SQL规范)。M的范围是1 ~ 255个字符。 VARCHAR值根据缺省字符集以大小写不区分的方式排序和比较,除非给出BINARY关键词值。见7.7.1 隐式列指定变化。 VARCHAR是CHARACTER VARYING一个缩写。 TINYBLOB TINYTEXT 一个BLOB或TEXT列,最大长度为255(2^8-1)个字符。见7.7.1 隐式列指定变化。 BLOB TEXT 一个BLOB或TEXT列,最大长度为65535(2^16-1)个字符。见7.7.1 隐式列指定变化。 MEDIUMBLOB MEDIUMTEXT 一个BLOB或TEXT列,最大长度为16777215(2^24-1)个字符。见7.7.1 隐式列指定变化。 LONGBLOB LONGTEXT 一个BLOB或TEXT列,最大长度为4294967295(2^32-1)个字符。见7.7.1 隐式列指定变化 ENUM('value1','value2',...) 枚举。一个仅有一个值的字符串对象,这个值式选自与值列表'value1'、'value2', ...,或NULL。一个ENUM最多能有65535不同的值。 SET('value1','value2',...) 一个集合。能有零个或多个值的一个字符串对象,其中每一个必须从值列表'value1', 'value2', ...选出。一个SET最多能有64个成员。
7.3.1 列类型存储需求
对于每个由MySQL支持的列类型的存储需求在下面按类列出。
7.3.2 数字类型
列类型 | 需要的存储量 |
TINYINT | 1 字节 |
SMALLINT | 2 个字节 |
MEDIUMINT | 3 个字节 |
INT | 4 个字节 |
INTEGER | 4 个字节 |
BIGINT | 8 个字节 |
FLOAT(X) | 4 如果 X < = 24 或 8 如果 25 < = X < = 53 |
FLOAT | 4 个字节 |
DOUBLE | 8 个字节 |
DOUBLE PRECISION | 8 个字节 |
REAL | 8 个字节 |
DECIMAL(M,D) | M字节(D+2 , 如果M < D) |
NUMERIC(M,D) | M字节(D+2 , 如果M < D) |
7.3.3 日期和时间类型
列类型 | 需要的存储量 |
DATE | 3 个字节 |
DATETIME | 8 个字节 |
TIMESTAMP | 4 个字节 |
TIME | 3 个字节 |
YEAR | 1 字节 |
7.3.4 串类型
列类型 | 需要的存储量 |
CHAR(M) | M字节,1 <= M <= 255 |
VARCHAR(M) | L+1 字节, 在此L <= M和1 <= M <= 255 |
TINYBLOB, TINYTEXT | L+1 字节, 在此L< 2 ^ 8 |
BLOB, TEXT | L+2 字节, 在此L< 2 ^ 16 |
MEDIUMBLOB, MEDIUMTEXT | L+3 字节, 在此L< 2 ^ 24 |
LONGBLOB, LONGTEXT | L+4 字节, 在此L< 2 ^ 32 |
ENUM('value1','value2',...) | 1 或 2 个字节, 取决于枚举值的数目(最大值65535) |
SET('value1','value2',...) | 1,2,3,4或8个字节, 取决于集合成员的数量(最多64个成员) |
VARCHAR和BLOB和TEXT类型是变长类型,对于其存储需求取决于列值的实际长度(在前面的表格中用L表示),而不是取决于类型的最大可能尺寸。例如,一个VARCHAR(10)列能保存最大长度为10个字符的一个字符串,实际的存储需要是字符串的长度(L),加上1个字节以记录字符串的长度。对于字符串'abcd',L是4而存储要求是5个字节。
BLOB和TEXT类型需要1,2,3或4个字节来记录列值的长度,这取决于类型的最大可能长度。
如果一个表包括任何变长的列类型,记录格式将也是变长的。注意,当一个表被创建时,MySQL可能在某些条件下将一个列从一个变长类型改变为一个定长类型或相反。见7.7.1 隐式列指定变化。
一个ENUM对象的大小由不同枚举值的数量决定。1字节被用于枚举,最大到255个可能的值;2个字节用于枚举,最大到65535 值。
一个SET对象的大小由不同的集合成员的数量决定。如果集合大小是N,对象占据(N+7)/8个字节,四舍五入为1,2,3,4或8 个字节。一个SET最多能有64个成员。
7.3.5 数字类型
MySQL支持所有的ANSI/ISO SQL92的数字类型。这些类型包括准确数字的数据类型(NUMERIC, DECIMAL, INTEGER,和SMALLINT),也包括近似数字的数据类型(FLOAT, REAL,和DOUBLE PRECISION)。关键词INT是INTEGER的一个同义词,而关键词DEC是DECIMAL一个同义词。
NUMERIC和DECIMAL类型被MySQL实现为同样的类型,这在SQL92标准允许。他们被用于保存值,该值的准确精度是极其重要的值,例如与金钱有关的数据。当声明一个类是这些类型之一时,精度和规模的能被(并且通常是)指定;例如:
salary DECIMAL(9,2)
在这个例子中,9(precision)代表将被用于存储值的总的小数位数,而2(scale)代表将被用于存储小数点后的位数。因此,在这种情况下,能被存储在salary列中的值的范围是从-9999999.99到9999999.99。在ANSI/ISO SQL92中,句法DECIMAL(p)等价于DECIMAL(p,0)。同样,句法DECIMAL等价于DECIMAL(p,0),这里实现被允许决定值p。MySQL当前不支持DECIMAL/NUMERIC数据类型的这些变种形式的任一种。这一般说来不是一个严重的问题,因为这些类型的主要益处得自于明显地控制精度和规模的能力。
DECIMAL和NUMERIC值作为字符串存储,而不是作为二进制浮点数,以便保存那些值的小数精度。一个字符用于值的每一位、小数点(如果scale>0)和“-”符号(对于负值)。如果scale是0,DECIMAL和NUMERIC值不包含小数点或小数部分。
DECIMAL和NUMERIC值得最大的范围与DOUBLE一样,但是对于一个给定的DECIMAL或NUMERIC列,实际的范围可由制由给定列的precision或scale限制。当这样的列赋给了小数点后面的位超过指定scale所允许的位的值,该值根据scale四舍五入。当一个DECIMAL或NUMERIC列被赋给了其大小超过指定(或缺省的)precision和scale隐含的范围的值,MySQL存储表示那个范围的相应的端点值。
作为对ANSI/ISO SQL92标准的扩展,MySQL也支持上表所列的整型类型TINYINT、MEDIUMINT和BIGINT。另一个扩展是MySQL支持可选地指定一个整型值显示的宽度,用括号跟在基本关键词之后(例如,INT(4))。这个可选的宽度指定被用于其宽度小于列指定宽度的值得左填补显示,但是不限制能在列中被存储的值的范围,也不限制值将被显示的位数,其宽度超过列指定的宽度。当与可选的扩展属性ZEROFILL一起使用时,缺省的空格填补用零代替。例如,对于声明为INT(5) ZEROFILL的列,一个为4的值作为00004被检索。注意,如果你在一个整型列存储超过显示宽度的更大值,当MySQL对于某些复杂的联结(join)生成临时表时,你可能会遇到问题,因为在这些情况下,MySQL相信数据确实适合原来的列宽度。
所有的整型类型可以有一个可选(非标准的)属性UNSIGNED。当你想要在列中仅允许正数并且你需要一个稍大一点的列范围,可以使用无符号值。
FLOAT类型被用来标示近似数字的数据类型。ANSI/ISO SQL92标准允许一个可选的精度说明(但不是指数的范围),跟在关键词FLOAT后面的括号内位数。MySQL实现也支持这个可选的精度说明。当关键词FLOAT被用于一个列类型而没有精度说明时,MySQL使用4个字节存储值。一个变种的句法也被支持,在FLOAT关键词后面的括号给出2个数字。用这个选项,第一个数字继续表示在字节计算的值存储需求,而第二个数字指定要被存储的和显示跟随小数点后的位数(就象DECIMAL和NUMERIC)。当MySQL要求为这样一个列,一个小数点后的小数位超过列指定的值,存储值时,该值被四舍五入,去掉额外的位。
REAL和DOUBLE PRECISION类型不接受精度说明。作为对 ANSI/ISO SQL92 标准的扩展,MySQL识别出DOUBLE作为DOUBLE PRECISION类型的一个同义词。与REAL精度比用于DOUBLE PRECISION的更小的标准要求相反,MySQL实现了两种,作为8字节双精度浮点值(当运行不是“Ansi模式”时)。为了最大的移植性,近似数字的数据值的存储所需代码应该使用没有精度或小数位数说明的FLOAT或DOUBLE PRECISION。
当要求在数字的列存储超出该列类型允许的范围的值时,MySQL剪切该值到范围内的正确端点值并且存储剪切后的结果值。
例如,一个INT列的范围是-2147483648到2147483647。如果你试图插入-9999999999到一个INT列中,值被剪切到范围的低部端点,并存储-2147483648。同样,如果你试图插入9999999999,2147483647被存储。
如果INT列是UNSIGNED,列的范围的大小是相同的,但是它的端点移到了0和4294967295。如果你试图存储-9999999999和9999999999,在列被存储的值变为0和4294967296。
对于ALTER TABLE、LOAD DATA INFILE、UPDATE和多行INSERT语句,由于剪切所发生的变换作为“警告”被报告。
7.3.6 日期和时间类型
日期和时间类型是DATETIME、DATE、TIMESTAMP、TIME和YEAR。这些的每一个都有合法值的一个范围,而“零”当你指定确实不合法的值时被使用。注意,MySQL允许你存储某个“不严格地”合法的日期值,例如1999-11-31,原因我们认为它是应用程序的责任来处理日期检查,而不是SQL服务器。为了使日期检查更“快”,MySQL仅检查月份在0-12的范围,天在0-31的范围。上述范围这样被定义是因为MySQL允许你在一个DATE或DATETIME列中存储日期,这里的天或月是零。这对存储你不知道准确的日期的一个生日的应用程序来说是极其有用的,在这种情况下,你简单地存储日期象1999-00-00或1999-01-00。(当然你不能期望从函数如DATE_SUB()或DATE_ADD()得到类似以这些日期的正确值)。
当用日期和时间工作时,这里是的一些要记住的一般考虑:
- MySQL对一个给定的日期或时间类型以标准的格式检索,但是它试图为你提供的值解释成许多格式(例如,当你指定一个值被赋给或与比较一个日期或时间类型时),但是只支持有在下列小节描述的格式。期望你提供合法的值,并且如果你以其他格式使用这些值,可能造成无法预料的结果。
- 尽管MySQL试图以多种格式解释值,但它总是期望日期值的年份部分在最左面,日期必须以年-月-日的顺序给出(例如,'98-09-04'),而不是以其他地方常用的月-日-年或日-月-年的次序(例如,'09-04-98'、'04-09-98')。
- 如果一个值在数字的上下文环境中被使用,MySQL自动变换一个日期或时间类型值到一个数字,反过来也如此。
- 当MySQL遇到一个日期或时间类型的值超出范围或对给类型不合法(见本节的开始)时,它将该类型的值变换到“零”值。(例外的是超出范围的TIME值被剪切为适当的TIME范围端点值。)下表显示对每种类型的“零”值的格式:
列类型 “零”值 DATETIME '0000-00-00 00:00:00' DATE '0000-00-00' TIMESTAMP 00000000000000(长度取决于显示尺寸) TIME '00:00:00' YEAR 0000 - “零”值是特殊的,但是你能使用在表中显示的值来明显地存储或引用他们。你也可以使用值'0'或0做到, 这更容易写。
- 在MyODBC 2.50.12和以上版本中,由MyODBC使用的“零”日期或时间值被自动变换到NULL,因为ODBC不能处理这样的值。
7.3.6.1 Y2K问题和日期类型
MySQL本身Y2K安全的(见1.6 2000年一致性),但是呈交给MySQL的输入值可能不是。一个包含2位年份值的任何输入是由二义性的,因为世纪是未知的。这样的值必须被解释成4位形式,因为MySQL内部使用4位存储年份。
对于DATETIME, DATE, TIMESTAMP和YEAR类型,MySQL使用下列规则的解释二义性的年份值:
- 在范围00-69的年值被变换到2000-2069。
- 在范围70-99的年值被变换到1970-1999。
记得这些规则仅仅提供对于你数据的含义的合理猜测。如果MySQL使用的启发规则不产生正确的值,你应该提供无二义的包含4位年值的输入。
7.3.6.2 DATETIME, DATE和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列类型提供一种类型,你可以使用它自动地用当前的日期和时间标记INSERT或UPDATE的操作。如果你有多个TIMESTAMP列,只有第一个自动更新。
自动更新第一个TIMESTAMP列在下列任何条件下发生:
- 列没有明确地在一个INSERT或LOAD DATA INFILE语句中指定。
- 列没有明确地在一个UPDATE语句中指定且一些另外的列改变值。(注意一个UPDATE设置一个列为它已经有的值,这将不引起TIMESTAMP列被更新,因为如果你设置一个列为它当前的值,MySQL为了效率而忽略更改。)
- 你明确地设定TIMESTAMP列为NULL.
除第一个以外的TIMESTAMP列也可以设置到当前的日期和时间,只要将列设为NULL,或NOW()。
通过明确地设置希望的值,你可以设置任何TIMESTAMP列为不同于当前日期和时间的值,即使对第一个TIMESTAMP列也是这样。例如,如果,当你创建一个行时,你想要一个TIMESTAMP被设置到当前的日期和时间,但在以后无论何时行被更新时都不改变,你可以使用这个属性:
- 让MySQL在行被创建时设置列,这将初始化它为当前的日期和时间。
- 当你执行随后的对该行中其他列的更改时,明确设定TIMESTAMP列为它的当前值。
另一方面,你可能发现,当行被创建并且远离随后的更改时,很容易用一个你用NOW()初始化的DATETIME列。
TIMESTAMP值可以从1970的某时的开始一直到2037年,精度为一秒,其值作为数字显示。
在MySQL检索并且显示TIMESTAMP值取决于显示尺寸的格式如下表。“完整”TIMESTAMP格式是14位,但是TIMESTAMP列可以用更短的显示尺寸创造:
列类型 | 显示格式 |
TIMESTAMP(14) | YYYYMMDDHHMMSS |
TIMESTAMP(12) | YYMMDDHHMMSS |
TIMESTAMP(10) | YYMMDDHHMM |
TIMESTAMP(8) | YYYYMMDD |
TIMESTAMP(6) | YYMMDD |
TIMESTAMP(4) | YYMM |
TIMESTAMP(2) | YY |
所有的TIMESTAMP列都有同样的存储大小,不考虑显示尺寸。最常见的显示尺寸是6、8、12、和14。你可以在表创建时间指定一个任意的显示尺寸,但是值0或比14大被强制到14。在从1~13范围的奇数值尺寸被强制为下一个更大的偶数。
使用一个常用的格式集的任何一个,你可以指定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',但是'971122459015'是不合法的(它有毫无意义的分钟部分)且变成'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的月或天的值指定2位数字,'1979-6-9'与'1979-06-09'是一样的。同样, 对于包括的时间部分分隔符的指定为字符串的值,不必为小于10的小时、月或秒指定2位数字,'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,但是日期部分丢失(零),因此该值不是一个合法的日期。
TIMESTAMP列使用被指定的值的完整精度的存储合法的值,不考虑显示大小。这有几个含意:
- 总是指定年,月,和日,即使你的列类型是TIMESTAMP(4)或TIMESTAMP(2)。否则,值将不是一个合法的日期并且0将被存储。
- 如果你使用ALTER TABLE拓宽一个狭窄的TIMESTAMP列,以前被“隐蔽”的信息将被显示。
- 同样,缩小一个TIMESTAMP列不会导致信息失去,除了感觉上值在显示时,较少的信息被显示出。
- 尽管TIMESTAMP值被存储为完整精度,直接操作存储值的唯一函数是UNIX_TIMESTAMP(),其他函数操作在格式化了的检索的值上,这意味着你不能使用函数例如HOUR()或SECOND(),除非TIMESTAMP值的相关部分被包含在格式化的值中。例如,一个TIMESTAMP列的HH部分部被显示,除非显示大小至少是10,因此在更短的TIMESTAMP值上试试使用HOUR()产生一个无意义的结果。
在某种程度上,你可以把一种日期类型的值赋给一个不同的日期类型的对象。然而,这可能值有一些改变或信息的损失:
- 如果你将一个DATE值赋给一个DATETIME或TIMESTAMP对象,结果值的时间部分被设置为'00:00:00',因为DATE值不包含时间信息。
- 如果你将一个DATETIME或TIMESTAMP值赋给一个DATE对象,结果值的时间部分被删除,因为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'不是一个合法的月份。
- 以2位数字指定的年值是模糊的,因为世纪是未知的。MySQL使用下列规则解释2位年值:
- 在00-69范围的年值被变换到2000-2069。
- 在范70-99围的年值被变换到1970-1999。
7.3.6.3 TIME类型
MySQL检索并以'HH:MM:SS'格式显示TIME值(或对大小时值,'HHH:MM:SS'格式)。TIME值的范围可以从'-838:59:59'到'838:59:59'。小时部分可能很大的的原因是TIME类型不仅可以被使用在表示一天的时间(它必须是不到24个小时),而且用在表示在2个事件之间经过的时间或时间间隔(它可以是比24个小时大些,或甚至是负值)。
你能用多中格式指定TIME值:
- 作为'HH:MM:SS'格式的一个字符串。“宽松”的语法被允许--任何标点符号可用作时间部分的分隔符,例如,'10:11:12'和'10.11.12'是等价的。
- 作为没有分隔符的'HHMMSS'格式的一个字符串,如果它作为一个时间解释。例如,'101112'被理解为'10:11:12',但是'109712'是不合法的(它有无意义的分钟部分)并变成'00:00:00'。
- 作为HHMMSS格式的一个数字,如果它能解释为一个时间。例如,101112被理解为'10:11:12'。
- 返回值可在一个TIME上下文接受的函数,例如CURRENT_TIME。
对于作为包括一个时间分隔符的字符串被指定的TIME值,不必为小于10的小时、分钟或秒值指定2位数字,'8:3:2'与'08:03:02'是一样的。
将“短的”TIME值赋值给一个TIME行列是要格外小心。MySQL使用最右位代表秒的假设来解释值。(MySQL将TIME值解释为经过的时间,而非作为一天的时间 )例如,你可能想到'11:12'、'1112'和1112意味着'11:12:00'(11点12分),但是MySQL解释他们为'00:11:12'(11分12秒)。同样,'12'和12被解释为'00:00: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'或它是否是不合法的。
7.3.6.4 YEAR类型
YEAR类型是一个 1 字节类型用于表示年份。
MySQL检索并且以YYYY格式显示YEAR值,其范围是1901到2155。
你能用多种格式指定YEAR值:
- 作为在'1901'到'2155'范围的一个4位字符串。
- 作为在1901到2155范围的一个4位数字。
- 作为在'00'到'99'范围的一个2位字符串.在'00'到'69'和'70'到'99'范围的值被变换到在2000到2069范围和1970到1999的YEAR值。
- 作为在1到99范围的一个2位数字。在范围1到69和70到99的值被变换到在范围2001到2069和1970到1999的YEAR的值。注意对于2位数字的范围略微不同于2位数字字符串的范围,因为你不能直接指定零作为一个数字并且把它解释为2000。你必须作为一个字符串'0'或'00'指定它,它将被解释为0000。
- 其返回值可在一个YEAR上下文环境中接受的函数,例如NOW()。
不合法YEAR值被变换到0000。
7.3.7 字符串类型
字符串类型是CHAR、VARCHAR、BLOB、TEXT、ENUM和SET。
7.3.7.1 CHAR和VARCHAR类型
CHAR和VARCHAR类型是类似的,但是在他们被存储和检索的方式不同。
一个CHAR列的长度被修正为在你创造表时你所声明的长度。长度可以是1和255之间的任何值。(在MySQL 3.23中,CHAR长度可以是0~255。) 当CHAR值被存储时,他们被用空格在右边填补到指定的长度。当CHAR值被检索时,拖后的空格被删去。
在VARCHAR列中的值是变长字符串。你可以声明一个VARCHAR列是在1和255之间的任何长度,就像对CHAR列。然而,与CHAR相反,VARCHAR值只存储所需的字符,外加一个字节记录长度,值不被填补;相反,当值被存储时,拖后的空格被删去。(这个空格删除不同于ANSI SQL规范。)
如果你把一个超过列最大长度的值赋给一个CHAR或VARCHAR列,值被截断以适合它。
下表显示了两种类型的列的不同,通过演示存储变长字符串值到CHAR(4)和VARCHAR(4)列:
值 | CHAR(4) | 存储需求 | VARCHAR(4) | 存储需求 |
'' | ' ' | 4 个字节 | '' | 1 字节 |
'ab' | 'ab ' | 4 个字节 | 'ab' | 3 个字节 |
'abcd' | 'abcd' | 4 个字节 | 'abcd' | 5 个字节 |
'abcdefgh' | 'abcd' | 4 个字节 | 'abcd' | 5 个字节 |
从CHAR(4)和VARCHAR(4)列检索的值在每种情况下都是一样的,因为拖后的空格从检索的CHAR列上被删除。
在CHAR和VARCHAR列中存储和比较值是以大小写不区分的方式进行的,除非当桌子被创建时,BINARY属性被指定。BINARY属性意味着该列的值根据MySQL服务器正在运行的机器的ASCII顺序以大小写区分的方式存储和比较。
BINARY属性是“粘性”的。这意味着,如果标记了BINARY的列用于一个表达式中,整个的表达式作为一个BINARY值被比较。
MySQL在表创建时可以隐含地改变一个CHAR或VARCHAR列的类型。见7.7.1 隐含的的列说明改变。
7.3.7.2 BLOB和TEXT类型
一个BLOB是一个能保存可变数量的数据的二进制的大对象。4个BLOB类型TINYBLOB、BLOB、MEDIUMBLOB和LONGBLOB仅仅在他们能保存值的最大长度方面有所不同。见7.3.1 列类型存储需求。
4个TEXT类型TINYTEXT、TEXT、MEDIUMTEXT和LONGTEXT对应于4个BLOB类型,并且有同样的最大长度和存储需求。在BLOB和TEXT类型之间的唯一差别是对BLOB值的排序和比较以大小写敏感方式执行,而对TEXT值是大小写不敏感的。换句话说,一个TEXT是一个大小写不敏感的BLOB。
如果你把一个超过列类型最大长度的值赋给一个BLOB或TEXT列,值被截断以适合它。
在大多数方面,你可以认为一个TEXT行列是你所希望大的一个VARCHAR列。同样,你可以认为一个BLOB列是一个VARCHAR BINARY列。差别是:
- 用MySQL版本3.23.2和更新,你能在BLOB和TEXT列上索引。更旧的MySQL版本不支持这个。
- 当值被存储时,对BLOB和TEXT列没有拖后空格的删除,因为对VARCHAR列有删除。
- BLOB和TEXT列不能有DEFAULT值。
MyODBC定义BLOB为LONGVARBINARY,TEXT值为LONGVARCHAR。
因为BLOB和TEXT值可以是非常长的,当使用他们时,你可能遇到一些限制:
- 如果你想要在一个BLOB或TEXT列上使用GROUP BY或ORDER BY,你必须将列值变换成一个定长对象。这样做的标准方法是用SUBSTRING函数。例如:
mysql> select comment from tbl_name,substring(comment,20) as substr ORDER BY substr;
如果你不这样做,在排序时,只有列的首max_sort_length个字节被使用,缺省的max_sort_length是1024;这个值能在启动mysqld服务器时使用-O选择改变。你可以在包含BLOB或TEXT值得一个表达式上分组(group),通过指定列的位置或使用一个别名:
mysql> select id,substring(blob_col,1,100) from tbl_name GROUP BY 2; mysql> select id,substring(blob_col,1,100) as b from tbl_name GROUP BY b;
- 一个BLOB或TEXT对象的最大尺寸由其类型决定,但是你能在客户与服务器之间是实际传输的最大值由可用的内存数量和通讯缓冲区的大小来决定。你能改变消息缓冲区大小,但是你必须在服务器和客户两端做。见10.2.3 调节服务器参数。
注意,每个BLOB或TEXT值内部由一个独立分配的对象表示。这与所有的其他列类型相反,它们是在打开表时,按列被分配一次存储。
7.3.7.3 ENUM类型
一个ENUM是一个字符对象,其值通常从一个在表创建时明确被列举的允许值的一张表中选择。
在下列的某个情形下,值也可以空字符串("")或NULL:
- 如果你把一个无效值插入到一个ENUM(即,一个不在允许的值列表中的字符串),空字符串作为一个特殊错误的值被插入。
- 如果一个ENUM被声明为NULL,NULL也是列的合法值,并且缺省值是NULL。如果一个ENUM被声明为NOT NULL,缺省值是允许值的列表的第一成员。
每枚举值有一个编号:
- 在列说明中来自允许成员值列表值用从1开始编号。
- 空字符串错误值的编号值是0。这意味着,你能使用下列SELECT语句找出被赋给无效ENUM值的行:
mysql> SELECT * FROM tbl_name WHERE enum_col=0;
- NULL值的编号是NULL。
例如,指定为ENUM("one", "two", "three")的列可以有显示在下面的值的任何一个。每个值的编号也被显示:
值 | 编号 |
NULL | NULL |
"" | 0 |
"one" | 1 |
"two" | 2 |
"three" | 3 |
枚举可以有最大65535个成员。
当你把值赋给一个ENUM列时,字母的大小写是无关紧要的。然而,以后从列中检索的值大小写匹配在表创建时用来指定允许值的值的大小写。
如果你在一个数字的上下文环境中检索一个ENUM,列值的编号被返回。如果你存储一个数字到一个ENUM中,数字被当作一个标号,并且存储的值是该编号的枚举成员。
ENUM值根据列说明列举的枚举成员的次序被排序。(换句话说,ENUM值根据他们的编号数字被排序) 例如,对ENUM("a", "b"),"a"排在"b"前面,但是对ENUM("b", "a"),"b"排在"a"前面。空字符串排序非空字符串之前,并且NULL排在所有其他枚举值之前。
如果你想要得到一个ENUM列的所有可能的值,你应该使用:SHOW COLUMNS FROM table_name LIKE enum_column_name并且分析在第二列的ENUM定义。
7.3.7.4 SET类型
一个SET是可以有零或多个值的一个字符串对象,其每一个必须从表创建造被指定了的允许值的一张列表中被选择。由多个集合成员组成的SET列通过由由逗号分隔(“,”)的成员被指定,其推论是该SET成员值不能包含逗号本身。
例如, 一个指定为SET("one", "two") NOT NULL的列可以有这些值的任何一个:
"" "one" "two" "one,two" 一个SET能有最多64个不同的成员。
MySQL用数字值存储SET值,存储值的低阶位对应于第一个集合成员。如果你在数字上下文中检索一个SET值,检索的值把位设置位对应组成列值的集合成员。如果一个数字被存储进一个SET列,在数字的二进制表示中设置的位决定了在列中的集合成员。假定一个列被指定为SET("a","b","c","d"),那么成员有下列位值:
SET 成员 | 十进制的值 | 二进制的值 |
a | 1 | 0001 |
b | 2 | 0010 |
c | 4 | 0100 |
d | 8 | 1000 |
如果你给该列赋值9,即二进制的1001,这样第一个和第四个SET值成员"a"和"d"被选择并且结果值是"a,d"。
对于包含超过一个SET成员的值,当你插入值时,无所谓以什么顺序列举值,也无所谓给定的值列举了多少次。当以后检索值时,在值中的每个成员将出现一次,根据他们在表创建时被指定的顺序列出成员。例如,如果列指定为SET("a","b","c","d"),那么"a,d"、"d,a"和"d,a,a,d,d"在检索时将均作为"a,d"出现。
SET值以数字次序被排序。NULL指排在非NULL SET值之前。
通常,你使用LIKE操作符或FIND_IN_SET()函数执行在一个SET上的一个SELECT:
mysql> SELECT * FROM tbl_name WHERE set_col LIKE '%value%'; mysql> SELECT * FROM tbl_name WHERE FIND_IN_SET('value',set_col)>0;
但是下列也会工作:
mysql> SELECT * FROM tbl_name WHERE set_col = 'val1,val2'; mysql> SELECT * FROM tbl_name WHERE set_col & 1;
这些语句的第一个语句寻找一个精确的匹配。第二个寻找包含第一个集合成员的值。
如果你想要得到一个SET列的所有可能的值,你应该使用:SHOW COLUMNS FROM table_name LIKE set_column_name并且分析在第二列的SET定义。
7.3.8 为列选择正确的类型
为了最有效地使用存储空间,试着在所有的情况下使用最精确的类型。例如,如果一个整数列被用于在之间1和99999的值, MEDIUMINT UNSIGNED是最好的类型。
货币值的精确表示是一个常见的问题。在MySQL,你应该使用DECIMAL类型,它作为一个字符串被存储,不会发生精确性的损失。如果精确性不是太重要,DOUBLE类型也是足够好的。
对高精度,你总是能变换到以一个BIGINT存储的定点类型。这允许你用整数做所有的计算,并且仅在必要时将结果转换回浮点值。见10.6 选择一个表类型。
7.3.9 列索引
所有的MySQL列类型能被索引。在相关的列上的使用索引是改进SELECT操作性能的最好方法。
一个表最多可有16个索引。最大索引长度是256个字节,尽管这可以在编译MySQL时被改变。
对于CHAR和VARCHAR列,你可以索引列的前缀。这更快并且比索引整个列需要较少的磁盘空间。在CREATE TABLE语句中索引列前缀的语法看起来像这样:
KEY index_name (col_name(length))
下面的例子为name列的头10个字符创建一个索引:
mysql> CREATE TABLE test ( name CHAR(200) NOT NULL, KEY index_name (name(10)));
对于BLOB和TEXT列,你必须索引列的前缀,你不能索引列的全部。
7.3.10 多列索引
MySQL能在多个列上创建索引。一个索引可以由最多15个列组成。(在CHAR和VARCHAR列上,你也可以使用列的前缀作为一个索引的部分)。
一个多重列索引可以认为是包含通过合并(concatenate)索引列值创建的值的一个排序数组。
当你为在一个WHERE子句索引的第一列指定已知的数量时,MySQL以这种方式使用多重列索引使得查询非常快速,即使你不为其他列指定值。
假定一张表使用下列说明创建:
mysql> CREATE TABLE test ( id INT NOT NULL, last_name CHAR(30) NOT NULL, first_name CHAR(30) NOT NULL, PRIMARY KEY (id), INDEX name (last_name,first_name));
那么索引name是一个在last_name和first_name上的索引,这个索引将被用于在last_name或last_name和first_name的一个已知范围内指定值的查询,因此,name索引将使用在下列查询中:
mysql> SELECT * FROM test WHERE last_name="Widenius"; mysql> SELECT * FROM test WHERE last_name="Widenius" AND first_name="Michael"; mysql> SELECT * FROM test WHERE last_name="Widenius" AND (first_name="Michael" OR first_name="Monty"); mysql> SELECT * FROM test WHERE last_name="Widenius" AND first_name >="M" AND first_name < "N";
然而,name索引将不用在下列询问中:
mysql> SELECT * FROM test WHERE first_name="Michael"; mysql> SELECT * FROM test WHERE last_name="Widenius" OR first_name="Michael";
关于MySQL使用索引改进性能的方式的更多的信息,见10.4 使用MySQL索引。
7.3.11 使用来自其他数据库引擎的列类型
为了跟容易地使用为其他供应商的SQL实现编写的代码,下表显示了MySQL映射的列类型。这些映射使得从其他数据库引擎移动表定义到MySQL更容易:
其他供应商类型 | MySQL类型 |
BINARY(NUM) | CHAR(NUM) BINARY |
CHAR VARYING(NUM) | VARCHAR(NUM) |
FLOAT4 | FLOAT |
FLOAT8 | DOUBLE |
INT1 | TINYINT |
INT2 | SMALLINT |
INT3 | MEDIUMINT |
INT4 | INT |
INT8 | BIGINT |
LONG VARBINARY | MEDIUMBLOB |
LONG VARCHAR | MEDIUMTEXT |
MIDDLEINT | MEDIUMINT |
VARBINARY(NUM) | VARCHAR(NUM) BINARY |
列类型映射发生在表创建时。如果你用其他供应商使用的类型创建表,那么发出一个DESCRIBE tbl_name语句,MySQL使用等价的MySQL类型报告表结构。
7.4 用在SELECT和WHERE子句中的函数
在一个SQL语句中的select_expression或where_definition可由使用下面描述的函数的任何表达式组成。
包含NULL的一个表达式总是产生一个NULL值,否则除非表达式所包含的操作符和函数在文档中说明。
注意:在一个函数名和跟随它的括号之间不许没有空格。这帮助MySQL分析器区分函数调用和具有相同名字的对表或列的引用,尽管允许在参数周围有空格。
为了简洁,例子以缩写形式显示从mysql程序输出。因此:
mysql> select MOD(29,9); 1 rows in set (0.00 sec) +-----------+ | mod(29,9) | +-----------+ | 2 | +-----------+
被显示为这样:
mysql> select MOD(29,9); -> 2
7.4.1 分组函数
( ... ) 括号。使用它们来强制在一个表达式的计算顺序。mysql> select 1+2*3; -> 7 mysql> select (1+2)*3; -> 9
7.4.2 常用的算术操作
一般的算术操作符是可用的。注意在-、+和*情况下,如果两个参数是整数,结果用BIGINT(64位)精度计算! + 加法
mysql> select 3+5; -> 8- 减法
mysql> select 3-5; -> -2* 乘法
mysql> select 3*5; -> 15 mysql> select 18014398509481984*18014398509481984.0; -> 324518553658426726783156020576256.0 mysql> select 18014398509481984*18014398509481984; -> 0
最后一个表达式的结果是不正确的,因为整数乘积的结果超过用BIGINT计算的64位范围。
/ 除法mysql> select 3/5; -> 0.60
被零除产生一个NULL结果:
mysql> select 102/(1-1); -> NULL
一个除法用BIGINT算术计算,只要在它的结果被转换到一个整数的上下文中执行!
7.4.3 位函数
MySQL为位操作使用BIGINT(64位)算法,因此这些操作符有最大64位的一个范围。 | 位或
mysql> select 29 | 15; -> 31& 位与
mysql> select 29 & 15; -> 13<< 左移位一个长(BIGINT)数字。
mysql> select 1 << 2 -> 4>> 右移位一个长(BIGINT)数字。
mysql> select 4 >> 2 -> 1~ 颠倒所有的位。
mysql> select 5 & ~1 -> 4BIT_COUNT(N) 返回在参数N设定的位的数量。
mysql> select BIT_COUNT(29); -> 4
7.4.4 逻辑运算
所有的逻辑函数返回1(TRUE)或0(FALSE)。 NOT ! 逻辑非。如果参数是0,返回1,否则返回0。例外: NOT NULL返回NULL。
mysql> select NOT 1; -> 0 mysql> select NOT NULL; -> NULL mysql> select ! (1+1); -> 0 mysql> select ! 1+1; -> 1
最后的例子返回1,因为表达式作为(!1)+1计算。OR || 逻辑或。如果任何一个参数不是0并且不NULL,返回1。
mysql> select 1 || 0; -> 1 mysql> select 0 || 0; -> 0 mysql> select 1 || NULL; -> 1AND && 逻辑与。如果任何一个参数是0或NULL,返回0,否则返回1。
mysql> select 1 && NULL; -> 0 mysql> select 1 && 0; -> 0
7.4.5 比较运算符
比较操作得出值1(TRUE)、0(FALSE)或NULL等结果。这些函数工作运用在数字和字符串上。当需要时,字符串自动地被变换到数字且数字到字符串(如在Perl)。
MySQL使用下列规则执行比较:
- 如果一个或两个参数是NULL,比较的结果是NULL,除了<=>操作符。
- 如果在比较中操作的两个参数是字符串,他们作为字符串被比较。
- 如果两个参数是整数,他们作为整数被比较。
- 十六进制的值如果不与一个数字比较,则被当作二进制字符串。
- 如果参数之一是一个TIMESTAMP或DATETIME列而其他参数是一个常数,在比较执行前,常数被转换为一个时间标记。这样做是为了对ODBC更友好。
- 在所有其他的情况下,参数作为浮点(实数)数字被比较。
缺省地,字符串使用当前的字符集以大小写敏感的方式进行(缺省为ISO-8859-1 Latin1,它对英语运用得很出色)。
下面的例子演示了对于比较操作字符串到数字的转换:
mysql> SELECT 1 > '6x'; -> 0 mysql> SELECT 7 > '6x'; -> 1 mysql> SELECT 0 > 'x6'; -> 0 mysql> SELECT 0 = 'x6'; -> 1= 等于
mysql> select 1 = 0; -> 0 mysql> select '0' = 0; -> 1 mysql> select '0.0' = 0; -> 1 mysql> select '0.01' = 0; -> 0 mysql> select '.01' = 0.01; -> 1<> != 不等于
mysql> select '.01' <> '0.01'; -> 1 mysql> select .01 <> '0.01'; -> 0 mysql> select 'zapp' <> 'zappp'; -> 1<= 小于或等于
mysql> select 0.1 <= 2; -> 1< 小于
mysql> select 2 <= 2; -> 1>= 大于或等于
mysql> select 2 >= 2; -> 1> 大于
mysql> select 2 > 2; -> 0<=> 安全等于Null
mysql> select 1 <=> 1, NULL <=> NULL, 1 <=> NULL; -> 1 1 0IS NULL IS NOT NULL 测试值是否是或不是NULL
mysql> select 1 IS NULL, 0 IS NULL, NULL IS NULL: -> 0 0 1 mysql> select 1 IS NOT NULL, 0 IS NOT NULL, NULL IS NOT NULL;expr BETWEEN min AND max 如果expr对大于或等于min且expr是小于或等于max,BETWEEN返回1,否则它返回0。如果所有的参数类型是一样得,这等价于表达式(min <= expr AND expr <= max)。第一个参数(expr)决定比较如何被执行。如果expr是一个大小写不敏感的字符串表达式,进行一个大小写不敏感的字符串比较。如果expr是一个大小写敏感的字符串表达式,进行一个大小写敏感的字符串比较。如果expr是一个整数表达式,进行整数比较。否则,进行一个浮点(实数)比较。
mysql> select 1 BETWEEN 2 AND 3; -> 0 mysql> select 'b' BETWEEN 'a' AND 'c'; -> 1 mysql> select 2 BETWEEN 2 AND '3'; -> 1 mysql> select 2 BETWEEN 2 AND 'x-3'; -> 0expr IN (value,...) 如果expr是在IN表中的任何值,返回1,否则返回0。如果所有的值是常数,那么所有的值根据expr类型被计算和排序,然后项目的搜索是用二进制的搜索完成。这意味着如果IN值表全部由常数组成,IN是很快的。如果expr是一个大小写敏感的字符串表达式,字符串比较以大小写敏感方式执行。
mysql> select 2 IN (0,3,5,'wefwf'); -> 0 mysql> select 'wefwf' IN (0,3,5,'wefwf'); -> 1expr NOT IN (value,...) 与NOT (expr IN (value,...))相同。 ISNULL(expr) 如果expr是NULL,ISNULL()返回1,否则它返回0。
mysql> select ISNULL(1+1); -> 0 mysql> select ISNULL(1/0); -> 1
注意,使用=的NULL的值比较总为假!
COALESCE(list) 回来list中第一个非NULL的单元。mysql> select COALESCE(NULL,1); -> 1 mysql> select COALESCE(NULL,NULL,NULL); -> NULLINTERVAL(N,N1,N2,N3,...) 如果N< N1,返回0,如果N< N2,返回1等等。所有的参数被当作整数。为了函数能正确地工作,它要求N1<N2<N3< ...<Nn。这是因为使用二进制搜索(很快)。
mysql> select INTERVAL(23, 1, 15, 17, 30, 44, 200); -> 3 mysql> select INTERVAL(10, 1, 10, 100, 1000); -> 2 mysql> select INTERVAL(22, 23, 30, 44, 200); -> 0
7.4.6 字符串比较函数
通常,如果在字符串比较中的任何表达式是区分大小写的,比较以大小写敏感的方式执行。 expr LIKE pat [ESCAPE 'escape-char'] 使用SQL的简单的正规表达式比较的模式匹配。返回1(TRUE)或0(FALSE)。用LIKE,你可以在模式中使用下列2个通配符字符:
% | 匹配任何数目的字符,甚至零个字符 |
_ | 精确匹配一个字符 |
mysql> select 'David!' LIKE 'David_'; -> 1 mysql> select 'David!' LIKE '%D%v%'; -> 1
为了测试一个通配符的文字实例,用转义字符的加在字符前面。如果你不指定ESCAPE字符,假定为“\”:
\% | 匹配一%字符 |
\_ | 匹配一_字符 |
mysql> select 'David!' LIKE 'David\_'; -> 0 mysql> select 'David_' LIKE 'David\_'; -> 1 为了指定一个不同的转义字符,使用ESCAPE子句:
mysql> select 'David_' LIKE 'David|_' ESCAPE '|'; -> 1
LIKE允许用在数字的表达式上!(这是MySQL对ANSI SQL LIKE的一个扩充。)
mysql> select 10 LIKE '1%'; -> 1
注意:因为MySQL在字符串中使用C转义语法(例如,“\n”),你必须在你的LIKE字符串中重复任何“\”。例如,为了查找“\n”,指定它为“ \\n”,为了查找“\”,指定它为“\\\\”(反斜线被分析器剥去一次,另一次是在模式匹配完成时,留下一条单独的反斜线被匹配)。
expr NOT LIKE pat [ESCAPE 'escape-char'] 与NOT (expr LIKE pat [ESCAPE 'escape-char'])相同。 expr REGEXP pat expr RLIKE pat 执行一个字符串表达式expr对一个模式pat的模式匹配。模式可以是一个扩充的正则表达式。见MySQL 正则表达式句法的 H 描述.如果expr匹配pat,返回1,否则返回0。RLIKE是REGEXP的一个同义词,提供了与mSQL的兼容性。注意:因为MySQL在字符串中使用C转义语法(例如,“\n”), 你必须在你的REGEXP字符串重复任何“\”。在MySQL3.23.4中,REGEXP对于正常的(不是二进制)字符串是忽略大小写。mysql> select 'Monty!' REGEXP 'm%y%%'; -> 0 mysql> select 'Monty!' REGEXP '.*'; -> 1 mysql> select 'new*\n*line' REGEXP 'new\\*.\\*line'; -> 1 mysql> select "a" REGEXP "A", "a" REGEXP BINARY "A"; -> 1 0当决定一个字符的类型时,REGEXP和RLIKE使用当前的字符集(缺省为ISO-8859-1 Latin1)。 expr NOT REGEXP pat expr NOT RLIKE pat 与NOT (expr REGEXP pat)相同。 STRCMP(expr1,expr2) 如果字符串相同,STRCMP()回来0,如果第一参数根据当前的排序次序小于第二个,返回-1,否则返回1。
mysql> select STRCMP('text', 'text2'); -> -1 mysql> select STRCMP('text2', 'text'); -> 1 mysql> select STRCMP('text', 'text'); -> 0
7.4.7 类型转换运算符
BINARY BINARY操作符强制跟随它后面的字符串为一个二进制字符串。即使列没被定义为BINARY或BLOB,这是一个强制列比较区分大小写的简易方法。mysql> select "a" = "A"; -> 1 mysql> select BINARY "a" = "A"; -> 0
BINARY在MySQL 3.23.0中被引入。
7.4.8 控制流函数
IFNULL(expr1,expr2) 如果expr1不是NULL,IFNULL()返回expr1,否则它返回expr2。IFNULL()返回一个数字或字符串值,取决于它被使用的上下文环境。mysql> select IFNULL(1,0); -> 1 mysql> select IFNULL(0,10); -> 0 mysql> select IFNULL(1/0,10); -> 10 mysql> select IFNULL(1/0,'yes'); -> 'yes'IF(expr1,expr2,expr3) 如果expr1是TRUE(expr1<>0且expr1<>NULL),那么IF()返回expr2,否则它返回expr3。IF()返回一个数字或字符串值,取决于它被使用的上下文。
mysql> select IF(1>2,2,3); -> 3 mysql> select IF(1<2,'yes','no'); -> 'yes' mysql> select IF(strcmp('test','test1'),'yes','no'); -> 'no'
expr1作为整数值被计算,它意味着如果你正在测试浮点或字符串值,你应该使用一个比较操作来做。
mysql> select IF(0.1,1,0); -> 0 mysql> select IF(0.1<>0,1,0); -> 1
在上面的第一种情况中,IF(0.1)返回0,因为0.1被变换到整数值, 导致测试IF(0)。这可能不是你期望的。在第二种情况中,比较测试原来的浮点值看它是否是非零,比较的结果被用作一个整数。
CASE value WHEN [compare-value] THEN result [WHEN [compare-value] THEN result ...] [ELSE result] END CASE WHEN [condition] THEN result [WHEN [condition] THEN result ...] [ELSE result] END 第一个版本返回result,其中value=compare-value。第二个版本中如果第一个条件为真,返回result。如果没有匹配的result值,那么结果在ELSE后的result被返回。如果没有ELSE部分,那么NULL被返回。mysql> SELECT CASE 1 WHEN 1 THEN "one" WHEN 2 THEN "two" ELSE "more" END; -> "one" mysql> SELECT CASE WHEN 1>0 THEN "true" ELSE "false" END; -> "true" mysql> SELECT CASE BINARY "B" when "a" then 1 when "b" then 2 END; -> NULL