MySQL学习总结(适用版本:MySQL 3.23.7alpla)目录1. MySQL与标准的兼容性?31.1. MySQL对ANSI SQ L92扩充31.2. 以ANSI模式运行MySQL51.3. MySQL相比ANSI SQL92的差别61.4. MySQL缺乏的 功能61.4.1. 子选择61.4.2. SELECT INTO TABLE71.4.3. 事务处理71.4.4. 存储过程和触发 器71.4.5. 外键81.4.6. 视图91.4.7. ''--''作为一个注释的开始91.5. MySQL 遵循什么标准?101. 6. 怎样处理没有COMMIT/ROLLBACK102. MySQL 存取权限系统122.1. 权限系统做什么122.2. MyS QL 用户名和口令122.3. 与MySQL服务器连接132.4. 使你的口令安全142.5. MySQL提供的权限152.6. 权限系统工作原理172.7. 存取控制, 阶段1:连接证实202.8. 存取控制,阶段2:请求证实232.9. 权限更改何时生效2 52.10. 建立初始的MySQL权限262.11. 向MySQL增加新用户权限272.12. 怎样设置口令302.13. Acc ess denied错误的原因312.14. 怎样使MySQL安全以对抗解密高手343. MySQL语言参考353.1. 文字:怎 么写字符串和数字363.1.1. 字符串363.1.2. 数字383.1.3. 十六进制值383.1.4. NULL值383.1. 5. 数据库、表、索引、列和别名的命名393.2. 用户变量403.3. 列类型413.3.1. 列类型存储需求443.3.2. 数字类型443.3.3. 日期和时间类型453.3.4. 串类型453.3.5. 数字类型463.3.6. 日期和时间类型483. 3.7. 字符串类型543.3.8. 为列选择正确的类型583.3.9. 列索引593.3.10. 多列索引593.3.11. 使 用来自其他数据库引擎的列类型603.4. 用在SELECT和WHERE子句中的函数613.4.1. 分组函数613.4.2. 常用 的算术操作623.4.3. 位函数633.4.4. 逻辑运算633.4.5. 比较运算符643.4.6. 字符串比较函数683.4 .7. 类型转换运算符703.4.8. 控制流函数703.4.9. 数学函数713.4.10. 字符串函数773.4.11. 日期 和时间函数863.4.12. 其他函数943.4.13. 与GROUP BY子句一起使用的函数973.5. CREATE DATA BASE句法993.6. DROP DATABASE句法993.7. CREATE TABLE句法1003.7.1. 隐含的列说明 改变1053.8. ALTER TABLE句法1053.9. OPTIMIZE TABLE句法1083.10. DROP TABL E句法1093.11. DELETE句法1093.12. SELECT句法1093.13. JOIN句法1123.14. INSE RT句法1143.15. REPLACE句法1173.16. LOAD DATA INFILE句法1173.17. UPDATE句 法1243.18. USE句法1243.19. FLUSH句法(清除缓存)1253.20. KILL句法1253.21. SHOW 句法 (得到表,列等的信息)1263.22. EXPLAIN句法(得到关于SELECT的信息)1323.23. DESCRIBE句 法 (得到列的信息)1363.24. LOCK TABLES/UNLOCK TABLES句法1373.25. SET OPTION 句法1383.26. GRANT和REVOKE句法1393.27. CREATE INDEX句法1433.28. DROP IND EX句法1433.29. 注释句法1433.30. CREATE FUNCTION/DROP FUNCTION句法1443.31. MySQL对保留词很挑剔吗?145MySQL与标准的兼容性?MySQL对ANSI SQL92扩充MySQL包含了一些可能在其他S QL数据库找不到的扩充。要注意如果你使用他们,你的代码将不与其他SQL服务器兼容。在一些情况下,你可以编写包括MySQL扩展的代码 ,但是仍然是可移植的,通过使用/! ... /形式的注释。在这种情况下,MySQL将进行词法分析并且执行在注释内的代码,好像它 是任何其它MySQL语句,但是其他SQL服务器将忽略扩展。例如: SELECT /! STRAIGHT_JOIN / col_ name FROM table1,table2 WHERE ... 如果你在''!''后增加一个版本数字,该语法将仅在MySQL版本是 等于或比使用的版本数字新时才执行: CREATE /!32302 TEMPORARY / TABLE (a int);上面的意 思是如果你有3.23.02或更新,那么MySQL将使用TEMPORARY关键词。 MySQL扩展被列在下面: 字段类型MEDIUM INT、SET、ENUM和不同的BLOB和TEXT类型。 字段属性AUTO_INCREMENT、BINARY、UNSIGNED和Z EROFILL。 缺省地,所有的字符串比较是忽略大小写的,由当前的字符集决定了(缺省为ISO-8859-1 Latin1)排序顺序 。如果你不喜欢这样,你应该用BINARY属性或使用BINARY强制符声明列,它导致根据MySQL服务器主机的ASCII顺序进行排序 。 MySQL将每个数据库映射一个MySQL数据目录下面的目录,将数据库表映射到数据库目录下的数据库文件名。这有2个含意: 在区分 大小写文件名的操作系统(象大多数 Unix 系统一样)上的MySQL中数据库名字和表名是区分大小写的。如果你有困难记得表名,接受一 个一致的约定,例如总是用小写名字创建数据库和表。 数据库、表、索引、列或别名可以以数字开始(但是不能仅由数字组成)。 你可以使用标 准的系统命令备份、重命名、移动、删除和拷贝表。例如,重命名一个表,重命名“.MYD”、“.MYI”和“.frm”文件为相应的表。 在SQL语句中,你可以用db_name.tbl_name语法访问不同数据库中的表。一些SQL服务器提供同样的功能但是称它们为这Us er space(用户空间)。MySQL不支持类似在create table ralph.my_table...IN my_tab lespace中的表空间。 LIKE在数字列上被允许。 在一SELECT语句里面使用INTO OUTFILE和STRAIGHT_J OIN。见7.12 SELECT句法. 在一个SELECT语句中SQL_SMALL_RESULT选项。 EXPLAIN SELEC T得到如何联结表的描述。 在一个CREATE TABLE语句里面使用索引、在字段前缀上的索引和使用INDEX或KEY。见7.7 C REATE TABLE 句法。 CREATE TABLE使用TEMPORARY或IF NOT EXISTS。 使用COUNT(DI STINCT list),这里“list”超过一个元素。 在一个ALTER TABLE语句里面使用CHANGE col_name、 DROP col_name或DROP INDEX。见7.8 ALTER TABLE句法。 在一个ALTER TABLE里面语句使用 IGNORE。 在一个ALTER TABLE语句中使用多重ADD、ALTER、DROP或CHANGE子句。 使用带关键词IF EX ISTS的DROP TABLE。 你能用单个DROP TABLE语句抛弃多个表。 DELETE语句的LIMIT子句。 INSERT 和REPLACE语句的DELAYED子句。 INSERT, REPLACE, DELETE和UPDATE语句的LOW_PRIORI TY子句。 使用LOAD DATA INFILE。在多数情况下,这句法与Oracle的LOAD DATA INFILE兼容。见7. 16 LOAD DATA INFILE 句法。 OPTIMIZE TABLE语句。见7.9 OPTIMIZE TABLE句法。 S HOW语句。见7.21 SHOW句法(得到表、列等的信息)。 字符串可以被“"”或“''”包围,而不只是“''”。 使用“\”转义字符 。 SET OPTION语句。见7.25 SET OPTION句法。 你不需要命名所有在GROUP BY部分的被选择的列。这为一些 很特定的情况给出更好的性能,而不是一般的查询。见7.4.13 用于GROUP BY子句的函数。 为了方便来自于SQL环境其他为用户 ,MySQL对许多函数支持别名。例如,所有的字符串功能都支持ANSI SQL句法和 ODBC句法。 MySQL理解||和&&意味着 逻辑的OR和AND,就像在C程序语言中。在MySQL中,||和OR是同义词,&&和AND是同义词。正因为这个好的句法,MySQL对 字符串并置的不支持ANSI SQL ||操作符;相反使用CONCAT(),因为CONCAT()接受任何数量的参数,很容易把||操作 符使用变换到MySQL。 CREATE DATABASE或DROP DATABASE。见7.5 CREATE DATABASE句法 。 %操作符是MOD()一个同义词,即,N % M等价于MOD(N,M)。%支持C程序员并与PostgreSQL兼容。 =, <> , <=,<, >=,>, <<, >>, <=>, AND, OR或LIKE操作符可以放在SELECT语句的FROM左边用于比较 列。例如: mysql> SELECT col1=1 AND col2=2 FROM tbl_name;LAST_INSERT_I D()函数。见20.4.29 mysql_insert_id()。 扩展的正则表达式操作符REGEXP和NOT REGEXP。 C ONCAT()或CHAR()有一个参数或超过2个参数。(在MySQL中,这些函数可取任何数量的参数。) BIT_COUNT(), CASE, ELT(), FROM_DAYS(), FORMAT(), IF(), PASSWORD(), ENCRYPT(), md5(), ENCODE(), DECODE(), PERIOD_ADD(), PERIOD_DIFF(), TO_DAYS() ,或WEEKDAY()函数。 使用TRIM()整修子串。ANSI SQL 只支持单个字符的删除。 GROUP BY函数STD(), BIT_OR()和BIT_AND()。 使用REPLACE而不是DELETE+INSERT。见7.15 REPLACE句法。 F LUSH flush_option语句。 在一个语句用:=设置变量的可能性: SELECT @a:=SUM(total),@b=C OUNT(),@a/@b AS avg FROM test_table;SELECT @t1:=(@t2:=1)+@t3:=4, @t1,@t2,@t3;以ANSI模式运行MySQL如果你用--ansi选项启动mysqld,MySQL的下列行为改变。 ||是字 符串并置而不是OR。 可在一个函数名字之间与“(”有任何数量的空格。这也使所有的功能名字成为保留词。 "将是一个标识符引号字符(象 MySQL `引号字符一样)而不是一个字符串引号字符。 REAL将是FLOAT一个同义词,不是DOUBLE一个同义词。 MySQL 相比ANSI SQL92的差别我们尝试使得MySQL遵照ANSI SQL标准和ODBC SQL标准,但是在一些情况下,MySQL做 一些不同的事情: --只是一个注释,如果后面跟一个白空字符。见5.4.7 `--''作为一个注释的开始。 对于VARCHAR列,当值 被存储时,拖后的空格被删除。见E MySQL已知的错误和设计缺限。 在一些情况下,CHAR列偷偷地被改变为VARCHAR列。见7. 7.1 平静的列指定变化。 当你删除一个表时,对表的权限不自动地废除。你必须明确地发出一个REVOKE来废除对一个表的权限。见7. 26 GRANT和REVOKE句法。 MySQL缺乏的功能下列功能在当前的MySQL版本是没有的。对于一张优先级表指出何时新扩展可 以加入MySQL, 你应该咨询在线MySQL TODO 表。这是本手册最新的TODO表版本。见F 我们想要在未来加入到MySQL的 事情列表(TODO)。 子选择在MySQL中下列语句还不能工作: SELECT FROM table1 WHERE id IN (SELECT id FROM table2);SELECT FROM table1 WHERE id NOT IN (SE LECT id FROM table2);然而,在很多情况下,你可以重写查询,而不用子选择: SELECT table1. FR OM table1,table2 WHERE table1.id=table2.id;SELECT table1. FROM t able1 LEFT JOIN table2 ON table1.id=table2.id where table2.id IS NULL对于更复杂的子查询,通常你可以创建临时的表保存子查询。然而在一些情况下,这种选择将行不通。最经常遇到的情形是DELETE语 句,对于它标准SQL不支持联结(join)(除了在子选择)。对于这种情况,有2个可用选择,直到子选择被MySQL支持。 第一个选择 是使用一种过程化的程序语言(例如Perl或PHP)来提交一个SELECT查询获得要被删除记录主键,并然后使用这些值构造DELETE 语句(DELETE FROM ... WHERE ... IN (key1, key2, ...))。 第二个选择是使用交互式SQ L自动构造一套DELETE语句,使用MySQL扩展CONCAT()(代替标准||操作符)。例如: SELECT CONCAT(''D ELETE FROM tab1 WHERE pkid = '', tab1.pkid, '';'') FROM tab1, tab2 W HERE tab1.col1 = tab2.col2;你可以把这个查询放在一个脚本文件并且从它重定向输入到mysql命令行解释器, 将其输出作为管道返回给解释器的第2个实例: prompt> mysql --skip-column-names mydb < my script.sql | mysql mydbMySQL仅支持INSERT ... SELECT ...和REPLACE ... SELECT ...,独立的子选择将可能在3.24.0得到,然而,在其他环境下,你现在可以使用函数IN()。 SELECT INT O TABLEMySQL还不支持Oracle SQL的扩展:SELECT ... INTO TABLE ....,相反MySQL支 持ANSI SQL句法INSERT INTO ... SELECT ...,基本上他们是一样的。另外,你可使用SELECT INT O OUTFILE...或CREATE TABLE ... SELECT解决你的问题。 事务处理不支持事务处理。MySQL将在短时 间内支持原子(atomic)操作,它象没有回卷的事务。用原子操作,你能执行一组INSERT/SELECT/whatever 命令并 且保证没有其他线程介入。在本文中,你通常不会需要回卷。目前,你可通过使用LOCK TABLES和UNLOCK TABLES命令阻止 其他线程的干扰。见7.24 LOCK TABLES/UNLOCK TABLES句法。 存储过程和触发器一个存储过程是能在服务器中编 译并存储的一套SQL命令。一旦这样做了,顾客不需要一直重新发出全部查询,而可以参考存储过程。因为查询仅需一次词法分析并且较少的信息 需要在服务器和客户之间传送,因此这提供了更好的性能。你与可以通过拥有在服务器中的函数库提升概念上的层次。 一个触发器是当一个特别的 事件发生时,被调用的一个存储过程。例如,你可以安装一个存储过程,它在每次从一个交易表删除一条记录时触发,并且当它所有交易被删除时, 自动地从一个客户表中删除相应的客户。 计划修改的语言将能处理存储过程,但是没有触发器。触发器通常使每件事情变慢,即使对他们不需要的 查询。 为了俩解什么时候MySQL可能得到存储过程,见F 我们想在未来加入到MySQL的事情列表(TODO)。外键注意,在SQL中 外键不用于联结表,而主要用于检查参考完整性(RI)。如果你想要得到用一个SELECT语句从多个表得到结果, 你通过联结表做! SE LECT from table1,table2 where table1.id = table2.id; 见7.13 JOIN 句法。见8.3.5 使用外键。 在MySQL里存在FOREIGN KEY句法仅仅为了与其他SQL供应商的CREATE TABLE命 令相兼容;它不做任何事情。没有ON DELETE ...的FOREIGN KEY句法主要用于文档目的。一些ODBC应用程序可以使用 它自动生成WHERE子句,但是这通常很容易的覆盖。 FOREIGN KEY有时用作一个约束检查,但是如果行以正确的顺序被插入表,该 检查实际上是不必要的。MySQL仅仅支持这些子句(不考虑是否他们工作!),因为一些应用程序要求他们存在。 在MySQL中,你可以解 决ON DELETE ...没被实现的问题,,在你从一个用外键的表删除记录时,通过为一个应用程序增加适当的DELETE语句即可。实 际上,这很快(在一些情况下更快)并且比使用外键更比便于移植。 在不久的将来我们将扩充FOREIGN KEY实现,以便至少信息将在表 说明文件中保存并且可以由mysqldump和ODBC检索。 不使用外键的理由有很多与FOREIGN KEY有关的问题我们不知道从哪 儿开始: 外键使生活更复杂,因为外键的定义必须存储在一个数据库中并且实现他们将破坏使用能被移动、拷贝和删除文件的全部“好方法”。 速度影响对INSERT和UPDATE语句是可怕的,并且在这种情况下几乎所有的FOREIGN KEY检查都是无用的,因为不管怎样你通 常以正确的顺序在正确的表中插入记录。 当更新一张表时,也有在许多表上保存锁的需求,因为副作用可以串联通过全部数据库。首先从一张表中 删除记录并且随后从其他表中删除他们,这更快。 你再也不可以通过做一个全面的表删除并随后恢复所有的记录的方法来恢复一张表(从新来源或 从一个备份)。 如果你有外键,你不能倾倒和恢复表,除非你以一个非常特定的做这些。 很容易做一个“允许的”的循环定义使得不可能用一个 单个create语句重建每一个表,就算定义可行又可用。 FOREIGN KEY唯一好的方面是它给ODBC和一些其他客户程序检查一张 表如何被连接的能力,并且使用它们显示出连接图表并帮助构造应用。 MySQL不久将存储FOREIGN KEY定义以便一个客户能询问并 收到原来的连接如何进行的一个答案。当前的“.frm 文件格式没有它应有的地位。 视图MySQL不支持视图,但是它在TODO上。 '' --''作为一个注释的开始有些其他SQL数据库使用''--''开始注释。MySQL有“#”作为开始数注释的字符,即使mysql命令行工具 删除以''--''开始的所有行。你也可以在MySQL中使用C注释风格/ this is a comment /。见7.29 注释句 法。 MySQL3.23.3和以上版本支持''--''注释风格,只要注释跟在一个空格之后。这是因为这种退化的注释风格已经引起用像下列代 码那样的自动生成的SQL查询的许多问题,这里我们自动地为!payment!插入支付值: UPDATE tbl_name SET c redit=credit-!payment! 你想出当payment的值是负的时将发生什么吗? 因为1--1在SQL中是合法的,我 们认为''--''开始注释是可怕的。 然而在MySQL 3.23中,你可使用:1-- This is a comment 如果你正在运 行一个比3.23早的MySQL的版本,下列的讨论才涉及你: 如果你在一个文本文件中有一个SQL程序,它包含''--''注释,你应该使用 : shell> replace " --" " #" < text-file-with-funny-comments.sql \ | mysql database而不是通常: shell> mysql database < text-file-with-fu nny-comments.sql你也可以“现场”编辑命令文件将''--''注释改为''#''注释: shell> replace " -- " " #" -- text-file-with-funny-comments.sql用这个命令改回他们: shell> repl ace " #" " --" -- text-file-with-funny-comments.sqlMySQL 遵循什么标准?E ntry level SQL92。ODBC level 0-2。 怎样处理没有COMMIT/ROLLBACKMySQL不支持COM MIT-ROLLBACK。问题是有效地处理COMMIT-ROLLBACK将需要完全不同于MySQL今天使用的表布局。MySQL也将 需要额外的线程在表上做自动清除工作,而且磁盘用量将更高。这将使MySQL比现今慢上大约2-4倍。MySQL比几乎所有其他SQL数据 库都快(一般至少快2-3倍)。原因之一就是缺少COMMIT-ROLLBACK。 目前,我们是更多地实现SQL服务器语言(象存储过程 ),有了它,你将确实很少需要COMMIT-ROLLBACK,这也将得到更好的性能。 通常需要事务的循环可以借助LOCK TABLE S进行编码,并且当你能即时地更新记录时,你不需要光标(cursor)。 我们在TODO上有事务和光标,然而并非相当优先。如果我们实 现这些,将作为CREATE TABLE的选项,那意味着COMMIT-ROLLBACK将仅工作在那些表上,以便速度损失仅仅强加在那些 表上。 我们在TcX有一个更大的需求,一个比100%通用数据库的真正快速的数据库。无论何时我们发现一个方法来实现这些特征而没有任何 速度损失,我们将可能做它。暂时,有许多更重要的事情要做。检查TODO,看我们此时如何将事情优先排列。(有的较高级别支持的客户可以改 变它,因此事情是可以重新优先化的。)当前的问题实际上是ROLLBACK,没有ROLLBACK,你能用LOCK TABLES做任何C OMMIT动作。为了支持ROLLBACK,MySQL将必须被改变以存储所有的旧记录,如果发出ROLLBACK,它们被更新的并且将任 何东西恢复到起点。对于简单的情形,这不是难做的 (当前isamlog可以用于此目的),但是为ALTER/DROP/CREATE T ABLE实现ROLLBACK将是更困难的。 避免使用ROLLBACK,你可以使用下列策略: 使用LOCK TABLES ...锁住 所有你想要存取的数据库表。 测试条件。 如果一切无误,更新。 使用UNLOCK TABLES释放你的锁。 这通常比使用可能带ROL LBACK的交易是一个更快的方法,尽管不总是这样。这个解决方案不能处理的唯一状况是当某人在更新当中杀死线程时。在这种情况下,所有的 锁将被释放,但是一些更改不能被执行。 你也可使函数以单个操作更新记录。你能通过使用下列技术得到一个很有效率的应用程序: 相对他们的 当前的值修改字段 仅仅更新那些实际上更改的字段 例如,当我们正在更新一些客户信息时,我们仅仅更新那些改变了的客户数据并只测试没有任 何数据的改变,或数据取决于改变的数据,与原来的行相比变化了。对于改变了的数据的测试用WHERE子句在UPDATE语句中完成。如果记 录没被更新,我们给客户一条消息:“你改变了的一些数据已被其他用户改变了”,然后我们在一个窗口中显示新行对照旧行,因此用户能决定他该 使用哪个版本的客户记录。 这给了我们类似于“列锁定”的东西,但是实际上甚至更好,因为我们仅仅更新某些列,使用相对于他们的当前值的值 。这意味着典型的UPDATE语句看上去象这些一样东西: UPDATE tablename SET pay_back=pay_bac k+''relative change'';UPDATE customer SET customer_date=''current_da te'', address=''new address'', phone=''new phone'', money_he_owes_us=m oney_he_owes_us+''new_money'' WHERE customer_id=id AND address=''old address'' AND phone=''old phone'';正如你能看到的,这是很有效的并且就算其他客户已经改变了pay_ba ck或money_he_owes_us列的也能工作。 在许多情况下,为管理一些表格的唯一标识符目的,用户已经想要ROLLBACK或 LOCK TABLES。这可用一个AUTO_INCREMENT列和一个SQL函数LAST_INSERT_ID()或C API函数m ysql_insert_id()更高效地处理。见20.4.29 mysql_insert_id()。 在TcX,我们从来没有任何对 行级锁定的需求,因为我们总是能通过编码解决它。一些情况下需要确实行锁定,但是他们是很少见的。如果你想要行级锁定,你可以在表中使用标 志列并且这样做: UPDATE tbl_name SET row_flag=1 WHERE id=ID; 如果行被找到发现并且ro w_flag在原来的行已经不是1,对受影响的行数MySQL返回1。 你可以想到它,因为MySQL把上面的查询变为: UPDATE tbl_name SET row_flag=1 WHERE id=ID and row_flag <> 1;MySQL 存取权限系 统MySQL有一个先进但非标准的安全/权限系统。本节描述它的工作原理。 权限系统做什么MySQL权限系统的主要功能是证实连接到一台 给定主机的一个用户,并且赋予该用户在一个数据库上select、 insert、update和delete的权限。 附加的功能包括有 一个匿名的用户和对于MySQL特定的功能例如LOAD DATA INFILE进行授权及管理操作的能力。 MySQL 用户名和口令由 MySQL使用用户名和口令的方法与Unix或Windows使用的方式有很多不同之处: MySQL使用于认证目的的用户名,与Unix 用户名(登录名字)或Windows用户名无关。缺省地,大多数MySQL客户尝试使用当前Unix用户名作为MySQL用户名登录,但是 这仅仅为了方便。客户程序允许用-u或--user选项指定一个不同的名字,这意味着无论如何你不能使得一个数据库更安全,除非所有的My SQL用户名都有口令。任何人可以试图用任何名字连接服务器,而且如果他们指定了没有口令的任何名字,他们将成功。 MySQL用户名最长 可以是16各字符;典型地,Unix用户名限制为8个字符。 MySQL口令与Unix口令没关系。在你使用登录到一台Unix机器口令和 你使用在那台机器上存取一个数据库的口令之间没有必要有关联。 MySQL加密口令使用了一个Unix登录期间所用的不同算法,见7.4. 12 杂项函数一节中描述PASSWORD()和ENCRYPT()函数部分。 与MySQL服务器连接当你想要存取一个MySQL服务器 时,MySQL客户程序一般要求你指定连接参数:你想要联接的主机、你的用户名和你的口令。例如,mysql客户可以象这样启动(可选的参 数被包括在“[”和“]”之间): shell> mysql [-h host_name][-u user_name][-pyour _pass ]-h, -u和-p选项的另一种形式是--host=host_name、--user=user_name和--pass word=your_pass。注意在-p或--password=与跟随它后面的口令之间没有空格。 注意:在命令行上指定一个口令是不 安全的!随后在你系统上的任何用户可以通过打类似这样的命令发现你的口令:ps auxww。见4.15.4 选项文件。 对于命令行没有 的联接参数,mysql使用缺省值: 缺省主机名是localhost。 缺省用户名是你的Unix登录名。 如果没有-p,则没有提供口 令。 这样, 对一个Unix用户joe,下列命令是等价的: shell>mysql -h localhost -u joe she ll>mysql -h localhost shell>mysql -u joe shell>mysql其它MySQL客户程序有同 样表现。 在Unix系统上,当你进行一个连接时,你可以指定要使用的不同的缺省值,这样你不必每次在你调用一个客户程序是在命令行上输入 他们。这可以有很多方法做到: 你能在你的主目录下“.my.cnf”的配置文件的[client]小节里指定连接参数。文件的相关小节看 上去可能像这样: [client] host=host_name user=user_name password=your_pas s见4.15.4 选项文件。你可以用环境变量指定连接参数。主机可用MYSQL_HOST指定,MySQL用户名字可用USER指定(仅 对 Windows),口令可用MYSQL_PWD指定(但是这不安全,见下一节) 。 如果连接参数以多种方法被指定,在命令行上被指定 的值优先于在配置文件和环境变量中指定的值,而在配置文件指定的值优先于在环境变量指定的值。 使你的口令安全以一种暴露的可被其他用户发 现的方式指定你的口令是不妥当的。当你运行客户程序时,你可以使用下列方法指定你的口令,还有每个方法的风险评估: 使用一个在命令行上- pyour_pass或--password=your_pass的选项。这很方便但是不安全,因为你的口令对系统状态程序(例如ps)变 得可见,它可以被其他的用户调用来显示命令行。(一般MySQL客户在他们的初始化顺序期间用零覆盖命令行参数,但是仍然有一个短暂间隔时 间内参数值可见的。) 使用一个-p或--password选项(没有指定your_pass值)。在这种情况下,客户程序请求来自终端的 口令: shell>mysql - u user_name - pEnter password: 客户回应“” 字符到作为输入你的口令的终端使得旁观者不能看见它。因为它对其他用户不可见,与在命令行上指定它相比,这样进入你的口令更安全。然而,这 个输入一个口令的方法仅仅为你交互式运行程序是合适的。如果你想要从非交互式运行的一个脚本调用一个客户,就没有从终端输入入口令的机会。 在一个配置文件中存储你的口令。例如,你可你的主目录的“.my.cnf”文件中的[client]节列出你的口令: [client] password=your_pass如果你在“.my.cnf”里面存储口令,文件应该不是组或世界可读或可写的。保证文件的存取模式是 400或600。见4.15.4 选项文件。 你可在MYSQL_PWD环境变量中存储口令,但是这个方法必须想到是极不安全的且应该不使 用。ps的某些版本包括显示运行进程的环境的选项;如果你设定MYSQL_PWD,你的口令将对所有人是显而易见的,甚至在没有这样一个版 本的ps系统上,假设没有其他方法观察到进程环境是不明智的。 总之,最安全的方法是让客户程序提示口令或在一个适当保护的“.my.cn f”文件中指定口令。 MySQL提供的权限权限信息用user、db、host、tables_priv和columns_priv表被 存储在mysql数据库中(即在名为mysql的数据库中)。在MySQL启动时和在6.9 权限修改何时生效所说的情况时,服务器读入这 些数据库表内容。 本手册所用的涉及由MySQL提供的权限名称显示在下表,还有在授权表中每个权限的表列名称和每个权限有关的上下文: 权限 列 上下文 select Select_priv 表insert Insert_priv 表update Update_pr iv 表delete Delete_priv 表index Index_priv 表alter Alter_priv 表creat e Create_priv 数据库、表或索引drop Drop_priv 数据库或表grant Grant_priv 数据库或表r eferences References_priv 数据库或表reload Reload_priv 服务器管理shutdown S hutdown_priv 服务器管理process Process_priv 服务器管理file File_priv 在服务器上的 文件存取select、insert、update和delete权限允许你在一个数据库现有的表上实施操作。 SELECT语句只有在他 们真正从一个表中检索行是才需要select权限,你可以执行某个SELECT语句,甚至没有任何到服务器上的数据库里的存取任何东西的许 可。例如,你可使用mysql客户作为一个简单的计算器: mysql> SELECT 1+1;mysql> SELECT PI() 2;index权限允许你创建或抛弃(删除)索引。 alter权限允许你使用ALTER TABLE。 create和drop权限允许 你创建新的数据库和表,或抛弃(删除)现存的数据库和表。 注意:如果你将mysql数据库的drop权限授予一个用户,该用户能抛弃存储 了MySQL存取权限的数据库! grant权限允许你把你自己拥有的那些权限授给其他的用户。 file权限给予你用LOAD DATA INFILE和SELECT ... INTO OUTFILE语句读和写服务器上的文件,任何被授予这个权限的用户都能读或写MySQ L服务器能读或写的任何文件。 其余的权限用于管理性操作,它使用mysqladmin程序实施。下表显示mysqladmin支配每个管 理性权限允许你执行的命令: 优惠 权限拥有者允许执行的命令 reload reload, refresh, flush-privi leges, flush-hosts, flush-logs, flush-tables shutdown shutdown pr ecess processlist, kill reload命令告诉服务器再读入授权表,refresh命令清洗所有表并打开和关闭记 录文件,flush-privileges是reload的一个同义词,其它flush-命令执行类似refresh的功能,但是范围更 有限,并且在某些情况下可能更好用。例如,如果你只是想清洗记录文件,flush-logs比refresh是更好的选择。 shutdo wn命令关掉服务器。 processlist命令显示在服务器内执行的线程的信息。kill命令杀死服务器线程。你总是能显示或杀死你自 己的线程,但是你需要process权限来显示或杀死其他用户启动的线程。 总的说来,只授予权限给需要他们的那些用户是一个好主意,但是 你应该在授予某个权限时试验特定的警告: grant权限允许用户放弃他们的权限给其他用户。2个有不同的权限并有grant权限的用户可 以合并权限。 alter权限可以用于通过重新命名表来推翻权限系统。 file权限可以被滥用在服务器上读取任何世界可读(world- readable,即任何人可读)的文件到一张数据库表,然后其内容能用SELECT被存取。 shutdown权限通过终止服务器可以被 滥用完全拒绝为其他用户服务, 。 precess权限能被用来察看当前执行的查询的普通文本,包括设定或改变口令查询。 在mysql数 据库上的权限能被用来改变口令和其他存取权限信息。(口令被加密存储,所以一个恶意的用户不能简单地读取他们。然而,有足够的权限,同一个 用户能用不同的一个代替一个口令。) 有一些事情你不能用MySQL权限系统做到: 你不能明显地指定一个给定用户应该被拒绝存取。即,你 不能明显地匹配一个用户并且然后拒绝连接。 你不能指定一个用户有权创建立或抛弃一个数据库中的表,也不能创建或抛弃数据库本身。 权限系 统工作原理MySQL权限系统保证所有的用户可以严格地做他们假定被允许做的事情。当你连接一个MySQL服务器时, 你的身份由你从那连 接的主机和你指定的用户名来决定,系统根据你的身份和你想做什么来授予权限。 MySQL在认定身份中考虑你的主机名和用户名字,是因为有 很小的原因假定一个给定的用户在因特网上属于同一个人。例如,用户从whitehouse.gov连接的bill不必和从mosoft.c om连接bill是同一个人。 MySQL通过允许你区分在不同的主机上碰巧有同样名字用户来处理它:你可以对从whitehouse.g ov连接授与bill一个权限集,而为从microsoft.com的连接授予一个不同的权限集。 MySQL存取控制包含2个阶段: 阶 段1:服务器检查你是否允许连接。 阶段2:假定你能连接,服务器检查你发出的每个请求。看你是否有足够的权限实施它。例如,如果你从数据 库中一个表精选(select)行或从数据库抛弃一个表,服务器确定你对表有select权限或对数据库有drop权限。 服务器在存取控 制的两个阶段使用在mysql的数据库中的user、db和host表,在这些授权表中字段如下: 表名称 user db host 范 围字段 Host Host Host User Db Db Password User 权限字段 Select_priv Sele ct_priv Select_priv Insert_priv Insert_priv Insert_priv Update_pr iv Update_priv Update_priv Delete_priv Delete_priv Delete_priv In dex_priv Index_priv Index_priv Alter_priv Alter_priv Alter_priv C reate_priv Create_priv Create_priv Drop_priv Drop_priv Drop_priv Grant_priv Grant_priv Grant_priv Reload_priv Shutdown_priv Proces s_priv File_priv 对存取控制的第二阶段(请求证实),如果请求涉及表,服务器可以另外参考tables_priv和co lumns_priv表。这些表的字段如下: 表名称tables_priv columns_priv 范围字段 Host Host Db Db User User Table_name Table_name Column_name 权限字段 Table_priv Column_priv Column_priv 其他字段 Timestamp Timestamp Grantor 每个授权表包含 范围字段和权限字段。 范围字段决定表中每个条目的范围,即,条目适用的上下文。例如, 一个user表条目的Host和User值为''t homas.loc.gov''和''bob''将被用于证实来自主机thomas.loc.gov的bob对服务器的连接。同样,一个db表条 目的Host、User和Db字段的值是''thomas.loc.gov''、''bob''和''reports''将用在bob从主机联接tho mas.loc.gov存取reports数据库的时候。 tables_priv和columns_priv表包含范围字段,指出每个条 目适用的表或表/列的组合。 对于检查存取的用途,比较Host值是忽略大小写的。User、Password、Db和Table_nam e值是区分大小写的。Column_name值在MySQL3.22.12或以后版本是忽略大小写的。 权限字段指出由一个表条目授予的权 限,即,可实施什么操作。服务器组合各种的授权表的信息形成一个用户权限的完整描述。为此使用的规则在6.8 存取控制, 阶段2:请求证 实描述。范围字段是字符串,如下所述;每个字段的缺省值是空字符串: 字段名 类型 Host CHAR(60) User CHAR(1 6) Password CHAR(16) Db CHAR(64) (tables_priv和columns_priv表为CHAR( 60))在user、db和host表中,所有权限字段被声明为ENUM(''N'',''Y'')--每一个都可有值''N''或''Y'',并且缺省值 是''N''. 在tables_priv和columns_priv表中,权限字段被声明为SET字段: 表名 字段名 可能的集合成员 t ables_priv Table_priv ''Select'', ''Insert'', ''Update'', ''Delete'', ''Cr eate'', ''Drop'', ''Grant'', ''References'', ''Index'', ''Alter'' tables_pri v Column_priv ''Select'', ''Insert'', ''Update'', ''References'' columns_ priv Column_priv ''Select'', ''Insert'', ''Update'', ''References'' 简单地说, 服务器使用这样的授权表: user表范围字段决定是否允许或拒绝到来的连接。对于允许的连接,权限字段指出用户的全局(超级用户)权限。 db和host表一起使用: db表范围字段决定用户能从哪个主机存取哪个数据库。权限字段决定允许哪个操作。 当你想要一个给定的db 条目应用于若干主机时,host表作为db表的扩展被使用。例如,如果你想要一个用户能在你的网络从若干主机使用一个数据库,在用户的db 表的Host条目设为空值,然后将那些主机的每一个移入host表。这个机制详细描述在6.8 存取控制, 阶段2:请求证实。 tabl es_priv和columns_priv表类似于db表,但是更精致:他们在表和列级应用而非在数据库级。 注意管理权限(reload , shutdown, 等等)仅在user表中被指定。这是因为管理性操作是服务器本身的操作并且不是特定数据库,因此没有理由在其他授 权表中列出这样的权限。事实上,只需要请教user表来决定你是否执行一个管理操作。 file权限也仅在user表中指定。它不是管理性 权限,但你读或谢在服务器主机上的文件的的能力独立于你正在存取的数据库。 当mysqld服务器启动时,读取一次授权表内容。对授权表的 更改生效在6.9 权限更改何时生效描述。 当你修改授权表的内容时,确保你按你想要的方式更改权限设置是一个好主意。为帮助诊断问题,见 6.13 “存取拒绝引起”错误的原因。对于安全问题上的忠告,见6.14 怎么对使MySQL安全对抗解密高手。 一个有用的诊断工具是 mysqlaccess脚本,由Carlier Yves 提供给MySQL分发。使用--help选项调用mysqlaccess查明它 怎样工作。注意:mysqlaccess仅用user、db和host表仅检查存取。它不检查表或列级权限。 存取控制, 阶段1:连接证 实当你试图联接一个MySQL服务器时,服务器基于你的身份和你是否能通过供应正确的口令验证身份来接受或拒绝连接。如果不是,服务器完全 具结你的存取,否则,服务器接受连接,然后进入阶段2并且等待请求。 你的身份基于2个信息: 你从那个主机连接 你的MySQL用户名 身份检查使用3个user表(Host, User和Password)范围字段执行。服务器只有在一个user表条目匹配你的主机名和用 户名并且你提供了正确的口令时才接受连接。 在user表范围字段可以如下被指定: 一个Host值可以是主机名或一个IP数字,或''lo calhost''指出本地主机。 你可以在Host字段里使用通配符字符“%”和“_”。 一个Host值''%''匹配任何主机名,一个空白 Host值等价于''%''。注意这些值匹配能创建一个连接到你的服务器的任何主机! 通配符字符在User字段中不允许,但是你能指定空白的 值,它匹配任何名字。如果user表匹配到来的连接的条目有一个空白的用户名,用户被认为是匿名用户(没有名字的用户),而非客户实际指定 的名字。这意味着一个空白的用户名被用于在连接期间的进一步的存取检查(即,在阶段2期间)。 Password字段可以是空白的。这不意 味着匹配任何口令,它意味着用户必须不指定一个口令进行连接。 非空白Password值代表加密的口令。 MySQL不以任何人可以看的 纯文本格式存储口令,相反,正在试图联接的一个用户提供的口令被加密(使用PASSWORD()函数),并且与存储了user表中的已经加 密的版本比较。如果他们匹配,口令是正确的。 下面的例子显示出各种user表中Host和User条目的值的组合如何应用于到来的连接: Host 值 User 值 被条目匹配的连接 ''thomas.loc.gov'' ''fred'' fred, 从thomas.loc .gov 连接''thomas.loc.gov'' '''' 任何用户, 从thomas.loc.gov连接 ''%'' ''fred'' fre d, 从任何主机连接''%'' '''' 任何用户, 从任何主机连接''%.loc.gov'' ''fred'' fred, 从在loc.gov域 的任何主机连接''x.y.%'' ''fred'' fred, 从x.y.net、x.y.com,x.y.edu等联接。(这或许无用)''1 44.155.166.177'' ''fred'' fred, 从有144.155.166.177 IP 地址的主机连接''144.155 .166.%'' ''fred'' fred, 从144.155.166 C类子网的任何主机连接既然你能在Host字段使用IP通配符值( 例如,''144.155.166.%''匹配在一个子网上的每台主机),有可能某人可能企图探究这种能力,通过命名一台主机为144.155 .166.somewhere.com。为了阻止这样的企图,MySQL不允许匹配以数字和一个点起始的主机名,这样,如果你用一个命名为 类似1.2.foo.com的主机,它的名字决不会匹配授权表中Host列。只有一个IP数字能匹配IP通配符值。 一个到来的连接可以被 在user表中的超过一个条目匹配。例如,一个由fred从thomas.loc.gov的连接匹配多个条目如上所述。如果超过一个匹配, 服务器怎么选择使用哪个条目呢?服务器在启动时读入user表后通过排序来解决这个问题,然后当一个用户试图连接时,以排序的顺序浏览条目 ,第一个匹配的条目被使用。 user表排序工作如下,假定user表看起来像这样: +-----------+----------+ -| Host | User | ...+-----------+----------+-| % | root | ...| % | jeffrey | ...| localhost | root | ...| localhost | | ...+-----------+----------+-当服务器 在表中读取时,它以最特定的Host值为先的次序排列(''%''在Host列里意味着“任何主机”并且是最不特定的)。有相同Host值的条 目以最特定的User值为先的次序排列(一个空白User值意味着“任何用户”并且是最不特定的)。最终排序的user表看起来像这样: +-----------+----------+-| Host | User | ...+----------- +----------+-| localhost | root | ...| localhost | | ...| % | jeffrey | ...| % | root | ...+---- -------+----------+-当一个连接被尝试时,服务器浏览排序的条目并使用找到的第一个匹配。对于由jeffrey从lo calhost的一个连接,在Host列的''localhost''条目首先匹配。那些有空白用户名的条目匹配连接的主机名和用户名。(''% ''/''jeffrey''条目也将匹配,但是它不是在表中的第一匹配。)这是另外一个例子。假定user桌子看起来像这样: +------ ----------+----------+-| Host | User | ...+-------- --------+----------+-| % | jeffrey | ...| thomas.lo c.gov | | ...+----------------+----------+-排序后的表看起来像这样: +----------------+----------+-| Host | User | ...+- ---------------+----------+-| thomas.loc.gov | | ...| % | jeffrey | ...+----------------+----------+-一个由jef frey从thomas.loc.gov的连接被第一个条目匹配,而一个由jeffrey从whitehouse.gov的连接被第二个匹 配。 普遍的误解是认为,对一个给定的用户名,当服务器试图对连接寻找匹配时,明确命名那个用户的所有条目将首先被使用。这明显不是事实。 先前的例子说明了这点,在那里一个由jeffrey从thomas.loc.gov的连接没被包含''jeffrey''作为User字段值的 条目匹配,但是由没有用户名的题目匹配! 如果你有服务器连接的问题,打印出user表并且手工排序它看看第一个匹配在哪儿进行。 存取控 制,阶段2:请求证实一旦你建立了一个连接,服务器进入阶段2。对在此连接上进来的每个请求,服务器检查你是否有足够的权限来执行它,它基 于你希望执行的操作类型。这正是在授权表中的权限字段发挥作用的地方。这些权限可以来子user、db、host、tables_priv 或columns_priv表的任何一个。授权表用GRANT和REVOKE命令操作。见7.26 GRANT和REVOKE 句法。(你 可以发觉参考6.6 权限系统怎样工作很有帮助,它列出了在每个权限表中呈现的字段。)user表在一个全局基础上授予赋予你的权限,该权 限不管当前的数据库是什么均适用。例如,如果user表授予你delete权限, 你可以删除在服务器主机上从任何数据库删除行!换句话说 ,user表权限是超级用户权限。只把user表的权限授予超级用户如服务器或数据库主管是明智的。对其他用户,你应该把在user表中的 权限设成''N''并且仅在一个特定数据库的基础上授权, 使用db和host表。 db和host表授予数据库特定的权限。在范围字段的值可 以如下被指定: 通配符字符“%”和“_”可被用于两个表的Host和Db字段。 在db表的''%''Host值意味着“任何主机”,在db 表中一个空白Host值意味着“对进一步的信息咨询host表”。 在host表的一个''%''或空白Host值意味着“任何主机”。 在两 个表中的一个''%''或空白Db值意味着“任何数据库”。 在两个表中的一个空白User值匹配匿名用户。 db和host表在服务器启动时 被读取和排序(同时它读user表)。db表在Host、Db和User范围字段上排序,并且host表在Host和Db范围字段上排序。 对于user表,排序首先放置最特定的值然后最后最不特定的值,并且当服务器寻找匹配入条目时,它使用它找到的第一个匹配。 tables _priv和columns_priv表授予表和列特定的权限。在范围字段的值可以如下被指定: 通配符“%”和“_”可用在使用在两个表 的Host字段。 在两个表中的一个''%''或空白Host意味着“任何主机”。 在两个表中的Db、Table_name和Column_ name字段不能包含通配符或空白。 tables_priv和columns_priv表在Host、Db和User字段上被排序。这类 似于db表的排序,尽管因为只有Host字段可以包含通配符,但排序更简单。 请求证实进程在下面描述。(如果你熟悉存取检查的源代码,你 会注意到这里的描述与在代码使用的算法略有不同。描述等价于代码实际做的东西;它只是不同于使解释更简单。)对管理请求(shutdown 、reload等等),服务器仅检查user表条目,因为那是唯一指定管理权限的表。如果条目许可请求的操作,存取被授权了,否则拒绝。例 如,如果你想要执行mysqladmin shutdown,但是你的user表条目没有为你授予shutdown权限,存取甚至不用检查 db或host表就被拒绝。(因为他们不包含Shutdown_priv行列,没有这样做的必要。)对数据库有关的请求(insert、u pdate等等),服务器首先通过查找user表条目来检查用户的全局(超级用户)权限。如果条目允许请求的操作,存取被授权。如果在us er表中全局权限不够,服务器通过检查db和host表确定特定的用户数据库权限: 服务器在db表的Host、Db和User字段上查找 一个匹配。 Host和User对应连接用户的主机名和MySQL用户名。Db字段对应用户想要存取的数据库。如果没有Host和User 的条目,存取被拒绝。 如果db表中的条目有一个匹配而且它的Host字段不是空白的,该条目定义用户的数据库特定的权限。 如果匹配的d b表的条目的Host字段是空白的,它表示host表列举主机应该被允许存取数据库的主机。在这种情况下,在host表中作进一步查找以发 现Host和Db字段上的匹配。如果没有host表条目匹配,存取被拒绝。如果有匹配,用户数据库特定的权限以在db和host表的条目的 权限,即在两个条目都是''Y''的权限的交集(而不是并集!)计算。(这样你可以授予在db表条目中的一般权限,然后用host表条目按一个 主机一个主机为基础地有选择地限制它们。) 在确定了由db和host表条目授予的数据库特定的权限后,服务器把他们加到由user表授予 的全局权限中。如果结果允许请求的操作,存取被授权。否则,服务器检查在tables_priv和columns_priv表中的用户的表 和列权限并把它们加到用户权限中。基于此结果允许或拒绝存取。 用布尔术语表示,前面关于一个用户权限如何计算的描述可以这样总结: gl obal privilegesOR (database privileges AND host privileges)OR tab le privilegesOR column privileges它可能不明显,为什么呢,如果全局user条目的权限最初发现对请求 的操作不够,服务器以后把这些权限加到数据库、表和列的特定权限。原因是一个请求可能要求超过一种类型的权限。例如,如果你执行一个INS ERT ... SELECT语句,你就都要insert和select权限。你的权限必须如此以便user表条目授予一个权限而db表条 目授予另一个。在这种情况下,你有必要的权限执行请求,但是服务器不能自己把两个表区别开来;两个条目授予的权限必须组合起来。 host 表能被用来维护一个“安全”服务器列表。在TcX,host表包含一个在本地的网络上所有的机器的表,这些被授予所有的权限。 你也可以使 用host表指定不安全的主机。假定你有一台机器public.your.domain,它位于你不认为是安全的一个公共区域,你可以用下 列的host表条目子允许除了那台机器外的网络上所有主机的存取: +--------------------+----+-| Hos t | Db | ...+--------------------+----+-| public.yo ur.domain | % | ... (所有权限设为 ''N'')| %.your.domain | % | ... (所有权限设为 ''Y'')+--------------------+----+-当然,你应该总是测试你在授权表中的条目(例如,使用 mysqlaccess)让你确保你的存取权限实际上以你认为的方式被设置。 权限更改何时生效当mysqld启动时,所有的授权表内容被 读进存储器并且从那点生效。 用GRANT、REVOKE或SET PASSWORD对授权表施行的修改会立即被服务器注意到。 如果你手 工地修改授权表(使用INSERT、UPDATE等等),你应该执行一个FLUSH PRIVILEGES语句或运行mysqladmin flush-privileges告诉服务器再装载授权表,否则你的改变将不生效,除非你重启服务器。 当服务器注意到授权表被改变了时 ,现存的客户连接有如下影响: 表和列权限在客户的下一次请求时生效。 数据库权限改变在下一个USE db_name命令生效。 全局权 限的改变和口令改变在下一次客户连接时生效。 建立初始的MySQL权限在安装MySQL后,你通过运行scripts/mysql_in stall_db安装初始的存取权限。见4.7.1 快速安装概述。 scripts/mysql_install_db脚本启动mysq ld服务器,然后初始化授权表,包含下列权限集合: MySQL root用户作为可做任何事情的一个超级用户被创造。连接必须由本地主机 发出。注意:出世的root口令是空的,因此任何人能以root而没有一个口令进行连接并且被授予所有权限。 一个匿名用户被创造,他可对 有一个''test''或以''test_''开始的名字的数据库做任何时期事情,连接必须由本地主机发出。这意味着任何本地用户能连接并且视为匿 名用户。 其他权限被拒绝。例如,一般用户不能使用mysqladmin shutdown或mysqladmin processlis t。 注意:对Win32的初始权限是不同的。见4.12.4 在Win32上运行MySQL。 既然你的安装初始时广开大门,你首先应该 做的事情之一是为MySQL root用户指定一个口令。你可以做如下(注意,你使用PASSWORD()函数指定口令): shell> mysql -u root mysqlmysql> UPDATE user SET Password=PASSWORD(''new _password'') WHERE user=''root'';mysql> FLUSH PRIVILEGES;在MySQL 3.22 和以上版本中,你可以使用SET PASSWORD语句: shell> mysql -u root mysqlmysql> SET PASSWORD FOR root=PASSWORD(''new_password'');设置口令的另一种方法是使用mysqladmi n命令: shell> mysqladmin -u root password new_password 注意:如果你使用第一种方 法在user表里直接更新口令,你必须告诉服务器再次读入授权表(用FLUSH PRIVILEGES),因为否则改变将不被注意到。 一 旦root口令被设置,此后当你作为root与服务器连接时,你必须供应那个口令。 你可能希望让root口令为空白以便当你施行附加的安 装时,你不需要指定它或测试,但是保证在任何真实的生产工作中使用你的安装之前,设置它。 看看scripts/mysql_instal l_db脚本,看它如何安装缺省的权限。你可用它作为一个研究如何增加其他用户的基础。 如果你想要初始的权限不同于上面描述的那些,在你 运行mysql_install_db之前,你可以修改它。 为了完全重建权限表,删除在包含mysql数据库的目录下所有“.frm” ,“.MYI”和“.MYD”文件。(这是在数据库目录下面命名为“mysql”的目录,当你运行mysqld --help时,它被 列出。)然后运行mysql_install_db脚本,可能在首先编辑它拥有你想要的权限之后。 注意:对于比MySQL 3.22.1 0旧的版本,你不应该删除“.frm”文件。如果你偶然做了,你应该在运行mysql_install_db之前你的MySQL分发中拷 回它们。 向MySQL增加新用户权限你可以有2个不同的方法增加用户:通过使用GRANT语句或通过直接操作MySQL授权表。比较好的 方法是使用GRANT语句,因为他们是更简明并且好像错误少些。 下面的例子显示出如何使用mysql客户安装新用户。这些例子假定权限根 据以前的章节描述的缺省被安装。这意味着为了改变,你必须在mysqld正在运行同一台机器上,你必须作为MySQL root用户连接, 并且root用户必须对mysql数据库有insert权限和reload管理权限。另外,如果你改变了root用户口令,你必须如下的m ysql命令指定它。 你可以通过发出GRANT语句增加新用户: shell> mysql --user=root mysqlmys ql> GRANT ALL PRIVILEGES ON . TO monty@localhost IDENTIFIED BY ''something'' WITH GRANT OPTION;mysql> GRANT ALL PRIVILEGES ON . TO monty@"%" IDENTIFIED BY ''something'' WITH GRANT OPTION;mysql> G RANT RELOAD,PROCESS ON . TO admin@localhost;mysql> GRANT USAGE ON . TO dummy@localhost;这些GRANT语句安装3个新用户: monty 可以从任何地方连接服务器的一个 完全的超级用户,但是必须使用一个口令(''something''做这个。注意,我们必须对monty@localhost和monty@" %"发出GRANT语句。如果我们增加localhost条目,对localhost的匿名用户条目在我们从本地主机连接接时由mysql _install_db创建的条目将优先考虑,因为它有更特定的Host字段值,所以以user表排列顺序看更早到来。 admin 可以 从localhost没有一个口令进行连接并且被授予reload和process管理权限的用户。这允许用户执行mysqladmin reload、mysqladmin refresh和mysqladmin flush-命令,还有mysqladmin proce sslist。没有授予数据库有关的权限。他们能在以后通过发出另一个GRANT语句授权。 dummy 可以不用一个口令连接的一个用户 ,但是只能从本地主机。全局权限被设置为''N''--USAGE权限类型允许你无需权限就可设置一个用户。它假定你将在以后授予数据库相关的 权限。 你也可以直接通过发出INSERT语句增加同样的用户存取信息,然后告诉服务器再次装入授权表: shell> mysql -- user=root mysqlmysql> INSERT INTO user VALUES(''localhost'',''monty'' ,PASSWORD(''something''), ''Y'',''Y'',''Y'',''Y'',''Y'',''Y'',''Y'',''Y'',''Y'',''Y'','' Y'',''Y'',''Y'',''Y'')mysql> INSERT INTO user VALUES(''%'',''monty'',PASSWOR D(''something''), ''Y'',''Y'',''Y'',''Y'',''Y'',''Y'',''Y'',''Y'',''Y'',''Y'',''Y'',''Y'','' Y'',''Y'')mysql> INSERT INTO user SET Host=''localhost'',User=''admin'', Reload_priv=''Y'', Process_priv=''Y'';mysql> INSERT INTO user (Host, User,Password) VALUES(''localhost'',''dummy'','''');mysql> FLUSH PRIVIL EGES;取决于你的MySQL版本,对上述,你可能必须使用一个不同数目''Y''值(在3.22.11以前的版本有更少的权限列)。对ad min用户,只用在3.22.11开始的版本具有的更加可读的INSERT扩充的语法。 注意,为了设置一个超级用户,你只需创造一个us er表条目,其权限字段设为''Y''。不需要db或host表的条目。 在user表中的权限列不是由最后一个INSERT语句明确设置的( 对dummy用户),因此那些列被赋予缺省值''N''。这是GRANT USAGE做的同样的事情。 下列例子增加一个用户custom,他 能从主机localhost、server.domain和whitehouse.gov连接。他只想要从localhost存取bank account数据库,从whitehouse.gov存取expenses数据库和从所有3台主机存取customer数据库。他想要从 所有3台主机上使用口令stupid。 为了使用GRANT语句设置个用户的权限,运行这些命令: shell> mysql --use r=root mysqlmysql> GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP ON bankaccount. TO custom@localhost IDENTIFIED BY ''stupid'';mysql > GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP ON expenses. TO custom@whitehouse.gov IDENTIFIED BY ''stupid'';mysql> GRANT SELECT, INSERT,UPDATE,DELETE,CREATE,DROP ON customer. TO custom@''%'' IDEN TIFIED BY ''stupid'';通过直接修改授权表设置用户权限,运行这些命令(注意,在结束时FLUSH PRIVILEGES ): shell> mysql --user=root mysqlmysql> INSERT INTO user (Host,Us er,Password) VALUES(''localhost'',''custom'',PASSWORD(''stupid''));mysq l> INSERT INTO user (Host,User,Password) VALUES(''server.domain'','' custom'',PASSWORD(''stupid''));mysql> INSERT INTO user (Host,User,Pa ssword) VALUES(''whitehouse.gov'',''custom'',PASSWORD(''stupid''));mysq l> INSERT INTO db (Host,Db,User,Select_priv,Insert_priv,Update_pr iv,Delete_priv, Create_priv,Drop_priv) VALUES (''localhost'',''banka ccount'',''custom'',''Y'',''Y'',''Y'',''Y'',''Y'',''Y'');mysql> INSERT INTO db ( Host,Db,User,Select_priv,Insert_priv,Update_priv,Delete_priv, Cre ate_priv,Drop_priv) VALUES (''whitehouse.gov'',''expenses'',''custom'', ''Y'',''Y'',''Y'',''Y'',''Y'',''Y'');mysql> INSERT INTO db (Host,Db,User,Sele ct_priv,Insert_priv,Update_priv,Delete_priv, Create_priv,Drop_pri v) VALUES(''%'',''customer'',''custom'',''Y'',''Y'',''Y'',''Y'',''Y'',''Y'');mysql> FLUSH PRIVILEGES;头3个INSERT语句增加user表条目,允许用户custom用给定口令从不同的主机进行连接, 但是没有授予任何许可(所有权限被设置为缺省值''N'')。后3个INSERT语句增加db表条目,授予custom以bankaccoun t、expenses和customer数据库权限,但是只能在从正确的主机存取时。通常,在授权表直接被修改时,服务器必须被告知再次装 入他们(用FLUSH PRIVILEGES)以便使权限修改生效。如果你想要给特定的用户从一个给定的域上的任何机器上存取权限,你可以 发出一个如下的GRANT语句: mysql> GRANT ... ON . TO myusername@"%.mydomain name.com" IDENTIFIED BY ''mypassword'';为了通过直接修改授权表做同样的事情,这样做: mysql > INSERT INTO user VALUES (''%.mydomainname.com'', ''myusername'', PA SSWORD(''mypassword''),...);mysql> FLUSH PRIVILEGES;你也可以使用xmysqladm in、mysql_webadmin甚至xmysql在授权表中插入、改变和更新值。你可以在MySQL的Contrib目录找到这些实用 程序。 怎样设置口令在前面小节的例子里说明了一个重要的原则:当你使用INSERT或UPDATE语句存储一个非空的口令时,你必须使用 PASSWORD()函数加密它。这是因为在user表中以加密形式存储口令,而不是作为纯文本。如果你忘记这个事实,你可能像这样试图设 置口令: shell> mysql -u root mysql mysql> INSERT INTO user (Host,Use r,Password) VALUES(''%'',''jeffrey'',''biscuit''); mysql> FLUSH PRIVILE GES结果是纯文本值''biscuit''作为口令被存储在user表中。在用户jeffrey试图用这个口令连接服务器时,mysql客户 用PASSWORD()加密它并且将结果送给服务器,服务器比较在user表中的值(它是纯文本值''biscuit'')和加密的口令(而不 是 ''biscuit''),比较失败并且服务器拒绝连接: shell> mysql -u jeffrey -pbiscuit tes tAccess denied因为当他们被插入user表时,口令必须被加密,相反,INSERT语句应该象这样被指定: mysql> INSERT INTO user (Host,User,Password) VALUES(''%'',''jeffrey'',PASSWO RD(''biscuit''));当你使用SET PASSWORD语句时,你也必须使用PASSWORD()函数: mysql> SET PASSWORD FOR jeffrey@"%" = PASSWORD(''biscuit''); 如果你使用GRANT ... I DENTIFIED BY语句或mysqladmin password命令设置口令,PASSWORD()函数是不必要的。他们都考虑到 为你加密口令,多以你可像这样指定一个口令''biscuit'': mysql> GRANT USAGE ON . TO jeffr ey@"%" IDENTIFIED BY ''biscuit'';或shell> mysqladmin -u jeffrey pass word biscuit 注意: PASSWORD()不是以在Unix口令加密的同样方法施行口令加密。你不应该假定如果你的Unix 口令和你的MySQL口令是一样的,PASSWORD()将导致与在Unix口令文件被存储的同样的加密值。见6.2 MySQL 用户名 和口令。 Access denied错误的原因当你试着联接MySQL服务器时,如果你碰到Access denied错误,显示在下面 的表指出一些你能用来更正这个问题的动作: 你是在安装MySQL以后运行mysql_install_db的脚本,来设置初始授权表内容 吗?如果不是,这样做。见6.10 设置初始MySQL权限。通过执行这个命令测试初始权限: shell> mysql -u root test 服务器应该让你无误地连接。你也应该保证你在MySQL数据库目录有一个文件“user.MYD”。通常,它是“PATH/v ar/mysql/user.MYD”,在此PATH是MySQL安装根目录的路径。 在一个新的安装以后,你应该连接服务器并且设置你的 用户及其存取许可: shell> mysql -u root mysql 服务器应该让你连接,因为MySQL root用户初始时没 有口令。既然那也是一个安全风险,当你正在设置其他MySQL用户时,设定root口令是一件重要的事请。如果你作为root尝试连接并且 得到这个错误: Access denied for user: ''@unknown'' to database mysql 这意味着 ,你没有一个条目在user表中的一个User列值为''root''并且mysqld不能为你的客库解析主机名。在这种情况下,你必须用-- skip-grant-tables选项重启服务器并且编辑你的“/etc/hosts”或“\windows\hosts”文件为你的主 机增加一个条目。 如果你从一个3.22.11以前的版本更新一个现存的MySQL安装到3.22.11版或以后版本,你运行了mysql _fix_privilege_tables脚本吗?如果没有,运行它。在GRANT语句变得能工作时,授权表的结构用MySQL 3.2 2.11修改 。 如果你直接对授权表做修改(使用INSERT或UPDATE语句)并且你的改变似乎被忽略,记住,你必须发出一个FLU SH PRIVILEGES语句或执行一个mysqladmin flush-privileges命令导致服务器再次读入表,否则你的改 变要道下一次服务器被重启时再生效。记住在你设定root口令以后,你将不需要指定它,直到在你清洗(flush)权限以后,因为服务器仍 然不会知道你改变了口令! 如果你的权限似乎在一个会话(session)当中改变了,可能是一个超级用户改变了他们。再次装入授权表作用 于新客户连接,但是它也影响现存的连接,如6.9 权限改变何时生效小节所述。 为了测试,用--skip-grant-tables选项 启动mysqld守护进程,然后你可以改变MySQL授权表并且使用mysqlaccess脚本检查你的修改是否有如期的效果。当你对你的 改变满意时,执行mysqladmin flush-privileges告诉mysqld服务器开始使用新的权限表。注意:再次装入授权 表覆盖了--skip-grant-tables选项。这允许你告诉服务器开始使用授权表,而不用停掉并重启它。 如果你有一个Perl、 Python或ODBC程序的存取问题,试着用mysql -u user_name db_name或mysql -u user_na me -pyour_pass db_name与服务器连接。如果你能用mysql客户连接,这是你程序的一个问题而不是存取权限的问题。 (注意在-p和口令之间没有空格;你也能使用--password=your_pass句法指定口令。) 如果你不能让口令工作,记得如果 你用INSERT, UPDATE或SET PASSWORD语句设置口令,你必须使用PASSWORD()函数。如果你用GRANT . .. INDENTIFIED BY语句或mysqladmin password命令指定口令,PASSWORD()函数是不需要的。见 6.12 怎样设置口令。 localhost是你本地主机名的一个同义词,并且也是如果你不明确地指定主机而客户尝试连接的缺省主机。然 而,如果你正在运行于一个使用MIT-pthreads的系统上,连接localhost是不行的(localhost连接使用Unix套 接字进行,它没被 MIT-pthreads支持),为了在这样的系统上避免这个问题,你应该使用--host选项明确地命名服务器主机, 这将做一个 TCP/IP连接到mysqld服务器。在这种情况下,你必须有在服务器主机上的user表中条目的你真实的主机名。(即使你 在服务器同一台的主机上运行一个客户程序,这也是真的。) 当尝试用mysql -u user_name db_name与数据库连接时 ,如果你得到一个Access denied错误,你可能有与user桌有关的问题,通过执行mysql -u root mysql并且 发出下面的SQL语句检查: mysql> SELECT FROM user; 结果应该包含一个有Host和User列的条目匹配 你的计算机主机名和你的MySQL用户名。 Access denied错误消息将告诉你,你正在用哪个用户尝试登录,你正在试图用连接哪 个主机,并且你是否正在使用一个口令。通常,你应该在user表中有一个条目,正确地匹配在错误消息给出的主机名和用户名。 如果当你试着 从一个不是MySQL服务器正在运行的主机上连接时,你得到下列错误,那么在user表中没有匹配那台主机行: Host ... is not allowed to connect to this MySQL server 你可以通过使用mysql命令行工具(在服务 器主机上!)修正它,把你正在试图连接的用户/主机名组合新加一行到user表中。如果你不在运行MySQL 3.22并且你不知道你正在 从它连接的机器的IP数字或主机名,你应该把一个''%''条目作为Host列值放在user表中并且在服务器机器上使用--log选项重启m ysqld。在试图从客户机器连接以后,在MySQL记录文件中的信息将显示你如何真正进行连接。(然后用在记录文件上面显示出的实际的主 机名代替user表中的''%''条目。否则,你将有一个不安全的系统。)如果mysql -u root test工作但是mysql -h your_hostname -u root test导致Access denied,那么在user表中你可能没有你的主机的正确名 字。这里的一个普遍的问题是在user表条目中的Host值指定一个唯一的主机名,但是你系统的名字解析例程返回一个完全正规的域名(或相 反)。例如,如果你在user表中有一个主机是''tcx''的条目,但是你的 DNS告诉MySQL你的主机名是''tcx.subnet.s e'',条目将不工作。尝试把一个条目加到user表中,它包含你主机的IP数字作为Host列的值。(另外,你可以把一个条目加到user 表中,它有包含一个通配符如''tcx.%''的Host值。然而,使用以“%”结尾的主机名是不安全的并且不推荐!) 如果mysql -u user_name test工作但是mysql -u user_name other_db_name不工作,对other_db_ name,你在db表中没有没有一个条目列出。 当在服务器机器上执行mysql -u user_name db_name时,它工作, 但是在其它客户机器上执行mysql -h host_name -u user_name db_name时,它却不工作,你没有把客户 机器列在user表或db表中。 如果你不能弄明白你为什么得到Access denied,从user表中删除所有Host包含通配符值 的条目(包含“%”或“_”的条目)。一个很普遍的错误是插入用Host=''%''和User=''some user''插入一个新条目,认为 这将允许你指定localhost从同一台机器进行连接。它不工作的原因是缺省权限包括一个有Host=''localhost''和User =''''的条目,因为那个条目一个比''%''更具体的Host值''localhost'',当从localhost连接时,它用于指向新条目!正 确的步骤是插入Host=''localhost''和User=''some_user''的第2个条目,或删除Host=''localhost ''和User=''''条目。 如果你得到下列错误,你可以有一个与db或host表有关的问题: Access to database d enied如果从db表中选择了在Host列有空值的条目,保证在host表中有一个或多个相应的条目,指定运用db表中的哪些主机。如果 在使用SQL命令SELECT ... INTO OUTFILE或LOAD DATA INFILE时,你得到错误,在user表中的你 的条目可能启用file权限。 记住,客户程序将使用在配置文件或环境变量被指定了的连接参数。如果当你不在命令行上指定他们时,一个客户 似乎正在发送错误的缺省连接参数,检查你的环境和在你的主目录下的“.my.cnf”文件。你也可以检查系统范围的MySQL配置文件,尽 管更不可能将在那里指定那个客户的连接参数。见4.15.4 选项文件。如果当你没有任何选项运行一个客户时,你得到Access den ied,确认你没在任何选项文件里指定一个旧的口令!见4.15.4 选项文件。 如果任何其它事情失败,用调试选项(例如,--debu g=d,general,query)启动mysqld守护进程。这将打印有关尝试连接的主机和用户信息,和发出的每个命令的信息。见G. 1 调试一个MySQL服务器。 如果你有任何与MySQL授权表的其它问题,而且觉得你必须邮寄这个问题到邮寄表,总是提供一个MySQ L授权表的倾倒副本(dump)。你可用mysqldump mysql命令倾倒数据库表。象平时一样,用mysqlbug脚本邮寄你的问 题。在一些情况下你可能用--skip-grant-tables重启mysqld以便能运行mysqldump。 怎样使MySQL安全 以对抗解密高手当你连接一个MySQL服务器时,你通常应该使用一个口令。口令不以明文在连接上传输。 所有其它信息作为能被任何人读懂的 文本被传输。如果你担心这个,你可使用压缩协议(MySQL3.22和以上版本)使事情变得更难。甚至为了使一切更安全,你应该安装ssh (见http://www.cs.hut.fi/ssh)。用它,你能在一个MySQL服务器与一个MySQL客户之间得到一个加密的TC P/IP连接。 为了使一个MySQL系统安全,强烈要求你考虑下列建议: 对所有MySQL用户使用口令。记住,如果other_use r没有口令,任何人能简单地用mysql -u other_user db_name作为任何其它的人登录。对客户机/服务器应用程序, 客户可以指定任何用户名是常见的做法。在你运行它以前,你可以通过编辑mysql_install_db脚本改变所有用户的口令,或仅仅M ySQL root的口令,象这样: shell> mysql -u root mysqlmysql> UPDATE user SE T Password=PASSWORD(''new_password'') WHERE user=''root'';mysql> FLUS H PRIVILEGES;不要作为Unix的root用户运行MySQL守护进程。mysqld能以任何用户运行,你也可以创造一个新的 Unix用户mysql使一切更安全。如果你作为其它Unix用户运行mysqld,你不需要改变在user表中的root用户名,因为M ySQL用户名与Unix 用户名没关系。你可以作为其它Unix用户编辑mysql.server启动脚本mysqld。通常这用su命 令完成。对于更多的细节,见18.8 怎样作为一个一般用户运行MySQL。 如果你把一个Unix root用户口令放在mysql.s erver脚本中,确保这个脚本只能对root是可读的。 检查那个运行mysqld的Unix用户是唯一的在数据库目录下有读/写权限的 用户。 不要把process权限给所有用户。mysqladmin processlist的输出显示出当前执行的查询正文,如果另外的 用户发出一个UPDATE user SET password=PASSWORD(''not_secure'')查询,被允许执行那个命令 的任何用户可能看得到。mysqld为有process权限的用户保留一个额外的连接, 以便一个MySQL root用户能登录并检查, 即使所有的正常连接在使用。 不要把file权限给所有的用户。有这权限的任何用户能在拥有mysqld守护进程权限的文件系统那里写一个 文件!为了使这更安全一些,用SELECT ... INTO OUTFILE生成的所有文件对每个人是可读的,并且你不能覆盖已经存在的 文件。file权限也可以被用来读取任何作为运行服务器的Unix用户可存取的文件。这可能被滥用,例如,通过使用LOAD DATA装载 “/etc/passwd”进一个数据库表,然后它能用SELECT被读入。 如果你不信任你的DNS,你应该在授权表中使用IP数字而不 是主机名。原则上讲,--secure选项对mysqld应该使主机名更安全。在任何情况下,你应该非常小心地使用包含通配符的主机名! 下列mysqld选项影响安全: --secure 由gethostbyname()系统调用返回的IP数字被检查,确保他们解析回到原 来的主机名。这对某些外人通过模仿其它主机获得存取权限变得更难。这个选项也增加一些聪明的主机名检查。在MySQL3.21里,选择缺省 是关掉的,因为它有时它花很长时间执行反向解析。MySQL 3.22缓存主机名并缺省地启用了这个选项。 --skip-grant-t ables 这个选项导致服务器根本不使用权限系统。这给每个人以完全存取所有的数据库的权力!(通过执行mysqladmin relo ad,你能告诉一个正在运行的服务器再次开始使用授权表。) --skip-name-resolve 主机名不被解析。所有在授权表的H ost的列值必须是IP数字或localhost。 --skip-networking 在网络上不允许TCP/IP连接。所有到mys qld的连接必须经由Unix套接字进行。这个选项对使用MIT-pthreads的系统是不合适的,因为MIT-pthreads包不支 持Unix套接字。 MySQL语言参考文字:怎么写字符串和数字字符串一个字符串是一个字符序列,由单引号(“''”)或双引号(“"”) 字符(后者只有你不在ANSI模式运行)包围。例如:''a string''"another string"在字符串内,某个顺序有特殊的 意义。这些顺序的每一个以一条反斜线(“\”)开始,称为转义字符。MySQL识别下列转义字符: \0 一个ASCII 0 (NUL) 字符。 \n 一个新行符。 \t 一个定位符。 \r 一个回车符。 \b 一个退格符。 \'' 一个单引号(“''”)符。 \" 一个 双引号(“"”)符。 \\ 一个反斜线(“\”)符。 \% 一个“%”符。它用于在正文中搜索“%”的文字实例,否则这里“%”将解释 为一个通配符。 \_ 一个“_”符。它用于在正文中搜索“_”的文字实例,否则这里“_”将解释为一个通配符。 注意,如果你在某些正文 环境中使用“\%”或“\%_”,这些将返回字符串“\%”和“\_”而不是“%”和“_”。 有几种方法在一个字符串内包括引号: 一个 字符串内用“''”加引号的“''”可以被写作为“''''”。 一个字符串内用“"”加引号的“"”可以被写作为“""”。 你可以把一个转义字 符(“\”)放在引号前面。 一个字符串内用“"”加引号的“''”不需要特殊对待而且不必被重复或转义。同理,一个字符串内用“''”加引号 的与“"”也不需要特殊对待。 下面显示的SELECT演示引号和转义如何工作: mysql> SELECT ''hello'', ''"h ello"'', ''""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";+------------ --------+| ThisIsFourlines |+--------------------+ 如果你想要把二进制数据插入到 一个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接口。 你应该在任何可能包含上述任何特殊字符的字符串上使用转义函数! 数字整数表示为一个数字顺序。浮点数使用“.”作为一 个十进制分隔符。这两种类型的数字可以前置“-”表明一个负值。 有效整数的例子: 12210-32有效浮点数的例子: 294.42- 32032.6809e+10148.00一个整数可以在浮点上下文使用;它解释为等值的浮点数。 十六进制值MySQL支持十六进制值。 在数字上下文,它们表现类似于一个整数(64位精度)。在字符串上下文,它们表现类似于一个二进制字符串,这里每一对十六进制数字被变换为 一个字符。 mysql> SELECT 0xa+0 -> 10mysql> select 0x5061756c; -> Paul十 六进制字符串经常被ODBC使用,给出BLOB列的值。 NULL值NULL值意味着“无数据”并且不同于例如数字类型的0为或字符串类型 的空字符串。见18.15 NULL值问题。 当使用文本文件导入或导出格式(LOAD DATA INFILE, SELECT ... INTO OUTFILE)时,NULL可以用\N表示。见7.16 LOAD DATA INFILE句法。数据库、表、索引、列和别 名的命名数据库、表、索引、列和别名的名字都遵守MySQL同样的规则: 注意,从MySQL3.23.6开始规则改变了,此时我们引入了 用''引用的标识符(数据库、表和列命名)(如果你以ANSI模式运行,"也将用于引用标识符)。 标识符 最大长度 允许的字符 数据库6 4在一个目录名允许的任何字符,除了/. 表64在文件名中允许的任何字符,除了/或. 列64所有字符别名255所有字符注意,除了以上 ,你在一个标识符中不能有ASCII(0)或ASCII(255)。 注意,如果标识符是一个限制词或包含特殊字符,当你使用它时,你必须 总是用`引用它: SELECT from `select` where `select`.id > 100; 在 MySQL的 先前版本,命名规则如下: 一个名字可以包含来自当前字符集的数字字母的字符和“_”和“$”。缺省字符集是ISO-8859-1 Lat in1;这可以通过重新编译MySQL来改变。见9.1.1 用于数据和排序的字符集。 一个名字可以以在一个名字中合法的任何字符开始。 特别地,一个名字可以以一个数字开始(这不同于许多其他的数据库系统!)。然而,一个名字不能仅仅由数字组成。 你不能在名字中使用“.” ,因为它被用来扩充格式,你能用它引用列(见下面)。 建议你不使用象1e这样的名字,因为一个表达式如1e+1是二义性的。它可以解释为 表达式1e + 1或数字1e+1。 在MySQL中,你能使用下列表格的任何一种引用列: 列引用 含义 col_name 来自于任意 表的列col_name,用于包含该表的一个列的查询中tbl_name.col_name 来自当前的数据库的表tbl_name的列c ol_namedb_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.co l_name和db2.t.col_name引用这些数据表的列。 句法.tbl_name意味着在当前的数据库中的表tbl_name, 该句法为了ODBC的兼容性被接受,因为一些ODBC程序用一个“.”字符作为数据库表名的前缀。 名字的大小写敏感性 在MySQL中, 数据库和表对应于在那些目录下的目录和文件,因而,内在的操作系统的敏感性决定数据库和表命名的大小写敏感性。这意味着数据库和表名在Un ix上是区分大小写的,而在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;列的别名是忽略大小写的。 用户 变量MySQL支持线程特定的变量,用@variablename句法。一个变量名可以由当前字符集的数字字母字符和“_”、“$”和“. ”组成。缺省字符集是ISO-8859-1 Latin1;这可以通过重新编译MySQL改变。见9.1.1 用于数据和排序的字符集。 变量不必被初始化。缺省地,他们包含NULL并能存储整数、实数或一个字符串值。当线程退出时,对于一个线程的所有变量自动地被释放。 你 可以用SET句法设置一个变量: SET @variable= { integer expression | real expres sion | 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 |+----------------------+ ------+------+------+(这里,我们不得不使用:=句法,因为=是为比较保留的)列类型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] [ZEROFI LL] 一个正常大小整数。有符号的范围是-2147483648到2147483647,无符号的范围是0到4294967295。 I NTEGER[(M)] [UNSIGNED] [ZEROFILL] 这是INT的一个同义词。 BIGINT[(M)] [UNSIG NED] [ZEROFILL] 一个大整数。有符号的范围是-9223372036854775808到922337203685477 5807,无符号的范围是0到18446744073709551615。注意,所有算术运算用有符号的BIGINT或DOUBLE值完成 ,因此你不应该使用大于9223372036854775807(63位)的有符号大整数,除了位函数!注意,当两个参数是INTEGER 值时,-、+和将使用BIGINT运算!这意味着如果你乘2个大整数(或来自于返回整数的函数),如果结果大于922337203685 4775807,你可以得到意外的结果。一个浮点数字,不能是无符号的,对一个单精度浮点数,其精度可以是<=24,对一个双精度浮点数, 是在25 和53之间,这些类型如FLOAT和DOUBLE类型马上在下面描述。FLOAT(X)有对应的FLOAT和DOUBLE相同的 范围,但是显示尺寸和小数位数是未定义的。在MySQL3.23中,这是一个真正的浮点值。在更早的MySQL版本中,FLOAT(pre cision)总是有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.7976931 348623157E+308到-2.2250738585072014E-308、 0和2.2250738585072014E-30 8到1.7976931348623157E+308。M是显示宽度而D是小数位数。没有一个参数的DOUBLE或FLOAT(X)(25 < = X < = 53)代表一个双精密浮点数字。 DOUBLE PRECISION[(M,D)] [ZEROFILL] RE AL[(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-D D''格式来显示DATE值,但是允许你使用字符串或数字把值赋给DATE列。 DATETIME 一个日期和时间组合。支持的范围是''10 00-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、YYMMDD HHMMSS、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中是新类型。) CH AR(M) [BINARY] 一个定长字符串,当存储时,总是是用空格填满右边到指定的长度。M的范围是1 ~ 255个字符。当值被检 索时,空格尾部被删除。CHAR值根据缺省字符集以大小写不区分的方式排序和比较,除非给出BINARY关键词。NATIONAL CHA R(短形式NCHAR)是ANSI SQL的方式来定义CHAR列应该使用缺省字符集。这是MySQL的缺省。CHAR是CHARACTE R的一个缩写。 [NATIONAL] VARCHAR(M) [BINARY] 一个变长字符串。注意:当值被存储时,尾部的空格被删除 (这不同于ANSI SQL规范)。M的范围是1 ~ 255个字符。 VARCHAR值根据缺省字符集以大小写不区分的方式排序和比较, 除非给出BINARY关键词值。见7.7.1 隐式列指定变化。 VARCHAR是CHARACTER VARYING一个缩写。 TIN YBLOB TINYTEXT 一个BLOB或TEXT列,最大长度为255(2^8-1)个字符。见7.7.1 隐式列指定变化。 B LOB TEXT 一个BLOB或TEXT列,最大长度为65535(2^16-1)个字符。见7.7.1 隐式列指定变化。 MEDI UMBLOB 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(''val ue1'',''value2'',...) 一个集合。能有零个或多个值的一个字符串对象,其中每一个必须从值列表''value1'', ''va lue2'', ...选出。一个SET最多能有64个成员。 列类型存储需求对于每个由MySQL支持的列类型的存储需求在下面按类列出。 数字类型列类型 需要的存储量 TINYINT 1 字节SMALLINT 2 个字节MEDIUMINT 3 个字节INT 4 个字 节INTEGER 4 个字节BIGINT 8 个字节FLOAT(X) 4 如果 X < = 24 或 8 如果 25 < = X < = 53FLOAT 4 个字节DOUBLE 8 个字节DOUBLE PRECISION 8 个字节REAL 8 个字节DECI MAL(M,D) M字节(D+2 , 如果M < D) NUMERIC(M,D) M字节(D+2 , 如果M < D) 日期和时间 类型列类型 需要的存储量 DATE 3 个字节DATETIME 8 个字节TIMESTAMP 4 个字节TIME 3 个字节YEA R 1 字节串类型列类型 需要的存储量 CHAR(M) M字节,1 <= M <= 255 VARCHAR(M) L+1 字节, 在此L <= M和1 <= M <= 255 TINYBLOB, TINYTEXT L+1 字节, 在此L< 2 ^ 8BLOB, TEXT L+2 字节, 在此L< 2 ^ 16MEDIUMBLOB, MEDIUMTEXT L+3 字节, 在此L< 2 ^ 24LONGBLOB, LONGTEXT L+4 字节, 在此L< 2 ^ 32ENUM(''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个成员。 数字类型MySQL支持所有的ANSI/ISO SQL92的数字类型。这 些类型包括准确数字的数据类型(NUMERIC, DECIMAL, INTEGER,和SMALLINT),也包括近似数字的数据类型( FLOAT, REAL,和DOUBLE PRECISION)。关键词INT是INTEGER的一个同义词,而关键词DEC是DECIM AL一个同义词。 NUMERIC和DECIMAL类型被MySQL实现为同样的类型,这在SQL92标准允许。他们被用于保存值,该值的 准确精度是极其重要的值,例如与金钱有关的数据。当声明一个类是这些类型之一时,精度和规模的能被(并且通常是)指定;例如:salary DECIMAL(9,2) 在这个例子中,9(precision)代表将被用于存储值的总的小数位数,而2(scale)代表将被用于 存储小数点后的位数。因此,在这种情况下,能被存储在salary列中的值的范围是从-9999999.99到9999999.99。在A NSI/ISO SQL92中,句法DECIMAL(p)等价于DECIMAL(p,0)。同样,句法DECIMAL等价于DECIMAL (p,0),这里实现被允许决定值p。MySQL当前不支持DECIMAL/NUMERIC数据类型的这些变种形式的任一种。这一般说来不 是一个严重的问题,因为这些类型的主要益处得自于明显地控制精度和规模的能力。 DECIMAL和NUMERIC值作为字符串存储,而不是 作为二进制浮点数,以便保存那些值的小数精度。一个字符用于值的每一位、小数点(如果scale>0)和“-”符号(对于负值)。如果sc ale是0,DECIMAL和NUMERIC值不包含小数点或小数部分。 DECIMAL和NUMERIC值得最大的范围与DOUBLE一 样,但是对于一个给定的DECIMAL或NUMERIC列,实际的范围可由制由给定列的precision或scale限制。当这样的列赋 给了小数点后面的位超过指定scale所允许的位的值,该值根据scale四舍五入。当一个DECIMAL或NUMERIC列被赋给了其大 小超过指定(或缺省的)precision和scale隐含的范围的值,MySQL存储表示那个范围的相应的端点值。 作为对ANSI/I SO SQL92标准的扩展,MySQL也支持上表所列的整型类型TINYINT、MEDIUMINT和BIGINT。另一个扩展是MyS QL支持可选地指定一个整型值显示的宽度,用括号跟在基本关键词之后(例如,INT(4))。这个可选的宽度指定被用于其宽度小于列指定宽 度的值得左填补显示,但是不限制能在列中被存储的值的范围,也不限制值将被显示的位数,其宽度超过列指定的宽度。当与可选的扩展属性ZER OFILL一起使用时,缺省的空格填补用零代替。例如,对于声明为INT(5) ZEROFILL的列,一个为4的值作为00004被检索 。注意,如果你在一个整型列存储超过显示宽度的更大值,当MySQL对于某些复杂的联结(join)生成临时表时,你可能会遇到问题,因为 在这些情况下,MySQL相信数据确实适合原来的列宽度。 所有的整型类型可以有一个可选(非标准的)属性UNSIGNED。当你想要在列 中仅允许正数并且你需要一个稍大一点的列范围,可以使用无符号值。 FLOAT类型被用来标示近似数字的数据类型。ANSI/ISO SQ L92标准允许一个可选的精度说明(但不是指数的范围),跟在关键词FLOAT后面的括号内位数。MySQL实现也支持这个可选的精度说明 。当关键词FLOAT被用于一个列类型而没有精度说明时,MySQL使用4个字节存储值。一个变种的句法也被支持,在FLOAT关键词后面 的括号给出2个数字。用这个选项,第一个数字继续表示在字节计算的值存储需求,而第二个数字指定要被存储的和显示跟随小数点后的位数(就象 DECIMAL和NUMERIC)。当MySQL要求为这样一个列,一个小数点后的小数位超过列指定的值,存储值时,该值被四舍五入,去掉 额外的位。 REAL和DOUBLE PRECISION类型不接受精度说明。作为对 ANSI/ISO SQL92 标准的扩展,MyS QL识别出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和42 94967296。 对于ALTER TABLE、LOAD DATA INFILE、UPDATE和多行INSERT语句,由于剪切所发 生的变换作为“警告”被报告。 日期和时间类型日期和时间类型是DATETIME、DATE、TIMESTAMP、TIME和YEAR。这 些的每一个都有合法值的一个范围,而“零”当你指定确实不合法的值时被使用。注意,MySQL允许你存储某个“不严格地”合法的日期值,例 如1999-11-31,原因我们认为它是应用程序的责任来处理日期检查,而不是SQL服务器。为了使日期检查更“快”,MySQL仅检查 月份在0-12的范围,天在0-31的范围。上述范围这样被定义是因为MySQL允许你在一个DATE或DATETIME列中存储日期,这 里的天或月是零。这对存储你不知道准确的日期的一个生日的应用程序来说是极其有用的,在这种情况下,你简单地存储日期象1999-00-0 0或1999-01-00。(当然你不能期望从函数如DATE_SUB()或DATE_ADD()得到类似以这些日期的正确值)。 当用日 期和时间工作时,这里是的一些要记住的一般考虑: MySQL对一个给定的日期或时间类型以标准的格式检索,但是它试图为你提供的值解释成 许多格式(例如,当你指定一个值被赋给或与比较一个日期或时间类型时),但是只支持有在下列小节描述的格式。期望你提供合法的值,并且如果 你以其他格式使用这些值,可能造成无法预料的结果。 尽管MySQL试图以多种格式解释值,但它总是期望日期值的年份部分在最左面,日期必 须以年-月-日的顺序给出(例如,''98-09-04''),而不是以其他地方常用的月-日-年或日-月-年的次序(例如,''09-04-9 8''、''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不能处理这样的值。 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位年值的输 入。 DATETIME, DATE和TIMESTAMP类型DATETIME, DATE和TIMESTAMP类型是相关的。本节描述他 们的特征,他们是如何类似的而又不同的。 DATETIME类型用在你需要同时包含日期和时间信息的值时。MySQL检索并且以''YYYY -MM-DD HH:MM:SS''格式显示DATETIME值,支持的范围是''1000-01-01 00:00:00''到''9999-1 2-31 23:59:59''。(“支持”意味着尽管更早的值可能工作,但不能保证他们可以。)DATE类型用在你仅需要日期值时,没有时 间部分。MySQL检索并且以''YYYY-MM-DD''格式显示DATE值,支持的范围是''1000-01-01''到''9999-12-3 1''。 TIMESTAMP列类型提供一种类型,你可以使用它自动地用当前的日期和时间标记INSERT或UPDATE的操作。如果你有多 个TIMESTAMP列,只有第一个自动更新。 自动更新第一个TIMESTAMP列在下列任何条件下发生: 列没有明确地在一个INSE RT或LOAD DATA INFILE语句中指定。 列没有明确地在一个UPDATE语句中指定且一些另外的列改变值。(注意一个UPD ATE设置一个列为它已经有的值,这将不引起TIMESTAMP列被更新,因为如果你设置一个列为它当前的值,MySQL为了效率而忽略更 改。) 你明确地设定TIMESTAMP列为NULL. 除第一个以外的TIMESTAMP列也可以设置到当前的日期和时间,只要将列设为 NULL,或NOW()。 通过明确地设置希望的值,你可以设置任何TIMESTAMP列为不同于当前日期和时间的值,即使对第一个TIM ESTAMP列也是这样。例如,如果,当你创建一个行时,你想要一个TIMESTAMP被设置到当前的日期和时间,但在以后无论何时行被更 新时都不改变,你可以使用这个属性: 让MySQL在行被创建时设置列,这将初始化它为当前的日期和时间。 当你执行随后的对该行中其他列 的更改时,明确设定TIMESTAMP列为它的当前值。 另一方面,你可能发现,当行被创建并且远离随后的更改时,很容易用一个你用NOW ()初始化的DATETIME列。 TIMESTAMP值可以从1970的某时的开始一直到2037年,精度为一秒,其值作为数字显示。 在MySQL检索并且显示TIMESTAMP值取决于显示尺寸的格式如下表。“完整”TIMESTAMP格式是14位,但是TIMESTA MP列可以用更短的显示尺寸创造: 列类型 显示格式 TIMESTAMP(14) YYYYMMDDHHMMSS TIMESTAMP( 12) YYMMDDHHMMSS TIMESTAMP(10) YYMMDDHHMM TIMESTAMP(8) YYYYMMDD T IMESTAMP(6) YYMMDD TIMESTAMP(4) YYMM TIMESTAMP(2) YY 所有的TIMESTAMP 列都有同样的存储大小,不考虑显示尺寸。最常见的显示尺寸是6、8、12、和14。你可以在表创建时间指定一个任意的显示尺寸,但是值0或 比14大被强制到14。在从1~13范围的奇数值尺寸被强制为下一个更大的偶数。 使用一个常用的格式集的任何一个,你可以指定DATET IME、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 113045''和''98@12@31 11^30^45''是等价的。 ''YYYY-MM-DD''或''YY-MM-DD''格式的一个字符串。允许一种“宽松”的语法。例如,''98-12-31'', ''98.1 2.31'', ''98/12/31''和''98@12@31''是等价的。 ''YYYYMMDDHHMMSS''或''YYMMDDHHMMSS'' 格式的没有任何分隔符的一个字符串,例如,''19970523091528''和''970523091528''被解释为''1997-05-2 3 09:15:28'',但是''971122459015''是不合法的(它有毫无意义的分钟部分)且变成''0000-00-00 00:0 0:00''。 ''YYYYMMDD''或''YYMMDD''格式的没有任何分隔符的一个字符串,如果字符串认为是一个日期。例如,''19970 523''和''970523''被解释作为''1997-05-23'',但是''971332''是不合法的( 它有无意义的月和天部分)且变成''0 000-00-00''。 YYYYMMDDHHMMSS或YYMMDDHHMMSS格式的一个数字,如果数字认为是一个日期。例如,198 30905132800和830905132800被解释作为''1983-09-05 13:28:00''。 YYYYMMDD或YYMM DD格式的一个数字,如果数字认为是一个日期。例如,19830905和830905被解释作为''1983-09-05''。 一个返回值可 以在一个DATETIME, DATE或TIMESTAMP上下文环境中接受的函数,例如NOW()或CURRENT_DATE。 不合法 DATETIME, DATE或TIMESTAMP值被变换到适当类型的“零”值(''0000-00-00 00:00:00'', ''00 00-00-00''或00000000000000)。 对于包括的日期部分分隔符的指定为字符串的值,不必要为小于10的月或天的值指定 2位数字,''1979-6-9''与''1979-06-09''是一样的。同样, 对于包括的时间部分分隔符的指定为字符串的值,不必为小于1 0的小时、月或秒指定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月,你会发现MySQ L把一个“零”日期插入到你的表中,这是因为年份和月份值99和03,但是日期部分丢失(零),因此该值不是一个合法的日期。 TIMES TAMP列使用被指定的值的完整精度的存储合法的值,不考虑显示大小。这有几个含意: 总是指定年,月,和日,即使你的列类型是TIMES TAMP(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''将被变换到''000 0-00-00'',因为''45''不是一个合法的月份。 以2位数字指定的年值是模糊的,因为世纪是未知的。MySQL使用下列规则解释2位 年值: 在00-69范围的年值被变换到2000-2069。 在范70-99围的年值被变换到1970-1999。 TIME类型MyS QL检索并以''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''和111 2意味着''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''或它是否是不合法的。 YEAR类型YEAR类型是一个 1 字节类型用于表示年份。 MySQL检索并且以YYY Y格式显示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''指定它,它将被解释为00 00。 其返回值可在一个YEAR上下文环境中接受的函数,例如NOW()。 不合法YEAR值被变换到0000。 字符串类型字符串类型 是CHAR、VARCHAR、BLOB、TEXT、ENUM和SET。 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列上被删除。 在CH AR和VARCHAR列中存储和比较值是以大小写不区分的方式进行的,除非当桌子被创建时,BINARY属性被指定。BINARY属性意味 着该列的值根据MySQL服务器正在运行的机器的ASCII顺序以大小写区分的方式存储和比较。 BINARY属性是“粘性”的。这意味着 ,如果标记了BINARY的列用于一个表达式中,整个的表达式作为一个BINARY值被比较。 MySQL在表创建时可以隐含地改变一个C HAR或VARCHAR列的类型。见7.7.1 隐含的的列说明改变。 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值为LONGVARC HAR。 因为BLOB和TEXT值可以是非常长的,当使用他们时,你可能遇到一些限制: 如果你想要在一个BLOB或TEXT列上使用G ROUP BY或ORDER BY,你必须将列值变换成一个定长对象。这样做的标准方法是用SUBSTRING函数。例如: mysql> select comment from tbl_name,substring(comment,20) as substr ORD ER BY substr;如果你不这样做,在排序时,只有列的首max_sort_length个字节被使用,缺省的max_sort_ length是1024;这个值能在启动mysqld服务器时使用-O选择改变。你可以在包含BLOB或TEXT值得一个表达式上分组(g roup),通过指定列的位置或使用一个别名: mysql> select id,substring(blob_col,1,100) from tbl_name GROUP BY 2;mysql> select id,substring(blob_col,1,1 00) as b from tbl_name GROUP BY b;一个BLOB或TEXT对象的最大尺寸由其类型决定,但是你能在客 户与服务器之间是实际传输的最大值由可用的内存数量和通讯缓冲区的大小来决定。你能改变消息缓冲区大小,但是你必须在服务器和客户两端做。 见10.2.3 调节服务器参数。 注意,每个BLOB或TEXT值内部由一个独立分配的对象表示。这与所有的其他列类型相反,它们是在打 开表时,按列被分配一次存储。 ENUM类型一个ENUM是一个字符对象,其值通常从一个在表创建时明确被列举的允许值的一张表中选择。 在下列的某个情形下,值也可以空字符串("")或NULL: 如果你把一个无效值插入到一个ENUM(即,一个不在允许的值列表中的字符串 ),空字符串作为一个特殊错误的值被插入。 如果一个ENUM被声明为NULL,NULL也是列的合法值,并且缺省值是NULL。如果一个 ENUM被声明为NOT NULL,缺省值是允许值的列表的第一成员。 每枚举值有一个编号: 在列说明中来自允许成员值列表值用从1开始 编号。 空字符串错误值的编号值是0。这意味着,你能使用下列SELECT语句找出被赋给无效ENUM值的行: mysql> SELEC T FROM tbl_name WHERE enum_col=0;NULL值的编号是NULL。 例如,指定为ENUM("one ", "two", "three")的列可以有显示在下面的值的任何一个。每个值的编号也被显示: 值 编号NULL NULL "" 0 "one" 1 "two" 2 "three" 3 枚举可以有最大65535个成员。 当你把值赋给一个ENUM列时,字母的大小 写是无关紧要的。然而,以后从列中检索的值大小写匹配在表创建时用来指定允许值的值的大小写。 如果你在一个数字的上下文环境中检索一个E NUM,列值的编号被返回。如果你存储一个数字到一个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定义。 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"。 对于包含超过一个SE T成员的值,当你插入值时,无所谓以什么顺序列举值,也无所谓给定的值列举了多少次。当以后检索值时,在值中的每个成员将出现一次,根据他 们在表创建时被指定的顺序列出成员。例如,如果列指定为SET("a","b","c","d"),那么"a,d"、"d,a"和"d,a ,a,d,d"在检索时将均作为"a,d"出现。 SET值以数字次序被排序。NULL指排在非NULL SET值之前。 通常,你使用L IKE操作符或FIND_IN_SET()函数执行在一个SET上的一个SELECT: mysql> SELECT FROM tb l_name WHERE set_col LIKE ''%value%'';mysql> SELECT FROM tbl_name WHERE FIND_IN_SET(''value'',set_col)>0;但是下列也会工作: mysql> SELECT F ROM tbl_name WHERE set_col = ''val1,val2'';mysql> SELECT FROM tbl _name WHERE set_col & 1;这些语句的第一个语句寻找一个精确的匹配。第二个寻找包含第一个集合成员的值。 如果你 想要得到一个SET列的所有可能的值,你应该使用:SHOW COLUMNS FROM table_name LIKE set_col umn_name并且分析在第二列的SET定义。 为列选择正确的类型为了最有效地使用存储空间,试着在所有的情况下使用最精确的类型。例 如,如果一个整数列被用于在之间1和99999的值, MEDIUMINT UNSIGNED是最好的类型。 货币值的精确表示是一个常见 的问题。在MySQL,你应该使用DECIMAL类型,它作为一个字符串被存储,不会发生精确性的损失。如果精确性不是太重要,DOUBL E类型也是足够好的。 对高精度,你总是能变换到以一个BIGINT存储的定点类型。这允许你用整数做所有的计算,并且仅在必要时将结果转 换回浮点值。见10.6 选择一个表类型。 列索引所有的MySQL列类型能被索引。在相关的列上的使用索引是改进SELECT操作性能的 最好方法。 一个表最多可有16个索引。最大索引长度是256个字节,尽管这可以在编译MySQL时被改变。 对于CHAR和VARCHA R列,你可以索引列的前缀。这更快并且比索引整个列需要较少的磁盘空间。在CREATE TABLE语句中索引列前缀的语法看起来像这样: KEY index_name (col_name(length)) 下面的例子为name列的头10个字符创建一个索引: mysq l> CREATE TABLE test ( name CHAR(200) NOT NULL, KEY index_name (n ame(10)));对于BLOB和TEXT列,你必须索引列的前缀,你不能索引列的全部。 多列索引MySQL能在多个列上创建索引。一 个索引可以由最多15个列组成。(在CHAR和VARCHAR列上,你也可以使用列的前缀作为一个索引的部分)。 一个多重列索引可以认为 是包含通过合并(concatenate)索引列值创建的值的一个排序数组。 当你为在一个WHERE子句索引的第一列指定已知的数量时, MySQL以这种方式使用多重列索引使得查询非常快速,即使你不为其他列指定值。 假定一张表使用下列说明创建: mysql> CREA TE TABLE test ( id INT NOT NULL, last_name CHAR(30) NOT NULL, fir st_name CHAR(30) NOT NULL, PRIMARY KEY (id), INDEX name (last_nam e,first_name));那么索引name是一个在last_name和first_name上的索引,这个索引将被用于在last _name或last_name和first_name的一个已知范围内指定值的查询,因此,name索引将使用在下列查询中: mysq l> SELECT FROM test WHERE last_name="Widenius";mysql> SELECT FROM test WHERE last_name="Widenius" AND first_name="Michael";mys ql> 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="Mi chael";mysql> SELECT FROM test WHERE last_name="Widenius" OR fi rst_name="Michael";关于MySQL使用索引改进性能的方式的更多的信息,见10.4 使用MySQL索引。 使用来自 其他数据库引擎的列类型为了跟容易地使用为其他供应商的SQL实现编写的代码,下表显示了MySQL映射的列类型。这些映射使得从其他数据 库引擎移动表定义到MySQL更容易: 其他供应商类型 MySQL类型 BINARY(NUM) CHAR(NUM) BINARY C HAR VARYING(NUM) VARCHAR(NUM) FLOAT4 FLOAT FLOAT8 DOUBLE INT1 TIN YINT INT2 SMALLINT INT3 MEDIUMINT INT4 INT INT8 BIGINT LONG VARBI NARY MEDIUMBLOB LONG VARCHAR MEDIUMTEXT MIDDLEINT MEDIUMINT VARBI NARY(NUM) VARCHAR(NUM) BINARY 列类型映射发生在表创建时。如果你用其他供应商使用的类型创建表,那么发出 一个DESCRIBE tbl_name语句,MySQL使用等价的MySQL类型报告表结构。 用在SELECT和WHERE子句中的 函数在一个SQL语句中的select_expression或where_definition可由使用下面描述的函数的任何表达式组成 。 包含NULL的一个表达式总是产生一个NULL值,否则除非表达式所包含的操作符和函数在文档中说明。 注意:在一个函数名和跟随它的 括号之间不许没有空格。这帮助MySQL分析器区分函数调用和具有相同名字的对表或列的引用,尽管允许在参数周围有空格。 为了简洁,例子 以缩写形式显示从mysql程序输出。因此: mysql> select MOD(29,9); 1 rows in set (0.0 0 sec) +-----------+| mod(29,9) |+-----------+| 2 |+----- ------+被显示为这样: mysql> select MOD(29,9); -> 2 分组函数 ( ... ) 括号。使用它们 来强制在一个表达式的计算顺序。 mysql> select 1+23; -> 7mysql> select (1+2)3; - > 9 常用的算术操作一般的算术操作符是可用的。注意在-、+和情况下,如果两个参数是整数,结果用BIGINT(64位)精度计算! + 加法mysql> select 3+5; -> 8- 减法mysql> select 3-5; -> -2 乘法mysq l> select 35; -> 15mysql> select 180143985094819841801439850948 1984.0; -> 324518553658426726783156020576256.0mysql> select 18014 39850948198418014398509481984; -> 0最后一个表达式的结果是不正确的,因为整数乘积的结果超过用B IGINT计算的64位范围。 / 除法mysql> select 3/5; -> 0.60被零除产生一个NULL结果: mysql > select 102/(1-1); -> NULL一个除法用BIGINT算术计算,只要在它的结果被转换到一个整数的上下文中执行 ! 位函数MySQL为位操作使用BIGINT(64位)算法,因此这些操作符有最大64位的一个范围。 | 位或mysql> sel ect 29 | 15; -> 31& 位与mysql> select 29 & 15; -> 13 << 左移位一个长(BIGI NT)数字。 mysql> select 1 << 2 -> 4 >> 右移位一个长(BIGINT)数字。 mysql> sele ct 4 >> 2 -> 1 ~ 颠倒所有的位。 mysql> select 5 & ~1 -> 4 BIT_COUNT(N) 返 回在参数N设定的位的数量。 mysql> select BIT_COUNT(29); -> 4 逻辑运算所有的逻辑函数返回1( TRUE)或0(FALSE)。 NOT ! 逻辑非。如果参数是0,返回1,否则返回0。例外: NOT NULL返回NULL。 my sql> select NOT 1; -> 0mysql> select NOT NULL; -> NULLmysql> sele ct ! (1+1); -> 0mysql> select ! 1+1; -> 1最后的例子返回1,因为表达式作为(!1)+1计算 。 OR || 逻辑或。如果任何一个参数不是0并且不NULL,返回1。 mysql> select 1 || 0; -> 1m ysql> select 0 || 0; -> 0mysql> select 1 || NULL; -> 1 AND && 逻辑与 。如果任何一个参数是0或NULL,返回0,否则返回1。 mysql> select 1 && NULL; -> 0mysql> s elect 1 && 0; -> 0 比较运算符比较操作得出值1(TRUE)、0(FALSE)或NULL等结果。这些函数工作运用在 数字和字符串上。当需要时,字符串自动地被变换到数字且数字到字符串(如在Perl)。 MySQL使用下列规则执行比较: 如果一个或两 个参数是NULL,比较的结果是NULL,除了<=>操作符。 如果在比较中操作的两个参数是字符串,他们作为字符串被比较。 如果两个参 数是整数,他们作为整数被比较。 十六进制的值如果不与一个数字比较,则被当作二进制字符串。 如果参数之一是一个TIMESTAMP或D ATETIME列而其他参数是一个常数,在比较执行前,常数被转换为一个时间标记。这样做是为了对ODBC更友好。 在所有其他的情况下, 参数作为浮点(实数)数字被比较。 缺省地,字符串使用当前的字符集以大小写敏感的方式进行(缺省为ISO-8859-1 Latin1, 它对英语运用得很出色)。 下面的例子演示了对于比较操作字符串到数字的转换: mysql> SELECT 1 > ''6x''; -> 0mysql> SELECT 7 > ''6x''; -> 1mysql> SELECT 0 > ''x6''; -> 0mysql> S ELECT 0 = ''x6''; -> 1= 等于mysql> select 1 = 0; -> 0mysql> select ''0 '' = 0; -> 1mysql> select ''0.0'' = 0; -> 1mysql> select ''0.01'' = 0; -> 0mysql> select ''.01'' = 0.01; -> 1 <> != 不等于mysql> select '' .01'' <> ''0.01''; -> 1mysql> select .01 <> ''0.01''; -> 0mysql> selec t ''zapp'' <> ''zappp''; -> 1<= 小于或等于mysql> select 0.1 <= 2; -> 1< 小于 mysql> select 2 <= 2; -> 1 >= 大于或等于mysql> select 2 >= 2; -> 1 > 大于mysql> select 2 > 2; -> 0<=> 安全等于Nullmysql> select 1 <=> 1, NUL L <=> NULL, 1 <=> NULL; -> 1 1 0 IS NULL IS NOT NULL 测试值是否是或不是N ULL mysql> select 1 IS NULL, 0 IS NULL, NULL IS NULL: -> 0 0 1mys ql> select 1 IS NOT NULL, 0 IS NOT NULL, NULL IS NOT NULL; expr B ETWEEN min AND max 如果expr对大于或等于min且expr是小于或等于max,BETWEEN返回1,否则它返回 0。如果所有的参数类型是一样得,这等价于表达式(min <= expr AND expr <= max)。第一个参数(expr)决 定比较如何被执行。如果expr是一个大小写不敏感的字符串表达式,进行一个大小写不敏感的字符串比较。如果expr是一个大小写敏感的字 符串表达式,进行一个大小写敏感的字符串比较。如果expr是一个整数表达式,进行整数比较。否则,进行一个浮点(实数)比较。 mysq l> select 1 BETWEEN 2 AND 3; -> 0mysql> select ''b'' BETWEEN ''a'' AN D ''c''; -> 1mysql> select 2 BETWEEN 2 AND ''3''; -> 1mysql> select 2 BETWEEN 2 AND ''x-3''; -> 0expr IN (value,...) 如果expr是在IN表中的任何值,返回 1,否则返回0。如果所有的值是常数,那么所有的值根据expr类型被计算和排序,然后项目的搜索是用二进制的搜索完成。这意味着如果IN 值表全部由常数组成,IN是很快的。如果expr是一个大小写敏感的字符串表达式,字符串比较以大小写敏感方式执行。 mysql> se lect 2 IN (0,3,5,''wefwf''); -> 0mysql> select ''wefwf'' IN (0,3,5,''w efwf''); -> 1 expr NOT IN (value,...) 与NOT (expr IN (value,...))相同 。 ISNULL(expr) 如果expr是NULL,ISNULL()返回1,否则它返回0。 mysql> select ISNU LL(1+1); -> 0mysql> select ISNULL(1/0); -> 1注意,使用=的NULL的值比较总为假! C OALESCE(list) 回来list中第一个非NULL的单元。 mysql> select COALESCE(NULL,1); -> 1mysql> select COALESCE(NULL,NULL,NULL); -> NULLINTERVAL(N,N1 ,N2,N3,...) 如果N< N1,返回0,如果N< N2,返回1等等。所有的参数被当作整数。为了函数能正确地工作,它要求N1 select INTERVAL(23, 1, 15, 17, 30, 44, 200); -> 3mysql> select INTERVAL(10, 1, 10, 100, 100 0); -> 2mysql> select INTERVAL(22, 23, 30, 44, 200); -> 0 字符串比较 函数通常,如果在字符串比较中的任何表达式是区分大小写的,比较以大小写敏感的方式执行。 expr LIKE pat [ESCAPE ''escape-char''] 使用SQL的简单的正规表达式比较的模式匹配。返回1(TRUE)或0(FALSE)。用LIKE,你可以 在模式中使用下列2个通配符字符: % 匹配任何数目的字符,甚至零个字符_ 精确匹配一个字符mysql> select ''David !'' LIKE ''David_''; -> 1mysql> select ''David!'' LIKE ''%D%v%''; -> 1为了 测试一个通配符的文字实例,用转义字符的加在字符前面。如果你不指定ESCAPE字符,假定为“\”: \% 匹配一%字符\_ 匹配一_ 字符mysql> select ''David!'' LIKE ''David\_''; -> 0mysql> select ''David _'' LIKE ''David\_''; -> 1为了指定一个不同的转义字符,使用ESCAPE子句: mysql> select ''D avid_'' LIKE ''David|_'' ESCAPE ''|''; -> 1LIKE允许用在数字的表达式上!(这是MySQL对AN SI SQL LIKE的一个扩充。) mysql> select 10 LIKE ''1%''; -> 1注意:因为MySQL在字符串 中使用C转义语法(例如,“\n”),你必须在你的LIKE字符串中重复任何“\”。例如,为了查找“\n”,指定它为“ \\n”,为了 查找“\”,指定它为“\\\\”(反斜线被分析器剥去一次,另一次是在模式匹配完成时,留下一条单独的反斜线被匹配)。 expr NO T LIKE pat [ESCAPE ''escape-char''] 与NOT (expr LIKE pat [ESCAPE ''es cape-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%%''; -> 0mysql> select ''M onty!'' REGEXP ''.''; -> 1mysql> select ''new\nline'' REGEXP ''new\\ .\\line''; -> 1mysql> 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''); -> -1mysql> sel ect STRCMP(''text2'', ''text''); -> 1mysql> select STRCMP(''text'', ''te xt''); -> 0 类型转换运算符BINARY BINARY操作符强制跟随它后面的字符串为一个二进制字符串。即使列没被定义为B INARY或BLOB,这是一个强制列比较区分大小写的简易方法。 mysql> select "a" = "A"; -> 1mysq l> select BINARY "a" = "A"; -> 0BINARY在MySQL 3.23.0中被引入。 控制流函数IFN ULL(expr1,expr2) 如果expr1不是NULL,IFNULL()返回expr1,否则它返回expr2。IFNULL( )返回一个数字或字符串值,取决于它被使用的上下文环境。 mysql> select IFNULL(1,0); -> 1mysql> select IFNULL(0,10); -> 0mysql> select IFNULL(1/0,10); -> 10mysq l> select IFNULL(1/0,''yes''); -> ''yes'' IF(expr1,expr2,expr3) 如果exp r1是TRUE(expr1<>0且expr1<>NULL),那么IF()返回expr2,否则它返回expr3。IF()返回一个数字 或字符串值,取决于它被使用的上下文。 mysql> select IF(1>2,2,3); -> 3mysql> select I F(1<2,''yes'',''no''); -> ''yes''mysql> select IF(strcmp(''test'',''test1'' ),''yes'',''no''); -> ''no''expr1作为整数值被计算,它意味着如果你正在测试浮点或字符串值,你应该使用一个比较操 作来做。 mysql> select IF(0.1,1,0); -> 0mysql> select IF(0.1<>0,1,0); -> 1在上面的第一种情况中,IF(0.1)返回0,因为0.1被变换到整数值, 导致测试IF(0)。这可能不是你期望的。在第二种 情况中,比较测试原来的浮点值看它是否是非零,比较的结果被用作一个整数。 CASE value WHEN [compare-valu e] THEN result [WHEN [compare-value] THEN result ...] [ELSE resul t] 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 T HEN "true" ELSE "false" END; -> "true"mysql> SELECT CASE BINARY " B" when "a" then 1 when "b" then 2 END; -> NULL 数学函数所有的数学函数在一个出错的 情况下返回NULL。 - 单目减。改变参数的符号。 mysql> select - 2;注意,如果这个操作符与一个BIGINT使用 ,返回值是一个BIGINT!这意味着你应该避免在整数上使用-,那可能有值-2^63! ABS(X) 返回X的绝对值。 mysql> select ABS(2); -> 2mysql> select ABS(-32); -> 32该功能可安全用于BIGINT值。 SIGN(X) 返回参数的符号,为-1、0或1,取决于X是否是负数、零或正数。 mysql> select SIGN(-32); -> -1mysql> select SIGN(0); -> 0mysql> select SIGN(234); -> 1 MOD(N,M) % 模 (类似C中的%操作符)。返回N被M除的余数。 mysql> select MOD(234, 10); -> 4mysql> select 253 % 7; -> 1mysql> select MOD(29,9); -> 2这个函数可 安全用于BIGINT值。 FLOOR(X) 返回不大于X的最大整数值。 mysql> select FLOOR(1.23); - > 1mysql> select FLOOR(-1.23); -> -2注意返回值被变换为一个BIGINT! CEILING(X ) 返回不小于X的最小整数值。 mysql> select CEILING(1.23); -> 2mysql> select CE ILING(-1.23); -> -1注意返回值被变换为一个BIGINT! ROUND(X) 返回参数X的四舍五入的一个整数。 m ysql> select ROUND(-1.23); -> -1mysql> select ROUND(-1.58); -> -2 mysql> select ROUND(1.58); -> 2 注意返回值被变换为一个BIGINT! ROUND(X,D) 返回参 数X的四舍五入的有D为小数的一个数字。如果D为0,结果将没有小数点或小数部分。 mysql> select ROUND(1.298 , 1); -> 1.3mysql> select ROUND(1.298, 0); -> 1注意返回值被变换为一个BIGINT! EXP(X) 返回值e(自然对数的底)的X次方。 mysql> select EXP(2); -> 7.389056mysql> select EXP(-2); -> 0.135335 LOG(X) 返回X的自然对数。 mysql> select LOG(2 ); -> 0.693147mysql> select LOG(-2); -> NULL如果你想要一个数字X的任意底B的对数,使用 公式LOG(X)/LOG(B)。 LOG10(X) 返回X的以10为底的对数。 mysql> select LOG10(2); - > 0.301030mysql> select LOG10(100); -> 2.000000mysql> select LOG1 0(-100); -> NULLPOW(X,Y) POWER(X,Y) 返回值X的Y次幂。 mysql> select POW( 2,2); -> 4.000000mysql> select POW(2,-2); -> 0.250000SQRT(X) 返回非负 数X的平方根。 mysql> select SQRT(4); -> 2.000000mysql> select SQRT(20); -> 4.472136 PI() 返回PI的值(圆周率)。 mysql> select PI(); -> 3.141593COS (X) 返回X的余弦, 在这里X以弧度给出。 mysql> select COS(PI()); -> -1.000000 SIN( X) 返回X的正弦值,在此X以弧度给出。 mysql> select SIN(PI()); -> 0.000000 TAN(X) 返回X的正切值,在此X以弧度给出。 mysql> select TAN(PI()+1); -> 1.557408 ACOS(X) 返回X反余弦,即其余弦值是X。如果X不在-1到1的范围,返回NULL。 mysql> select ACOS(1); -> 0.0 00000mysql> select ACOS(1.0001); -> NULLmysql> select ACOS(0); -> 1.570796 ASIN(X) 返回X反正弦值,即其正弦值是X。L如果X不在-1到1的范围,返回NULL。 mysql> se lect ASIN(0.2); -> 0.201358mysql> select ASIN(''foo''); -> 0.000000 ATAN(X) 返回X的反正切值,即其正切值是X。 mysql> select ATAN(2); -> 1.107149mysq l> select ATAN(-2); -> -1.107149ATAN2(X,Y) 返回2个变量X和Y的反正切。它类似于计算Y/ X的反正切,除了两个参数的符号被用来决定结果的象限。 mysql> select ATAN(-2,2); -> -0.785398 mysql> select ATAN(PI(),0); -> 1.570796 COT(X) 返回X的余切。 mysql> sel ect COT(12); -> -1.57267341mysql> select COT(0); -> NULLRAND() R AND(N) 返回在范围0到1.0内的随机浮点值。如果一个整数参数N被指定,它被用作种子值。 mysql> select RAND (); -> 0.5925mysql> select RAND(20); -> 0.1811mysql> select RAND( 20); -> 0.1811mysql> select RAND(); -> 0.2079mysql> select RAND() ; -> 0.7888你不能在一个ORDER BY子句用RAND()值使用列,因为ORDER BY将重复计算列多次。然而在MySQ L3.23中,你可以做: SELECT FROM table_name ORDER BY RAND(),这是有利于得到一个来自 SELECT FROM table1,table2 WHERE a=b AND c IT 1000的集合的随机样本。注意在一个WHERE子句里的一个RAND()将在每次WHERE被执行时重新评估。 LEAST(X, Y,...) 有2和2个以上的参数,返回最小(最小值)的参数。参数使用下列规则进行比较: 如果返回值被使用在一个INTEGER上下 文,或所有的参数都是整数值,他们作为整数比较。 如果返回值被使用在一个REAL上下文,或所有的参数是实数值,他们作为实数比较。 如 果任何参数是一个大小敏感的字符串,参数作为大小写敏感的字符串被比较。 在其他的情况下,参数作为大小写无关的字符串被比较。 mysq l> select LEAST(2,0); -> 0mysql> select LEAST(34.0,3.0,5.0,767.0) ; -> 3.0mysql> select LEAST("B","A","C"); -> "A"在MySQL 3.22.5以前的版 本,你可以使用MIN()而不是LEAST。 GREATEST(X,Y,...) 返回最大(最大值)的参数。参数使用与LEAST一样 的规则进行比较。 mysql> select GREATEST(2,0); -> 2mysql> select GREATEST( 34.0,3.0,5.0,767.0); -> 767.0mysql> select GREATEST("B","A","C"); -> "C"在MySQL在 3.22.5 以前的版本, 你能使用MAX()而不是GREATEST. DEGREES(X) 返回 参数X,从弧度变换为角度。 mysql> select DEGREES(PI()); -> 180.000000RADIANS(X ) 返回参数X,从角度变换为弧度。 mysql> select RADIANS(90); -> 1.570796TRUNCATE( X,D) 返回数字X,截断为D位小数。如果D为0,结果将没有小数点或小数部分。 mysql> select TRUNCATE(1. 223,1); -> 1.2mysql> select TRUNCATE(1.999,1); -> 1.9mysql> selec t TRUNCATE(1.999,0); -> 1 字符串函数如果结果的长度大于服务器参数max_allowed_packet, 字符串值函数返回NULL。见10.2.3 调节服务器参数。 对于针对字符串位置的操作,第一个位置被标记为1。 ASCII(str) 返回字符串str的最左面字符的ASCII代码值。如果str是空字符串,返回0。如果str是NULL,返回NULL。 mysql> select ASCII(''2''); -> 50mysql> select ASCII(2); -> 50mysql> sele ct ASCII(''dx''); -> 100也可参见ORD()函数。 ORD(str) 如果字符串str最左面字符是一个多字节字符 ,通过以格式((first byte ASCII code)256+(second byte ASCII code))[256 +third byte ASCII code...]返回字符的ASCII代码值来返回多字节字符代码。如果最左面的字符不是一个多字节 字符。返回与ASCII()函数返回的相同值。mysql> select ORD(''2''); -> 50 CONV(N,from_b ase,to_base) 在不同的数字基之间变换数字。返回数字N的字符串数字,从from_base基变换为to_base基,如果任 何参数是NULL,返回NULL。参数N解释为一个整数,但是可以指定为一个整数或一个字符串。最小基是2且最大的基是36。如果to_b ase是一个负数,N被认为是一个有符号数,否则,N被当作无符号数。 CONV以64位点精度工作。 mysql> select CO NV("a",16,2); -> ''1010''mysql> select CONV("6E",18,8); -> ''172''mys ql> select CONV(-17,10,-18); -> ''-H''mysql> select CONV(10+"10"+''1 0''+0xa,10,10); -> ''40'' BIN(N) 返回二进制值N的一个字符串表示,在此N是一个长整数(BIGINT)数字 ,这等价于CONV(N,10,2)。如果N是NULL,返回NULL。 mysql> select BIN(12); -> ''110 0''OCT(N) 返回八进制值N的一个字符串的表示,在此N是一个长整型数字,这等价于CONV(N,10,8)。如果N是NULL,返 回NULL。 mysql> select OCT(12); -> ''14'' HEX(N) 返回十六进制值N一个字符串的表示,在此N 是一个长整型(BIGINT)数字,这等价于CONV(N,10,16)。如果N是NULL,返回NULL。 mysql> select HEX(255); -> ''FF'' CHAR(N,...) CHAR()将参数解释为整数并且返回由这些整数的ASCII代码字符组 成的一个字符串。NULL值被跳过。 mysql> select CHAR(77,121,83,81,''76''); -> ''MySQ L''mysql> select CHAR(77,77.3,''77.3''); -> ''MMM'' CONCAT(str1,str2,. ..) 返回来自于参数连结的字符串。如果任何参数是NULL,返回NULL。可以有超过2个的参数。一个数字参数被变换为等价的字符串形 式。 mysql> select CONCAT(''My'', ''S'', ''QL''); -> ''MySQL''mysql> select CONCAT(''My'', NULL, ''QL''); -> NULLmysql> select CONCAT(14.3); -> ''14.3''LENGTH(str) OCTET_LENGTH(str) CHAR_LENGTH(str) CHARACTER _LENGTH(str) 返回字符串str的长度。 mysql> select LENGTH(''text''); -> 4mysql > select OCTET_LENGTH(''text''); -> 4注意,对于多字节字符,其CHAR_LENGTH()仅计算一次 。 LOCATE(substr,str) POSITION(substr IN str) 返回子串substr在字符串str第一 个出现的位置,如果substr不是在str里面,返回0. mysql> select LOCATE(''bar'', ''foobarb ar''); -> 4mysql> select LOCATE(''xbar'', ''foobar''); -> 0该函数是多字节可靠的。 LOCATE(substr,str,pos) 返回子串substr在字符串str第一个出现的位置,从位置pos开始。如果sub str不是在str里面,返回0。mysql> select LOCATE(''bar'', ''foobarbar'',5); -> 7这 函数是多字节可靠的。 INSTR(str,substr) 返回子串substr在字符串str中的第一个出现的位置。这与有2个参数形 式的LOCATE()相同,除了参数被颠倒。 mysql> select INSTR(''foobarbar'', ''bar''); -> 4mysql> select INSTR(''xbar'', ''foobar''); -> 0这函数是多字节可靠的。 LPAD(str ,len,padstr) 返回字符串str,左面用字符串padstr填补直到str是len个字符长。 mysql> select LPAD(''hi'',4,''??''); -> ''??hi'' RPAD(str,len,padstr) 返回字符串str,右面用字符串 padstr填补直到str是len个字符长。mysql> select RPAD(''hi'',5,''?''); -> ''hi???''L EFT(str,len) 返回字符串str的最左面len个字符。mysql> select LEFT(''foobarbar'', 5 ); -> ''fooba''该函数是多字节可靠的。 RIGHT(str,len) 返回字符串str的最右面len个字符。 mysql > select RIGHT(''foobarbar'', 4); -> ''rbar''该函数是多字节可靠的。 SUBSTRING(st r,pos,len) SUBSTRING(str FROM pos FOR len) MID(str,pos,len) 从字符 串str返回一个len个字符的子串,从位置pos开始。使用FROM的变种形式是ANSI SQL92语法。 mysql> selec t SUBSTRING(''Quadratically'',5,6); -> ''ratica''该函数是多字节可靠的。 SUBSTRIN G(str,pos) SUBSTRING(str FROM pos) 从字符串str的起始位置pos返回一个子串。 mysql> select SUBSTRING(''Quadratically'',5); -> ''ratically''mysql> select SUBSTRING(''foobarbar'' FROM 4); -> ''barbar''该函数是多字节可靠的。 SUBSTRING_ INDEX(str,delim,count) 返回从字符串str的第count个出现的分隔符delim之后的子串。如果count是 正数,返回最后的分隔符到左边(从左边数) 的所有字符。如果count是负数,返回最后的分隔符到右边的所有字符(从右边数)。 mys ql> select SUBSTRING_INDEX(''www.mysql.com'', ''.'', 2); -> ''www.mysq l''mysql> select SUBSTRING_INDEX(''www.mysql.com'', ''.'', -2); -> ''my sql.com''该函数对多字节是可靠的。 LTRIM(str) 返回删除了其前置空格字符的字符串str。 mysql> selec t LTRIM('' barbar''); -> ''barbar''RTRIM(str) 返回删除了其拖后空格字符的字符串str。 m ysql> select RTRIM(''barbar ''); -> ''barbar''该函数对多字节是可靠的。 TRIM([[ BOTH | LEADING | TRAILING] [remstr] FROM] str) 返回字符串str,其所有remstr 前缀或后缀被删除了。如果没有修饰符BOTH、LEADING或TRAILING给出,BOTH被假定。如果remstr没被指定,空格被 删除。 mysql> select TRIM('' bar ''); -> ''bar''mysql> select TRIM(LE ADING ''x'' FROM ''xxxbarxxx''); -> ''barxxx''mysql> select TRIM(BOTH '' x'' FROM ''xxxbarxxx''); -> ''bar''mysql> select TRIM(TRAILING ''xyz'' F ROM ''barxxyz''); -> ''barx''该函数对多字节是可靠的。 SOUNDEX(str) 返回str的一个同音字符串。 听起来“大致相同”的2个字符串应该有相同的同音字符串。一个“标准”的同音字符串长是4个字符,但是SOUNDEX()函数返回一个任意 长的字符串。你可以在结果上使用SUBSTRING()得到一个“标准”的 同音串。所有非数字字母字符在给定的字符串中被忽略。所有在A -Z之外的字符国际字母被当作元音。 mysql> select SOUNDEX(''Hello''); -> ''H400''mysql> select SOUNDEX(''Quadratically''); -> ''Q36324'' SPACE(N) 返回由N个空格字符组 成的一个字符串。 mysql> select SPACE(6); -> '' '' REPLACE(str,from_str ,to_str) 返回字符串str,其字符串from_str的所有出现由字符串to_str代替。 mysql> select RE PLACE(''www.mysql.com'', ''w'', ''Ww''); -> ''WwWwWw.mysql.com''该函数对多字节是可 靠的。 REPEAT(str,count) 返回由重复countTimes次的字符串str组成的一个字符串。如果count <= 0,返回一个空字符串。如果str或count是NULL,返回NULL。 mysql> select REPEAT(''MySQL'', 3); -> ''MySQLMySQLMySQL'' REVERSE(str) 返回颠倒字符顺序的字符串str。 mysql> se lect REVERSE(''abc''); -> ''cba''该函数对多字节可靠的。 INSERT(str,pos,len,newst r) 返回字符串str,在位置pos起始的子串且len个字符长得子串由字符串newstr代替。 mysql> select INS ERT(''Quadratic'', 3, 4, ''What''); -> ''QuWhattic''该函数对多字节是可靠的。 ELT(N, str1,str2,str3,...) 如果N= 1,返回str1,如果N= 2,返回str2,等等。如果N小于1或大于参数个数, 返回NULL。ELT()是FIELD()反运算。 mysql> select ELT(1, ''ej'', ''Heja'', ''hej'' , ''foo''); -> ''ej''mysql> select ELT(4, ''ej'', ''Heja'', ''hej'', ''foo'') ; -> ''foo''FIELD(str,str1,str2,str3,...) 返回str在str1, str2, str3, . ..清单的索引。如果str没找到,返回0。FIELD()是ELT()反运算。 mysql> select FIELD(''ej'', ''Hej'', ''ej'', ''Heja'', ''hej'', ''foo''); -> 2mysql> select FIELD(''fo'', ''Hej'', ''ej'', ''Heja'', ''hej'', ''foo''); -> 0FIND_IN_SET(str,strlist) 如果字符串str在由N子串组成的表strlist之中,返回一个1到N的值。一个字符串表是被“,”分隔的子串组成的一个字符串。如果 第一个参数是一个常数字符串并且第二个参数是一种类型为SET的列,FIND_IN_SET()函数被优化而使用位运算!如果str不是在 strlist里面或如果strlist是空字符串,返回0。如果任何一个参数是NULL,返回NULL。如果第一个参数包含一个“,”, 该函数将工作不正常。 mysql> SELECT FIND_IN_SET(''b'',''a,b,c,d''); -> 2 MAKE_SE T(bits,str1,str2,...) 返回一个集合 (包含由“,”字符分隔的子串组成的一个字符串),由相应的位在bits集合 中的的字符串组成。str1对应于位0,str2对应位1,等等。在str1, str2, ...中的NULL串不添加到结果中。 my sql> SELECT MAKE_SET(1,''a'',''b'',''c''); -> ''a''mysql> SELECT MAKE_SET (1 | 4,''hello'',''nice'',''world''); -> ''hello,world''mysql> SELECT MAK E_SET(0,''a'',''b'',''c''); -> ''''EXPORT_SET(bits,on,off,[separator,[num ber_of_bits]]) 返回一个字符串,在这里对于在“bits”中设定每一位,你得到一个“on”字符串,并且对于每个复位(r eset)的位,你得到一个“off”字符串。每个字符串用“separator”分隔(缺省“,”),并且只有“bits”的“numb er_of_bits” (缺省64)位被使用。 mysql> select EXPORT_SET(5,''Y'',''N'','','',4) -> Y,N,Y,N LCASE(str) LOWER(str) 返回字符串str,根据当前字符集映射(缺省是ISO-8859 -1 Latin1)把所有的字符改变成小写。该函数对多字节是可靠的。 mysql> select LCASE(''QUADRATIC ALLY''); -> ''quadratically'' UCASE(str) UPPER(str) 返回字符串str,根据当前字符 集映射(缺省是ISO-8859-1 Latin1)把所有的字符改变成大写。该函数对多字节是可靠的。 mysql> select U CASE(''Hej''); -> ''HEJ''该函数对多字节是可靠的。 LOAD_FILE(file_name) 读入文件并且作为一个 字符串返回文件内容。文件必须在服务器上,你必须指定到文件的完整路径名,而且你必须有file权限。文件必须所有内容都是可读的并且小于 max_allowed_packet。如果文件不存在或由于上面原因之一不能被读出,函数返回NULL。 mysql> UPDATE table_name SET blob_column=LOAD_FILE("/tmp/picture") WHERE id=1;M ySQL必要时自动变换数字为字符串,并且反过来也如此: mysql> SELECT 1+"1"; -> 2mysql> SELEC T CONCAT(2,'' test''); -> ''2 test''如果你想要明确地变换一个数字到一个字符串,把它作为参数传递到CON CAT()。 如果字符串函数提供一个二进制字符串作为参数,结果字符串也是一个二进制字符串。被变换到一个字符串的数字被当作是一个二进 制字符串。这仅影响比较。 日期和时间函数对于每个类型拥有的值范围以及并且指定日期何时间值的有效格式的描述见7.3.6 日期和时间 类型。 这里是一个使用日期函数的例子。下面的查询选择了所有记录,其date_col的值是在最后30天以内: mysql> SELE CT something FROM table WHERE TO_DAYS(NOW()) - TO_DAYS(date_col) <= 30;DAYOFWEEK(date) 返回日期date的星期索引(1=星期天,2=星期一, ……7=星期六)。这些索引值对应 于ODBC标准。 mysql> select DAYOFWEEK(''1998-02-03''); -> 3 WEEKDAY(date ) 返回date的星期索引(0=星期一,1=星期二, ……6= 星期天)。 mysql> select WEEKDAY(''1997 -10-04 22:23:00''); -> 5mysql> select WEEKDAY(''1997-11-05''); -> 2 DAYOFMONTH(date) 返回date的月份中日期,在1到31范围内。 mysql> select DAYOFMONTH( ''1998-02-03''); -> 3DAYOFYEAR(date) 返回date在一年中的日数, 在1到366范围内。 mysq l> select DAYOFYEAR(''1998-02-03''); -> 34MONTH(date) 返回date的月份,范围1 到12。 mysql> select MONTH(''1998-02-03''); -> 2 DAYNAME(date) 返回date 的星期名字。 mysql> select DAYNAME("1998-02-05"); -> ''Thursday''MONTHNAM E(date) 返回date的月份名字。 mysql> select MONTHNAME("1998-02-05"); -> ''F ebruary'' QUARTER(date) 返回date一年中的季度,范围1到4。 mysql> select QUARTER( ''98-04-01''); -> 2 WEEK(date) WEEK(date,first) 对于星期天是一周的第一天的地方,有一 个单个参数,返回date的周数,范围在0到52。2个参数形式WEEK()允许你指定星期是否开始于星期天或星期一。如果第二个参数是0 ,星期从星期天开始,如果第二个参数是1,从星期一开始。 mysql> select WEEK(''1998-02-20''); -> 7mysql> select WEEK(''1998-02-20'',0); -> 7mysql> select WEEK(''1998 -02-20'',1); -> 8YEAR(date) 返回date的年份,范围在1000到9999。mysql> select Y EAR(''98-02-03''); -> 1998HOUR(time) 返回time的小时,范围是0到23。mysql> selec t HOUR(''10:05:03''); -> 10MINUTE(time) 返回time的分钟,范围是0到59。mysql> se lect MINUTE(''98-02-03 10:05:03''); -> 5SECOND(time) 回来time的秒数,范围是0 到59。mysql> select SECOND(''10:05:03''); -> 3PERIOD_ADD(P,N) 增加N个月到阶 段P(以格式YYMM或YYYYMM)。以格式YYYYMM返回值。注意阶段参数P不是日期值。 mysql> select PERIO D_ADD(9801,2); -> 199803PERIOD_DIFF(P1,P2) 返回在时期P1和P2之间月数,P1和P2应该 以格式YYMM或YYYYMM。注意,时期参数P1和P2不是日期值。 mysql> select PERIOD_DIFF(9802, 199703); -> 11 DATE_ADD(date,INTERVAL expr type) DATE_SUB(dat e,INTERVAL expr type) ADDDATE(date,INTERVAL expr type) SUBDATE( date,INTERVAL expr type) 这些功能执行日期运算。对于MySQL 3.22,他们是新的。ADDDATE()和 SUBDATE()是DATE_ADD()和DATE_SUB()的同义词。在MySQL 3.23中,你可以使用+和-而不是DATE_ ADD()和DATE_SUB()。(见例子)date是一个指定开始日期的DATETIME或DATE值,expr是指定加到开始日期或 从开始日期减去的间隔值一个表达式,expr是一个字符串;它可以以一个“-”开始表示负间隔。type是一个关键词,指明表达式应该如何 被解释。EXTRACT(type FROM date)函数从日期中返回“type”间隔。下表显示了type和expr参数怎样被关联 : type值 含义 期望的expr格式 SECOND 秒SECONDS MINUTE 分钟MINUTES HOUR 时间HOUR S DAY 天DAYS MONTH 月MONTHS YEAR 年YEARS MINUTE_SECOND 分钟和秒"MINUTES: SECONDS" HOUR_MINUTE 小时和分钟"HOURS:MINUTES" DAY_HOUR 天和小时"DAYS HOUR S" YEAR_MONTH 年和月"YEARS-MONTHS" HOUR_SECOND 小时, 分钟,"HOURS:MINUTES :SECONDS" DAY_MINUTE 天, 小时, 分钟"DAYS HOURS:MINUTES" DAY_SECOND 天, 小时, 分钟, 秒"DAYS HOURS:MINUTES:SECONDS" MySQL在expr格式中允许任何标点分隔符。表示显示 的是建议的分隔符。如果date参数是一个DATE值并且你的计算仅仅包含YEAR、MONTH和DAY部分(即,没有时间部分),结果是 一个DATE值。否则结果是一个DATETIME值。 mysql> SELECT "1997-12-31 23:59:59" + I NTERVAL 1 SECOND; -> 1998-01-01 00:00:00mysql> SELECT INTERVAL 1 DAY + "1997-12-31"; -> 1998-01-01mysql> SELECT "1998-01-01" - INT ERVAL 1 SECOND; -> 1997-12-31 23:59:59 mysql> SELECT DATE_ADD("19 97-12-31 23:59:59", INTERVAL 1 SECOND); -> 1998-01-01 00:00:00mys ql> SELECT DATE_ADD("1997-12-31 23:59:59", INTERVAL 1 DAY); -> 19 98-01-01 23:59:59mysql> SELECT DATE_ADD("1997-12-31 23:59:59", IN TERVAL "1:1" MINUTE_SECOND); -> 1998-01-01 00:01:00mysql> SELECT DATE_SUB("1998-01-01 00:00:00", INTERVAL "1 1:1:1" DAY_SECOND); - > 1997-12-30 22:58:59mysql> SELECT DATE_ADD("1998-01-01 00:00:00" , INTERVAL "-1 10" DAY_HOUR); -> 1997-12-30 14:00:00mysql> SELECT DATE_SUB("1998-01-02", INTERVAL 31 DAY); -> 1997-12-02mysql> SEL ECT EXTRACT(YEAR FROM "1999-07-02"); -> 1999mysql> SELECT EXTRACT (YEAR_MONTH FROM "1999-07-02 01:02:03"); -> 199907mysql> SELECT E XTRACT(DAY_MINUTE FROM "1999-07-02 01:02:03"); -> 20102如果你指定太短的间隔 值(不包括type关键词期望的间隔部分),MySQL假设你省掉了间隔值的最左面部分。例如,如果你指定一个type是DAY_SECO ND,值expr被希望有天、小时、分钟和秒部分。如果你象"1:10"这样指定值,MySQL假设日子和小时部分是丢失的并且值代表分钟 和秒。换句话说,"1:10" DAY_SECOND以它等价于"1:10" MINUTE_SECOND的方式解释,这对那MySQL解 释TIME值表示经过的时间而非作为一天的时间的方式有二义性。如果你使用确实不正确的日期,结果是NULL。如果你增加MONTH、YE AR_MONTH或YEAR并且结果日期大于新月份的最大值天数,日子在新月用最大的天调整。 mysql> select DATE_A DD(''1998-01-30'', Interval 1 month); -> 1998-02-28注意,从前面的例子中词INTER VAL和type关键词不是区分大小写的。 TO_DAYS(date) 给出一个日期date,返回一个天数(从0年的天数)。 my sql> select TO_DAYS(950501); -> 728779mysql> select TO_DAYS(''1997 -10-07''); -> 729669TO_DAYS()不打算用于使用格列高里历(1582)出现前的值。 FROM_DAYS(N) 给出一个天数N,返回一个DATE值。 mysql> select FROM_DAYS(729669); -> ''1997-10- 07''TO_DAYS()不打算用于使用格列高里历(1582)出现前的值。 DATE_FORMAT(date,format) 根据f ormat字符串格式化date值。下列修饰符可以被用在format字符串中: %M 月名字(January……December) %W 星期名字(Sunday……Saturday) %D 有英语前缀的月份的日期(1st, 2nd, 3rd, 等等。)%Y 年, 数字, 4 位%y 年, 数字, 2 位%a 缩写的星期名字(Sun……Sat) %d 月份中的天数, 数字(00……31) % e 月份中的天数, 数字(0……31) %m 月, 数字(01……12) %c 月, 数字(1……12) %b 缩写的月份名字(J an……Dec) %j 一年中的天数(001……366) %H 小时(00……23) %k 小时(0……23) %h 小时(01… …12) %I 小时(01……12) %l 小时(1……12) %i 分钟, 数字(00……59) %r 时间,12 小时(hh: mm:ss [AP]M) %T 时间,24 小时(hh:mm:ss) %S 秒(00……59) %s 秒(00……59) %p A M或PM %w 一个星期中的天数(0=Sunday ……6=Saturday )%U 星期(0……52), 这里星期天是星期的第一 天%u 星期(0……52), 这里星期一是星期的第一天%% 一个文字“%”。 所有的其他字符不做解释被复制到结果中。 mysql> select DATE_FORMAT(''1997-10-04 22:23:00'', ''%W %M %Y''); -> ''Satur day October 1997''mysql> select DATE_FORMAT(''1997-10-04 22:23:00'', ''%H:%i:%s''); -> ''22:23:00''mysql> select DATE_FORMAT(''1997-10-04 22:23:00'', ''%D %y %a %d %m %b %j''); -> ''4th 97 Sat 04 10 Oct 277'' mysql> select DATE_FORMAT(''1997-10-04 22:23:00'', ''%H %k %I %r %T %S %w''); -> ''22 22 10 10:23:00 PM 22:23:00 00 6''MySQL3.23中,在格式修饰符 字符前需要%。在MySQL更早的版本中,%是可选的。 TIME_FORMAT(time,format) 这象上面的DATE_FOR MAT()函数一样使用,但是format字符串只能包含处理小时、分钟和秒的那些格式修饰符。其他修饰符产生一个NULL值或0。 CU RDATE() CURRENT_DATE 以''YYYY-MM-DD''或YYYYMMDD格式返回今天日期值,取决于函数是在一个字符 串还是数字上下文被使用。 mysql> select CURDATE(); -> ''1997-12-15''mysql> selec t CURDATE() + 0; -> 19971215CURTIME() CURRENT_TIME 以''HH:MM:SS''或H HMMSS格式返回当前时间值,取决于函数是在一个字符串还是在数字的上下文被使用。 mysql> select CURTIME(); -> ''23:50:26''mysql> select CURTIME() + 0; -> 235026NOW() SYSDAT E() CURRENT_TIMESTAMP 以''YYYY-MM-DD HH:MM:SS''或YYYYMMDDHHMMSS格式返回当 前的日期和时间,取决于函数是在一个字符串还是在数字的上下文被使用。 mysql> select NOW(); -> ''1997-1 2-15 23:50:26''mysql> select NOW() + 0; -> 19971215235026UNIX_TIME STAMP() UNIX_TIMESTAMP(date) 如果没有参数调用,返回一个Unix时间戳记(从''1970-01-01 00:00:00''GMT开始的秒数)。如果UNIX_TIMESTAMP()用一个date参数被调用,它返回从''1970-01-01 00:00:00'' GMT开始的秒数值。date可以是一个DATE字符串、一个DATETIME字符串、一个TIMESTAMP或以 YYMMDD或YYYYMMDD格式的本地时间的一个数字。 mysql> select UNIX_TIMESTAMP(); -> 8 82226357mysql> select UNIX_TIMESTAMP(''1997-10-04 22:23:00''); -> 8 75996580当UNIX_TIMESTAMP被用于一个TIMESTAMP列,函数将直接接受值,没有隐含的“string-to-u nix-timestamp”变换。 FROM_UNIXTIME(unix_timestamp) 以''YYYY-MM-DD HH:M M:SS''或YYYYMMDDHHMMSS格式返回unix_timestamp参数所表示的值,取决于函数是在一个字符串还是或数字上下 文中被使用。 mysql> select FROM_UNIXTIME(875996580); -> ''1997-10-04 22: 23:00''mysql> select FROM_UNIXTIME(875996580) + 0; -> 199710042223 00FROM_UNIXTIME(unix_timestamp,format) 返回表示 Unix 时间标记的一个字符串,根据for mat字符串格式化。format可以包含与DATE_FORMAT()函数列出的条目同样的修饰符。 mysql> select FR OM_UNIXTIME(UNIX_TIMESTAMP(), ''%Y %D %M %h:%i:%s %x''); -> ''1997 2 3rd December 03:43:30 x''SEC_TO_TIME(seconds) 返回seconds参数,变换成小时、分钟 和秒,值以''HH:MM:SS''或HHMMSS格式化,取决于函数是在一个字符串还是在数字上下文中被使用。 mysql> select SEC_TO_TIME(2378); -> ''00:39:38''mysql> select SEC_TO_TIME(2378) + 0; -> 3938TIME_TO_SEC(time) 返回time参数,转换成秒。 mysql> select TIME_T O_SEC(''22:23:00''); -> 80580mysql> select TIME_TO_SEC(''00:39:38''); -> 2378 其他函数DATABASE() 返回当前的数据库名字。 mysql> select DATABASE(); -> ''test''如果没有当前的数据库,DATABASE()返回空字符串。 USER() SYSTEM_USER() SESSION _USER() 返回当前MySQL用户名。 mysql> select USER(); -> ''davida@localhost'' 在MySQL 3.22.11或以后版本中,这包括用户名和客户主机名。你可以象这样只提取用户名部分(值是否包括主机名部分均可工作): mysql> select substring_index(USER(),"@",1); -> ''davida''PASSWORD (str) 从纯文本口令str计算一个口令字符串。该函数被用于为了在user授权表的Password列中存储口令而加密MySQL口 令。 mysql> select PASSWORD(''badpwd''); -> ''7f84554057dd964b''PASSWOR D()加密是非可逆的。PASSWORD()不以与Unix口令加密的相同的方法执行口令加密。你不应该假定如果你的Unix 口令和你的 MySQL口令是一样的,PASSWORD()将导致与在Unix口令文件存储的相同的加密值。见ENCRYPT()。 ENCRYPT( str[,salt]) 使用Unix crypt()系统调用加密str。salt参数应该是一个有2个字符的字符串。(MySQL 3 .22.16中,salt可以长于2个字符。)mysql> select ENCRYPT("hello"); -> ''VxuFAJX VARROc''如果crypt()在你的系统上不可用,ENCRYPT()总是返回NULL。ENCRYPT()只保留str起始8个字符 而忽略所有其他,至少在某些系统上是这样。这将由底层的crypt()系统调用的行为决定。 ENCODE(str,pass_str) 使用pass_str作为口令加密str。为了解密结果,使用DECODE()。结果是一个二进制字符串,如果你想要在列中保存它,使用一 个BLOB列类型。 DECODE(crypt_str,pass_str) 使用pass_str作为口令解密加密的字符串crypt_ str。crypt_str应该是一个由ENCODE()返回的字符串。 MD5(string) 对字符串计算MD5校验和。值作为一个 32长的十六进制数字被返回可以,例如用作哈希(hash)键。 mysql> select MD5("testing") -> ''a e2b1fca515949e5d54fb22b8ed95575''这是一个“RSA数据安全公司的MD5消息摘要算法”。 LAST_I NSERT_ID([expr]) 返回被插入一个AUTO_INCREMENT列的最后一个自动产生的值。见20.4.29 mysql _insert_id()。 mysql> select LAST_INSERT_ID(); -> 195产生的最后ID以每个连接为 基础在服务器被维护,它不会被其他客户改变。如果你更新另外一个有非魔术值(即,不是NULL和不是0的一个值)的AUTO_INCREM ENT列,它甚至不会被改变。如果expr作为一个参数在一个UPDATE子句的LAST_INSERT_ID()里面给出,那么参数值作 为一个LAST_INSERT_ID()值被返回。这可以用来模仿顺序:首先创建表: mysql> create table sequ ence (id int not null);mysql> insert into sequence values (0);然后表 能被用来产生顺序号,象这样: mysql> update sequence set id=LAST_INSERT_ID(id+1) ;你可以不调用LAST_INSERT_ID()而产生顺序,但是这样使用函数的实用程序在服务器上自动维护ID值作为最后自动产生的值。 你可以检索新的ID值,就像你能读入正常MySQL中的任何正常的AUTO_INCREMENT值一样。例如,LAST_INSERT_I D()(没有一个参数 )将返回新ID。C API函数mysql_insert_id()也可被用来得到值。 FORMAT(X,D) 格式化数字X为类似于格式''#,###,###.##'',四舍五入到D为小数。如果D为0,结果将没有小数点和小数部分。 mysql> select FORMAT(12332.123456, 4); -> ''12,332.1235''mysql> select FOR MAT(12332.1,4); -> ''12,332.1000''mysql> select FORMAT(12332.2,0); -> ''12,332''VERSION() 返回表明MySQL服务器版本的一个字符串。 mysql> select VERSION( ); -> ''3.22.19b-log''GET_LOCK(str,timeout) 试图获得由字符串str给定的一个名字的锁定,第 二个timeout为超时。如果锁定成功获得,返回1,如果尝试超时了,返回0,或如果发生一个错误,返回NULL(例如从存储器溢出或线 程用mysqladmin kill被杀死)。当你执行RELEASE_LOCK()时、执行一个新的GET_LOCK()或线程终止时, 一个锁定被释放。该函数可以用来实现应用锁或模拟记录锁,它阻止其他客户用同样名字的锁定请求;赞成一个给定的锁定字符串名字的客户可以使 用字符串执行子协作建议的锁定。 mysql> select GET_LOCK("lock1",10); -> 1mysql> se lect GET_LOCK("lock2",10); -> 1mysql> select RELEASE_LOCK("lock2" ); -> 1mysql> select RELEASE_LOCK("lock1"); -> NULL注意,第二个RELEASE_ LOCK()调用返回NULL,因为锁"lock1"自动地被第二个GET_LOCK()调用释放。 RELEASE_LOCK(str) 释放字符串str命名的通过GET_LOCK()获得的锁。如果锁被释放,返回1,如果锁没被这个线程锁定(在此情况下锁没被释放)返回 0,并且如果命名的锁不存在,返回NULL。如果锁从来没有通过调用GET_LOCK()获得或如果它已经被释放了,锁将不存在。 BEN CHMARK(count,expr) BENCHMARK()函数重复countTimes次执行表达式expr,它可以用于计时MyS QL处理表达式有多快。结果值总是0。意欲用于mysql客户,它报告查询的执行时间。 mysql> select BENCHMARK (1000000,encode("hello","goodbye"));+---------------------------- ------------------+| BENCHMARK(1000000,encode("hello","goodbye")) |+----------------------------------------------+| 0 |+------------------------------- ---------------+1 row in set (4.74 sec)报告的时间是客户端的经过时间,不是在服务器端的CPU 时间。执行BENCHMARK()若干次可能是明智的,并且注意服务器机器的负载有多重来解释结果。 与GROUP BY子句一起使用的 函数如果你在不包含GROUP BY子句的一个语句中使用聚合函数,它等价于聚合所有行。 COUNT(expr) 返回由一个SELEC T语句检索出来的行的非NULL值的数目。 mysql> select student.student_name,COUNT() from student,course where student.student_id=course.student_id GR OUP BY student_name;COUNT()在它返回的检索出来的行数目上有些不同,不管他们是否包含NULL值。如果SE LECT从一个表检索,或没有检索出其他列并且没有WHERE子句,COUNT()被优化以便快速地返回。例如: mysql> sel ect COUNT() from student; COUNT(DISTINCT expr,[expr...]) 返回一个不同 值的数目。 mysql> select COUNT(DISTINCT results) from student;在MySQL中, 你可以通过给出一个表达式列表以得到不同的表达式组合的数目。在 ANSI SQL中,你可能必须在CODE(DISTINCT ..)内 进行所有表达式的连接。 AVG(expr) 返回expr的平均值。 mysql> select student_name, AVG (test_score) from student GROUP BY student_name; MIN(expr) MAX( expr) 返回expr的最小或最大值。MIN()和MAX()可以有一个字符串参数;在这种的情况下,他们返回最小或最大的字符串值。 mysql> select student_name, MIN(test_score), MAX(test_score) fro m student GROUP BY student_name; SUM(expr) 返回expr的和。注意,如果返回的集合没有行 ,它返回NULL! STD(expr) STDDEV(expr) 返回expr标准差(deviation)。这是对 ANSI S QL 的扩展。该函数的形式STDDEV()是提供与Oracle的兼容性。 BIT_OR(expr) 返回expr里所有位的位或。计 算用 64 位(BIGINT)精度进行。 BIT_AND(expr) 返回expr里所有位的位与。计算用 64 位(BIGINT) 精度进行。 MySQL扩展了GROUP BY的用法。你可以不出现在的GROUP BY部分的SELECT表达式中使用列或计算,这表示 这个组的任何可能值。你可以使用它是性能更好,避免在不必要的项目上排序和分组。例如,你在下列查询中不需要在customer.name 上聚合: mysql> select order.custid,customer.name,max(payments) from order,customer where order.custid = customer.custid GROUP BY orde r.custid;在 ANSI SQL中,你将必须将customer.name加到GROUP BY子句。在MySQL中,名字是冗余 的。 如果你从GROUP BY部分省略的列在组中不是唯一的,不要使用这个功能。在某些情况下,你可以使用MIN()和MAX()获得一 个特定的列值,即使它不是唯一的。下例给出从包含sort列中最小值的行的column值: substr(MIN(concat(sor t,space(6-length(sort)),column),7,length(column)))注意,如果你正在使用MySQL 3.22(或更早)或如果你正在试图遵从ANSI SQL,你不能在GROUP BY或ORDER BY子句中使用表达式。你可以通过使 用表达式的一个别名解决此限制: mysql> SELECT id,FLOOR(value/100) AS val FROM tbl _name GROUP BY id,val ORDER BY val;在MySQL3.23中,你可以这样做: mysql> SEL ECT id,FLOOR(value/100) FROM tbl_name ORDER BY RAND(); CREATE DAT ABASE句法CREATE DATABASE db_nameCREATE DATABASE用给定的名字创建一个数据库。允许的数据库 名字规则在7.1.5 数据库、桌子、索引、列和别名命名中给出。如果数据库已经存在,发生一个错误。 在MySQL中的数据库实现成包含 对应数据库中表的文件的目录。因为数据库在初始创建时没有任何表,CREATE DATABASE语句只是在MySQL数据目录下面创建一 个目录。 你也可以用mysqladmin创建数据库。见12.1 不同的MySQL程序的概述。 DROP DATABASE句法DR OP DATABASE [IF EXISTS] db_nameDROP DATABASE删除数据库中的所有表和数据库。要小心地使用 这个命令! DROP DATABASE返回从数据库目录被删除的文件的数目。通常,这3倍于表的数量,因为每张表对应于一个“.MYD” 文件、一个“.MYI”文件和一个“.frm”文件。 在MySQL 3.22或以后版本中,你可以使用关键词IF EXISTS阻止一个 错误的发生,如果数据库不存在。 你也可以用mysqladmin丢弃数据库。见12.1 不同的 MySQL 程序的概述。 CREA TE TABLE句法CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name [(cre ate_definition,...)][table_options] [select_statement]create_defi nition: col_name type [NOT NULL | NULL] [DEFAULT default_value] [ AUTO_INCREMENT] [PRIMARY KEY] [reference_definition] or PRIMAR Y KEY (index_col_name,...) or KEY [index_name] (index_col_name ,...) or INDEX [index_name] (index_col_name,...) or UNIQUE [INDEX] [index_name] (index_col_name,...) or [CONSTRAINT symbo l] FOREIGN KEY index_name (index_col_name,...) [reference_definit ion] or CHECK (expr)type: TINYINT[(length)] [UNSIGNED] [ZEROFI LL] or SMALLINT[(length)] [UNSIGNED] [ZEROFILL] or MEDIUMIN T[(length)] [UNSIGNED] [ZEROFILL] or INT[(length)] [UNSIGNED] [ZEROFILL] or INTEGER[(length)] [UNSIGNED] [ZEROFILL] or BI GINT[(length)] [UNSIGNED] [ZEROFILL] or REAL[(length,decimals) ] [UNSIGNED] [ZEROFILL] or DOUBLE[(length,decimals)] [UNSIGNED ] [ZEROFILL] or FLOAT[(length,decimals)] [UNSIGNED] [ZEROFILL] or DECIMAL(length,decimals) [UNSIGNED] [ZEROFILL] or NUMER IC(length,decimals) [UNSIGNED] [ZEROFILL] or CHAR(length) [BIN ARY] or VARCHAR(length) [BINARY] or DATE or TIME or T IMESTAMP or DATETIME or TINYBLOB or BLOB or MEDIUMBLO B or LONGBLOB or TINYTEXT or TEXT or MEDIUMTEXT or LONGTEXT or ENUM(value1,value2,value3,...) or SET(value1,v alue2,value3,...)index_col_name: col_name [(length)]reference_def inition: REFERENCES tbl_name [(index_col_name,...)] [MATCH FULL | MATCH PARTIAL] [ON DELETE reference_option] [ON UPDATE reference _option]reference_option: RESTRICT | CASCADE | SET NULL | NO ACTI ON | SET DEFAULTtable_options:TYPE = {ISAM | MYISAM | HEAP}orAUTO _INCREMENT = #orAVG_ROW_LENGTH = #orCHECKSUM = {0 | 1}orCOMMENT = "string"orMAX_ROWS = #orMIN_ROWS = #orPACK_KEYS = {0 | 1}orPASSW ORD = "string"orDELAY_KEY_WRITE = {0 | 1}or ROW_FORMAT= { de fault | dynamic | static | compressed }select_statement:[IGNORE | REPLACE] SELECT ... (Some legal select statement)CREATE TABLE在当 前数据库中用给出的名字创建一个数据库表。允许的表名的规则在7.1.5 数据库,桌子,索引,列和别名命名中给出。如果当前数据库不存在 或如果表已经存在,出现一个错误。 在MySQL3.22或以后版本中,表名可以被指定为db_name.tbl_name,不管有没有当 前的数据库都可以。 在MySQL3.23中,当你创建一张表时,你可以使用TEMPORARY关键词。如果一个连接死掉,临时表将自动被 删除,并且其名字是按连接命名。这意味着,2个不同的连接能使用相同的暂时表的名字而不会彼此冲突或与相同名字的现有数据库表冲突。(现有 的表被隐蔽直到临时表被删除)。 在MySQL3.23或以后版本中,你可以使用关键词IF NOT EXISTS以便如果表已经存在不发 生一个错误。注意,无法证实表结构是相同的。 每张表tbl_name由在数据库目录的一些文件表示。在MyISAM类型的表的情况下,你 将得到: 文件 目的 tbl_name.frm 表定义(表格)文件tbl_name.MYD 数据文件tbl_name.MYI 索引 文件对于各种列类型的性质的更多信息,见7.3 列类型。 如果既不指定NULL也不指定NOT NULL,列被视为指定了NULL。 整 型列可以有附加的属性AUTO_INCREMENT。当你插入NULL值(推荐)或0到一个AUTO_INCREMENT列中时,列被设置 为value+1,在此value是当前表中的列的最大值。AUTO_INCREMENT顺序从1开始。见20.4.29 mysql_i nsert_id()。如果你删除了包含一个AUTO_INCREMENT列的最大值的行,值将被重新使用。如果你删除表中所有的行,顺序 重新开始。注意:每个表只能有一个AUTO_INCREMENT列,并且它必须被索引。为了使做MySQL兼容一些 ODBC 应用程序, 用下列查询你可以找出最后插入的行: SELECT FROM tbl_name WHERE auto_col IS NULLNU LL值对于TIMESTAMP列的处理不同于其他列类型。你不能在一个TIMESTAMP列中存储一个文字NULL;设置列为NULL将把 它设成当前的日期和时间。因为TIMESTAMP列表现就这样,NULL和NOT NULL属性不以一般方式运用并且如果你指定它们,将被 忽略。在另一方面,为了使它MySQL客户更容易地使用TIMESTAMP列,服务器报告这样的列可以被赋值NULL( 它是对的),尽管 TIMESTAMP实际上绝不包含一个NULL值。当你使用DESCRIBE tbl_name得到有关你的表的描述时,你就会明白。注意 ,设置一个TIMESTAMP列为0不同于将它设置为NULL,因为0是一个有效的TIMESTAMP值。 如果没有为列指定DEFAUL T值,MySQL自动地分配一个。如果列可以取NULL作为值,缺省值是NULL。如果列被声明为NOT NULL,缺省值取决于列类型: 对于没有声明AUTO_INCREMENT属性的数字类型,缺省值是0。对于一个AUTO_INCREMENT列,缺省值是在顺序中的下 一个值。 对于除TIMESTAMP的日期和时间类型,缺省值是该类型适当的“零”值。对于表中第一个TIMESTAMP列,缺省值是当前 的日期和时间。见7.3.6 日期和时间类型。 对于除ENUM的字符串类型,缺省是空字符串。对于ENUM,缺省值是第一个枚举值。 K EY是INDEX的一个同义词。 在MySQL中,一个UNIQUE键只能有不同的值。如果你试图用匹配现有行的键来增加新行,发生一个错 误。 A PRIMARY KEY是一个唯一KEY,它有额外的限制,即所有的关键列必须被定义为NOT NULL。在MySQL中,键被 命名为PRIMARY。一张表只能有一个PRIMARY KEY。如果在表中你没有一个PRIMARY KEY并且一些应用程序要求PRI MARY KEY,MySQL将返回第一个UNIQUE键,它没有任何NULL列,作为PRIMARY KEY。 一个PRIMARY K EY可以是一个多列索引。然而,你不能在一个列说明中使用PRIMARY KEY的关键字属性创建一个多列索引。这样做将仅仅标记单个列作 为主键。你必须使用PRIMARY KEY(index_col_name, ...)语法。 如果你不能给索引赋予一个名字,这个索引将 赋予与第一个index_col_name相同的名字,用一个可选的suffix(_2, _3, ...)使它唯一。你能使用SHOW INDEX FROM tbl_name看到一张表的索引名字。见7.21 SHOW句法(得到表、列等的信息)。 只有MyISAM表类 型支持可以有NULL值的列上的索引。在其他情况下,你必须声明这样的列为NOT NULL,否则导致一个错。 用col_name(le ngth)语法,你可以指定仅使用部分的CHAR或VARCHAR列的一个索引。这能使索引文件变得更小。见7.3.9 列索引。 只有M yISAM表类型支持BLOB和TEXT列的索引。当在一个BLOB或TEXT列上放置索引时,你必须总是指定索引的长度: CREATE TABLE test (blob_col BLOB, index(blob_col(10)));当你与TEXT或BLOB列一起使 用ORDER BY或GROUP BY时,只使用头max_sort_length个字节。见7.3.7.2 BLOB和TEXT类型。 FOREIGN KEY、CHECK和REFERENCES子句实际上不做任何事情,其语法仅仅提供兼容性,使得它更容易从其他的SQL服 务器移植代码并运行借助引用创建表的应用。见5.4 MySQL缺少的功能。 每个NULL列占据额外一位,取舍到最接近的字节。 最大记 录长度以字节计可以如下计算: row length = 1 + (sum of column lengths) + (number of NULL columns + 7)/8 + (number of variable-length columns)tabl e_options和SELECT选项只在MySQL 3.23和以后版本中被实现。不同的表类型是: ISAM原来的表处理器MyISA M全新二进制可移植的表处理器HEAP用于该表的数据仅仅存储在内存中见9.4 MySQL 表类型。其他表选项被用来优化表的行为。在大 多数情况下,你不必指定他们任何一个。选项对所有表都适用,如果不是则说明。 AUTO_INCREMENT 你想要为你的表设定的下一个 auto_increment 值 ( MyISAM )AVG_ROW_LENGTH 你的表的平均行长度的近似值。你只需要为有变长 记录的表设置它。 CHECKSUM 如果你想要MySQL对每行维持一个校验和(使表变得更慢以更新但是使它更容易找出损坏的表)设置它 为1 ( MyISAM )COMMENT 对于你的表的一篇60个字符的注释MAX_ROWS 你计划在表中存储的行的最大数目MIN_ ROWS 你计划在表中存储的行的最小数目PACK_KEYS 如果你想要有更小的索引,将它设为1。这通常使的更新更慢并且读取更快(M yISAM,ISAM)。 PASSWORD 用一个口令加密.frm文件。该选项在标准MySQL版本中不做任何事情。 DELAY_K EY_WRITE 如果想要推迟关键表的更新直到表被关闭(MyISAM),将它设置为1。 ROW_FORMAT 定义行应该如何被存储 (为了将来)。 当你使用一个MyISAM表时,MySQL使用max_rows avg_row_length的乘积决定最终的表将 有多大。如果你不指定上面的任何选项,对一个表的最大尺寸将是4G(或2G,如果你的操作系统仅支持2G的表)。 如果你在CREATE语 句后指定一个SELECT,MySQL将为在SELECT中所有的单元创键新字段。例如: mysql> CREATE TABLE te st (a int not null auto_increment, primary key (a), key(b)) TYPE= HEAP SELECT b,c from test2;这将创建一个有3个列的HEAP表。注意如果在拷贝数据进表时发生任何错误,表将 自动被删除。 隐含的列说明改变在某些情况下,MySQL隐含地改变在一个CREATE TABLE语句给出的一个列说明。(这也可能在 ALTER TABLE。) 长度小于4的VARCHAR被改变为CHAR。 如果在一个表中的任何列有可变长度,结果是整个行是变长的。 因此, 如果一张表包含任何变长的列(VARCHAR、TEXT或BLOB),所有大于3个字符的CHAR列被改变为VARCHAR列。这 在任何方面都不影响你如何使用列;在MySQL中,VARCHAR只是存储字符的一个不同方法。MySQL实施这种改变,是因为它节省空间 并且使表操作更快捷。见10.6 选择一种表格类型。 TIMESTAMP的显示尺寸必须是偶数且在2 ~ 14的范围内。如果你指定0显 示尺寸或比14大,尺寸被强制为14。从1~13范围内的奇数值尺寸被强制为下一个更大的偶数。 你不能在一个TIMESTAMP列里面存 储一个文字NULL;将它设为NULL将设置为当前的日期和时间。因为TIMESTAMP列表现就是这样,NULL和NOT NULL属性 不以一般的方式运用并且如果你指定他们,将被忽略。DESCRIBE tbl_name总是报告该TIMESTAMP列可能赋予了NULL 值。 MySQL将其他SQL数据库供应商使用的某个列类型映射到MySQL类型。见7.3.11 只用其他数据库引擎的类型。 如果你想 要知道MySQL是否使用了除你指定的以外的一种列类型,在创建或改变你的表之后,发出一个DESCRIBE tbl_name语句即可。 如果你使用myisampack压缩一个表,可能会发生改变某些其他的列类型。见10.6.3 压缩表的特征。? ALTER TAB LE句法ALTER [IGNORE] TABLE tbl_name alter_spec [, alter_spec ...]al ter_specification: ADD [COLUMN] create_definition [FIRST | AFTER column_name ] or ADD INDEX [index_name] (index_col_name,...) o r ADD PRIMARY KEY (index_col_name,...) or ADD UNIQUE [index _name] (index_col_name,...) or ALTER [COLUMN] col_name {SET DE FAULT literal | DROP DEFAULT} or CHANGE [COLUMN] old_col_name create_definition or MODIFY [COLUMN] create_definition or D ROP [COLUMN] col_name or DROP PRIMARY KEY or DROP INDEX ind ex_name or RENAME [AS] new_tbl_name or table_optionsALTER T ABLE允许你修改一个现有表的结构。例如,你可以增加或删除列、创造或消去索引、改变现有列的类型、或重新命名列或表本身。你也能改变表 的注释和表的类型。见7.7 CREATE TABLE句法。 如果你使用ALTER TABLE修改一个列说明但是DESCRIBE t bl_name显示你的列并没有被修改,这可能是MySQL因为在7.7.1 隐含的列说明改变中描述的原因之一而忽略了你的修改。例如, 如果你试图将一个VARCHAR改为CHAR,MySQL将仍然使用VARCHAR,如果表包含其他变长的列。 ALTER TABLE通 过制作原来表的一个临时副本来工作。修改在副本上施行,然后原来的表被删除并且重新命名一个新的。这样做使得所有的修改自动地转向到新表, 没有任何失败的修改。当ALTER TABLE正在执行时,原来的桌可被其他客户读取。更新和写入表被延迟到新表准备好了为止。 为了使用 ALTER TABLE,你需要在表上的select、insert、delete、update、create和drop的权限。 IG NORE是MySQL对ANSI SQL92 的一个扩充,如果在新表中的唯一键上有重复,它控制ALTER TABLE如何工作。如果I GNORE没被指定,副本被放弃并且恢复原状。如果IGNORE被指定,那么对唯一键有重复的行,只有使用第一行;其余被删除。 你可以在 单个ALTER TABLE语句中发出多个ADD、ALTER、DROP和CHANGE子句。这是MySQL对ANSI SQL92的一个 扩充,SQL92在每个ALTER TABLE语句中只允许一个子句。 CHANGE col_name、DROP col_name和D ROP INDEX是MySQL对 ANSI SQL92 的扩充。 MODIFY是 Oracle 对ALTER TABLE的扩充。 可选的词COLUMN是一个纯粹的噪音且可以省略。 如果你使用ALTER TABLE tbl_name RENAME AS new_ name而没有任何其他选项,MySQL简单地重命名对应于表tbl_name的文件。没有必要创建临时表。 create_defini tion子句使用CREATE TABLE相同的ADD和CHANGE语法。注意语法包括列名字,不只列类型。见7.7 CREATE T ABLE句法。 你可以使用CHANGE old_col_name create_definition子句重命名一个列。为了这样做, 指定旧的和新的列名字和列当前有的类型。例如,重命名一个INTEGER列,从a到b,你可以这样做: mysql> ALTER TAB LE t1 CHANGE a b INTEGER;如果你想要改变列的类型而非名字,就算他们是一样的,CHANGE语法仍然需要2个列 名。例如: mysql> ALTER TABLE t1 CHANGE b b BIGINT NOT NULL;然而,在MySQL3 .22.16a,你也可以使用MODIFY来改变列的类型而不是重命名它: mysql> ALTER TABLE t1 MODIFY b BIGINT NOT NULL;如果你使用CHANGE或MODIFY缩短一个列,一个索引存在于该列的部分(例如,如果你有一个V ARCHAR列的头10个字符的索引),你不能使列短于被索引的字符数目。 当你使用CHANGE或MODIFY改变一个列类型时,MyS QL尽可能试图很好地变换数据到新类型。 在MySQL3.22或以后,你能使用FIRST或ADD ... AFTER col_nam e在一个表的行内在一个特定的位置增加列。缺省是增加到最后一列。 ALTER COLUMN为列指定新的缺省值或删除老的缺省值。如果老 的缺省值被删除且列可以是NULL,新缺省值是NULL。如果列不能是NULL,MySQL赋予一个缺省值。缺省值赋值在7.7 CREA TE TABLE句法中描述。 DROP INDEX删除一个索引。这是MySQL对 ANSI SQL92 的一个扩充。 如果列从一张 表中被丢弃,列也从他们是组成部分的任何索引中被删除。如果组成一个索引的所有列被丢弃,该索引也被丢弃。 DROP PRIMARY K EY丢弃主索引。如果这样的索引不存在,它丢弃表中第一个UNIQUE索引。(如果没有明确地指定PRIMARY KEY,MySQL标记 第一个UNIQUE键为PRIMARY KEY。) 用 C API 函数mysql_info(),你能找出多少记录被拷贝, 和(当使 用IGNORE时)由于唯一键值的重复多少记录被删除。 FOREIGN KEY、CHECK和REFERENCES子句实际上不做任何事 情,他们的句法仅仅提供兼容性,使得更容易地从其他SQL服务器移植代码并且运行借助引用来创建表的应用程序。见5.4 MySQL缺少的 功能。 这里是一个例子,显示了一些ALTER TABLE用法。我们以一个如下创建的表t1开始: mysql> CREATE TAB LE t1 (a INTEGER,b CHAR(10));重命名表,从t1到t2: mysql> ALTER TABLE t1 R ENAME t2;为了改变列a,从INTEGER改为TINYINT NOT NULL(名字一样),并且改变列b,从CHAR(10) 改为CHAR(20),同时重命名它,从b改为c: mysql> ALTER TABLE t2 MODIFY a TINYINT N OT NULL, CHANGE b c CHAR(20);增加一个新TIMESTAMP列,名为d: mysql> ALTER TA BLE t2 ADD d TIMESTAMP; 在列d上增加一个索引,并且使列a为主键: mysql> ALTER TABLE t 2 ADD INDEX (d), ADD PRIMARY KEY (a);删出列c: mysql> ALTER TABLE t2 DROP COLUMN c;增加一个新的AUTO_INCREMENT整数列,命名为c: mysql> ALTER TABLE t2 ADD c INT UNSIGNED NOT NULL AUTO_INCREMENT, ADD INDEX (c);注意,我们索 引了c,因为AUTO_INCREMENT柱必须被索引,并且另外我们声明c为NOT NULL,因为索引了的列不能是NULL。 当你增 加一个AUTO_INCREMENT列时,自动地用顺序数字填入列值。 OPTIMIZE TABLE句法OPTIMIZE TABLE tbl_name如果你删除了一个表的大部分或如果你用变长的行对一个表(有VARCHAR、BLOB或TEXT列的表)做了改变,应该 使用OPTIMZE TABLE。删除的记录以一个链接表维持并且随后的INSERT操作再次使用老记录的位置。你可以使用OPTIMIZ E TABLE回收闲置的空间。 OPTIMIZE TABLE通过制作原来的表的一个临时副本来工作。老的表子被拷贝到新表中(没有闲置 的行),然后原来的表被删除并且重命名一个新的。这样做使得所有更新自动转向新的表,没有任何失败的更新。当时OPTIMIZE TABL E正在执行时,原来的表可被另外的客户读取。对表的更新和写入延迟到新表是准备好为止。 DROP TABLE句法DROP TABLE [IF EXISTS] tbl_name [, tbl_name,...]DROP TABLE删除一个或多个数据库表。所有表中的 数据和表定义均被删除,故小心使用这个命令! 在MySQL 3.22或以后版本,你可以使用关键词IF EXISTS类避免不存在表的一 个错误发生。 DELETE句法DELETE [LOW_PRIORITY] FROM tbl_name [WHERE where_ definition] [LIMIT rows]DELETE从tbl_name表中删除满足由where_definition给出的 条件的行,并且返回删除记录的个数。 如果你发出一个没有WHERE子句的DELETE,所有行都被删除。MySQL通过创建一个空表来完 成,它比删除每行要快。在这种情况下,DELETE返回零作为受影响记录的数目。(MySQL不能返回实际上被删除的行数,因为进行再创建 而不是打开数据文件。只要表定义文件“tbl_name.frm”是有效的,表才能这样被再创建,即使数据或索引文件破坏了)。 如果你确 实想要知道在你正在删除所有行时究竟有对少记录被删除,并且愿意承受速度上的惩罚,你可以这种形式的一个ELETE语句: mysql> DELETE FROM tbl_name WHERE 1>0;注意这比没有WHERE子句的DELETE FROM tbl_name 慢的多了,因为它一次删除一行。 如果你指定关键词LOW_PRIORITY,DELETE的执行被推迟到没有其他客户读取表后。 删除的 记录以一个链接表维持并且随后的INSERT操作再次使用老的记录位置。为了回收闲置的空间并减小文件大小,使用OPTIMIZE TAB LE语句或myisamchk实用程序重新组织表。OPTIMIZE TABLE较容易,但是myisamchk更快。见7.9 OPTI MIZE TABLE句法和13.4.3 表优化。 MySQL对DELETE特定的LIMIT rows选项告诉服务器在控制被返回到客 户之前,将要删除的最大行数,这可以用来保证一个特定DELETE命令不会花太多的时间。你可以简单地重复DELETE命令直到受影响的行 数小于LIMIT值。 SELECT句法SELECT [STRAIGHT_JOIN] [SQL_SMALL_RESULT] [SQ L_BIG_RESULT] [HIGH_PRIORITY] [DISTINCT | DISTINCTROW | ALL] sele ct_expression,... [INTO {OUTFILE | DUMPFILE} ''file_name'' export_o ptions] [FROM table_references [WHERE where_definition] [GROUP BY col_name,...] [HAVING where_definition] [ORDER BY {unsigned_inte ger | col_name | formula} [ASC | DESC] ,...] [LIMIT [offset,] row s] [PROCEDURE procedure_name] ]SELECT被用来检索从一个或多个表中精选的行。select_exp ression指出你想要检索的列。SELECT也可以用来检索不引用任何表的计算行。例如: mysql> SELECT 1 + 1; -> 2所有使用的关键词必须精确地以上面的顺序给出。例如,一个HAVING子句必须跟在GROUP BY子句之后和ORDER BY 子句之前。 一个SELECT表达式可以用一个AS给定一个别名,别名被用作表达式的列名并且能使用在ORDER BY或HAVING子句 中。例如: mysql> select concat(last_name,'', '',first_name) AS full_nam e from mytable ORDER BY full_name;FROM table_references子句指出从哪个表中检 索行。如果你命名多个表,你正在执行一个联结(join)。对于联结的句法信息,见7.13 JOIN句法。 你可以引用一个列为col_ name、tbl_name.col_name或db_name.tbl_name.col_name,你不必在一个SELECT语句中指 定一个tbl_name或db_name.tbl_name是一个列引用的前缀,除非引用有二义性。见7.1.5 数据库、表、索引、列和 别名命名。对于二义性的例子要求更加显式的列引用格式。 一个表引用可以使用tbl_name [AS] alias_name起一个别名 。 mysql> select t1.name, t2.salary from employee AS t1, info AS t 2 where t1.name = t2.name;mysql> select t1.name, t2.salary from e mployee t1, info t2 where t1.name = t2.name;精选输出的列可以用列名、列别名或列位置在O RDER BY和GROUP BY子句引用,列位置从1开始。 mysql> select college, region, seed from tournament ORDER BY region, seed;mysql> select college, reg ion AS r, seed AS s from tournament ORDER BY r, s;mysql> select c ollege, region, seed from tournament ORDER BY 2, 3;为了以降序排列,把DESC( 下降 )关键词加到ORDER BY子句中你要排序的列名前。缺省是升序;这也可以用ASC关键词明确指定。 HAVING子句能引用任何 列或在select_expression中命名的别名,它最后运用,就在项目被送到客户之前,没有优化。不要对因该在WHERE子句中的 项目使用HAVING。例如,不能写成这样: mysql> select col_name from tbl_name HAVING col_name > 0;相反写成这样: mysql> select col_name from tbl_name WHERE col_name > 0;在MySQL 3.22.5或以后,你也能这样写查询: mysql> select user,max(sa lary) from users group by user HAVING max(salary)>10; 在里面更老的MySQL 版本中,你能这样写: mysql> select user,max(salary) AS sum from users group by user HAVING sum>10;SQL_SMALL_RESULT、SQL_BIG_RESULT、STRAIGHT_J OIN和HIGH_PRIORITY是MySQL对ANSI SQL92的扩展。 STRAIGHT_JOIN强制优化器以其列在FROM 子句的次序联结(join)桌子。如果优化器以非最佳次序联结表,你能使用它加速查询。见7.22 EXPLAIN句法(得到关于SELE CT的信息)。 SQL_SMALL_RESULT能与GROUP BY或DISTINCT一起使用告诉优化器结果集将很小。在这种情况下 ,MySQL将使用快速临时表存储最终的表而不是使用排序。 SQL_SMALL_RESULT是一个MySQL扩展。 SQL_BIG_ RESULT能与GROUP BY或DISTINCT一起使用以告诉优化器结果集合将有很多行。在这种情况下,如果需要,MySQL将直接 使用基于磁盘的临时表。 MySQL在这种情况下将选择用GROUP BY单元上的键值进行排序而不是做一个临时表。 HIGH_PRIO RITY将赋予SELECT比一个更新表的语句更高的优先级,你应该仅对非常快的并且必须一次完成的查询使用它。 如果表为读而锁定或甚至 有一个等待表释放的更新语句,一个SELECT HIGH_PRIORITY将运行。 LIMIT子句可以被用来限制SELECT语句返回 的行数。LIMIT取1个或2个数字参数,如果给定2个参数,第一个指定要返回的第一行的偏移量,第二个指定返回行的最大数目。初始行的偏 移量是0(不是1)。 mysql> select from table LIMIT 5,10; # Retrieve row s 6-15如果给定一个参数,它指出返回行的最大数目。 mysql> select from table LIMIT 5; # Retrieve first 5 rows换句话说,LIMIT n等价于LIMIT 0,n。 SELECT ... IN TO OUTFILE ''file_name''格式的SELECT语句将选择的行写入一个文件。文件在服务器主机上被创建,并且不能是已经 存在的(不管别的,这可阻止数据库表和文件例如“/etc/passwd”被破坏)。在服务器主机上你必须有file权限以使用这种SEL ECT。SELECT ... INTO OUTFILE是LOAD DATA INFILE逆操作;语句的export_options 部分的语法与用在LOAD DATA INFILE语句中的FIELDS和LINES子句的相同。见7.16 LOAD DATA INF ILE句法。在最终的文本文件中,只有下列字符由ESCAPED BY字符转义: ESCAPED BY字符 在FIELDS TERMI NATED BY中的第一个字符 在LINES TERMINATED BY中的第一个字符 另外,ASCII 0被变换到ESCAPED BY后跟0(ASCII 48)。上述的原因是你必须转义任何FIELDS TERMINATED BY、ESCAPED BY或LIN ES TERMINATED BY字符以便能可靠地能读回文件。ASCII 0被转义使它更容易用分页器观看。因为最终的文件不必须遵循S QL句法,没有别的东西需要转义。 如果你使用INTO DUMPFILE而不是INTO OUTFILE,MySQL将只写一行到文件中 ,没有任何列或行结束并且没有任何转义。如果你想要在一个文件存储一个blob,这是很有用的。 JOIN句法MySQL支持下列用于S ELECT语句的JOIN句法: table_reference, table_referencetable_reference [ CROSS] JOIN table_referencetable_reference INNER JOIN table_refer encetable_reference STRAIGHT_JOIN table_referencetable_reference LEFT [OUTER] JOIN table_reference ON conditional_exprtable_refere nce LEFT [OUTER] JOIN table_reference USING (column_list)table_re ference NATURAL LEFT [OUTER] JOIN table_reference{ oj table_refer ence LEFT OUTER JOIN table_reference ON conditional_expr }上述最后的LE FT OUTER JOIN的句法只是为了与ODBC兼容而存在的。 一个表可以是使用aliasedtbl_name AS alias _name或tbl_name alias_name的起的别名。 mysql> select t1.name, t2.salary from employee AS t1, info AS t2 where t1.name = t2.name;INNER JOI N和,(逗号)在语义上是等价的,都是进行一个在使用的表之间的全联结。通常,你指定表应该如何用WHERE条件联结起来。 ON条件是可 以用在一个WHERE子句形式的任何条件。 如果在一个LEFT JOIN中没有右表的匹配记录,一个所有列设置为NULL的行被用于右表 。你可以使用这个事实指出表中在另一个表中没有对应记录的记录: mysql> select table1. from table1 LEFT JOIN table2 ON table1.id=table2.id where table2.id is NULL; 这个例子找出在table1中所有的行,其id值在table2中不存在(即,所有table1中的在table2中没有对应行的行)。当 然这假定table2.id被声明为NOT NULL。USING (column_list)子句命名一系列必须存在于两个表中的列。 例如一个USING子句: A LEFT JOIN B USING (C1,C2,C3,...)被定义成在语义上等同一个这样的ON表 达式: A.C1=B.C1 AND A.C2=B.C2 AND A.C3=B.C3,...2个表的NATURAL LEFT JOI N被定义为在语义上等同于一个有USING子句命名在两表中存在的所有列的一个LEFT JOIN。 STRAIGHT_JOIN等同于J OIN,除了左表在右表之前被读入,这能用于这些情况,联结优化器将表的顺序放错了。 一些例子: mysql> select fr om table1,table2 where table1.id=table2.id;mysql> select from t able1 LEFT JOIN table2 ON table1.id=table2.id;mysql> select fro m table1 LEFT JOIN table2 USING (id);mysql> select from table1 LEFT JOIN table2 ON table1.id=table2.id LEFT JOIN table3 ON table 2.id=table3.id;见10.5.4 MySQL怎样优化LEFT JOIN。 INSERT句法 INSERT [LOW_ PRIORITY | DELAYED] [IGNORE] [INTO] tbl_name [(col_name,...)] VAL UES (expression,...),(...),...或 INSERT [LOW_PRIORITY | DELAYED] [IGNORE] [INTO] tbl_name [(col_name,...)] SELECT ...或 INSERT [LO W_PRIORITY | DELAYED] [IGNORE] [INTO] tbl_name SET col_name=expre ssion, col_name=expression, ...INSERT把新行插入到一个存在的表中,INSERT ... VAL UES形式的语句基于明确指定的值插入行,INSERT ... SELECT形式插入从其他表选择的行,有多个值表的INSERT .. . VALUES的形式在MySQL 3.22.5或以后版本中支持,col_name=expression语法在MySQL 3.22 .10或以后版本中支持。 tbl_name是行应该被插入其中的表。列名表或SET子句指出语句为那一列指定值。 如果你为INSERT ... VALUES或INSERT ... SELECT不指定列表,所有列的值必须在VALUES()表或由SELECT提供。如果 你不知道表中列的顺序,使用DESCRIBE tbl_name来找出。 任何没有明确地给出值的列被设置为它的缺省值。例如,如果你指定 一个列表并没命名表中所有列,未命名的列被设置为它们的缺省值。缺省值赋值在7.7 CREATE TABLE句法中描述。 一个expr ession可以引用在一个值表先前设置的任何列。例如,你能这样: mysql> INSERT INTO tbl_name (col 1,col2) VALUES(15,col12);但不能这样: mysql> INSERT INTO tbl_name (col 1,col2) VALUES(col22,15);如果你指定关键词LOW_PRIORITY,INSERT的执行被推迟到没有其他客 户正在读取表。在这种情况下,客户必须等到插入语句完成后,如果表频繁使用,它可能花很长时间。这与INSERT DELAYED让客马上 继续正好相反。 如果你在一个有许多值行的INSERT中指定关键词IGNORE,表中任何复制一个现有PRIMARY或UNIQUE键的 行被忽略并且不被插入。如果你不指定IGNORE,插入如果有任何复制现有关键值的行被放弃。你可用C API函数mysql_info( )检查多少行被插入到表中。 如果MySQL用DONT_USE_DEFAULT_FIELDS选项配置,INSERT语句产生一个错误, 除非你明确对需要一个非NULL值的所有列指定值。见4.7.3 典型configure选项。 INSERT INTO ... SEL ECT语句满足下列条件: 查询不能包含一个ORDER BY子句。 INSERT语句的目的表不能出现在SELECT查询部分的FROM 子句,因为这在ANSI SQL中被禁止让从你正在插入的表中SELECT。(问题是SELECT将可能发现在同一个运行期间内先前被插入 的记录。当使用子选择子句时,情况能很容易混淆) AUTO_INCREMENT列象往常一样工作。 如果你使用INSERT ... S ELECT或INSERT ... VALUES语句有多个值列表,你可以使用C API函数mysql_info()得到查询的信息。信 息字符串的格式如下: Records: 100 Duplicates: 0 Warnings: 0 Duplicates指出不能被 插入的行的数量,因为他们与现有的唯一的索引值重复。Warnings指出在出现某些问题时尝试插入列值的次数。在下列任何条件下都可能发 生错误: 插入NULL到被声明了NOT NULL的列,列被设置为它的缺省值。 将超出列范围的值设置给一个数字列,值被剪切为范围内适 当的端点值。 将数字列设成例如''10.34 a''的值,拖尾的垃圾被剥去并仍然是数字部分被插入。如果值根本不是一个数字,列被设置到0 。 把一个字符串插入到超过列的最大长度的一个CHAR、VARCHAR、TEXT或BLOB列中。值被截断为列的最大长度。 把一个对列 类型不合法的值插入到一个日期或时间列。列被设置为该列类型适当的“零”值。 对于INSERT语句的DELAYED选项是MySQL专属 的选项-如果你客户有不能等到INSERT完成,它是很有用的。当你为日记登录使用MySQL时,而且你也周期性地运行花很长时间完成的S ELECT语句,这是一个常见的问题。DELAYED在面MySQL 3.22.15中被引入,它是MySQL对 ANSI SQL92 的一个扩展。 当你使用INSERT DELAYED时,客户将马上准备好,并且当表不被任何其他的线程使用时,行将被插入。另一个使用I NSERT DELAYED的主要好处是从很多客户插入被捆绑在一起并且写进一个块。这比做很多单独的插入要来的快。 注意,当前排队的行 只是存储在内存中,直到他们被插入到表中。这意味着,如果你硬要杀死mysqld(kill -9)或如果mysqld出人意料地死掉,没 被写进磁盘的任何排队的行被丢失! 下列详细描述当你为INSERT或REPLACE使用DELAYED选项时,发生什么。在这个描述中, “线程”是收到一个INSERT DELAYED命令的线程并且“处理器”是处理所有对于一个特定表的INSERT DELAYED语句。 当一个线程对一个表执行一个DELAYED语句时,如果不存在这样的处理程序,一个处理器线程被创建以处理对于该表的所有DELAYED 语句。 线程检查处理程序是否已经获得了一个DELAYED锁;如果没有,它告诉处理程序去获得。即使其他的线程有在表上的一个READ或 WRITE锁,也能获得DELAYED锁。然而,处理程序将等待所有ALTER TABLE锁或FLUSH TABLES以保证表结构是最 新的。 线程执行INSERT语句,但不是将行写入表,它把最后一行的副本放进被处理器线程管理的一个队列。任何语法错误都能被线程发觉并 报告给客户程序。 顾客不能报告结果行的重复次数或AUTO_INCREMENT值;它不能从服务器获得它们,因为INSERT在插入操作 完成前返回。如果你使用C API,同样原因,mysql_info()函数不返回任何有意义的东西。 当行被插入到表中时,更新日志有处 理器线程更新。在多行插入的情况下,当第一行被插入时,更新日志被更新。 在每写入delayed_insert_limit行后,处理器 检查是否任何SELECT语句仍然是未完成,如果这样,在继续之前允许执行这些语句。 当处理器在它的队列中没有更多行时,表被解锁。如果 在delayed_insert_timeout秒内没有收到新的INSERT DELAYED命令,处理器终止。 如果已经有多于del ayed_queue_size行在一个特定的处理器队列中未解决,线程等待直到队列有空间。这有助于保证mysqld服务器对延迟的内存 队列不使用所有内存。 处理器线程将在Command列的MySQL进程表中显示delayed_insert。如果你执行一个FLUSH TABLES命令或以KILL thread_id杀死它,它将被杀死,然而,它在退出前首先将所有排队的行存进表中。在这期间,这次它 将不从其他线程接受任何新的INSERT命令。如果你在它之后执行一个INSERT DELAYED,将创建一个新的处理器线程。 注意, 上述意味着,如果有一个INSERT DELAYED处理器已经运行,INSERT DELAYED命令有比正常INSERT更高的优先级 !其他更新命令将必须等到INSERT DELAY排队变空、杀死处理器线程(用KILL thread_id)或执行FLUSH TAB LES。 下列状态变量提供了关于INSERT DELAYED命令的信息: Delayed_insert_threads 处理器线程 数量Delayed_writes 用INSERT DELAYED被写入的行的数量Not_flushed_delayed_rows 等待被写入的行数字你能通过发出一个SHOW STATUS语句或通过执行一个mysqladmin extended-status命令 察看这些变量。 注意如果桌子不在使用,INSERT DELAYED比一个正常的INSERT慢。对服务器也有额外开销来处理你对它使用 INSERT DELAYED的每个表的一个单独线程。这意味着,你应该只在你确实肯定需要它的时候才使用INSERT DELAYED! REPLACE句法 REPLACE [LOW_PRIORITY | DELAYED] [INTO] tbl_name [(co l_name,...)] VALUES (expression,...)或 REPLACE [LOW_PRIORITY | DE LAYED] [INTO] tbl_name [(col_name,...)] SELECT ...或 REPLACE [LOW _PRIORITY | DELAYED] [INTO] tbl_name SET col_name=expression, col _name=expression,... REPLACE功能与INSERT完全一样,除了如果在表中的一个老记录具有在一个唯一索引上 的新记录有相同的值,在新记录被插入之前,老记录被删除。见7.14 INSERT句法。 LOAD DATA INFILE句法LOA D DATA [LOW_PRIORITY] [LOCAL] INFILE ''file_name.txt'' [REPLACE | I GNORE] INTO TABLE tbl_name [FIELDS [TERMINATED BY ''\t''] [OPTIONAL LY] ENCLOSED BY ''''] [ESCAPED BY ''\\'' ]] [LINES TERMINATED BY ''\n'' ] [IGNORE number LINES] [(col_name,...)]LOAD DATA INFILE语句从一个文本文件 中以很高的速度读入一个表中。如果指定LOCAL关键词,从客户主机读文件。如果LOCAL没指定,文件必须位于服务器上。(LOCAL在 MySQL3.22.6或以后版本中可用。)为了安全原因,当读取位于服务器上的文本文件时,文件必须处于数据库目录或可被所有人读取。另 外,为了对服务器上文件使用LOAD DATA INFILE,在服务器主机上你必须有file的权限。见6.5 由MySQL提供的权限 。 如果你指定关键词LOW_PRIORITY,LOAD DATA语句的执行被推迟到没有其他客户读取表后。 使用LOCAL将比让服务 器直接存取文件慢些,因为文件的内容必须从客户主机传送到服务器主机。在另一方面,你不需要file权限装载本地文件。 你也可以使用my sqlimport实用程序装载数据文件;它由发送一个LOAD DATA INFILE命令到服务器来运作。 --local选项使得m ysqlimport从客户主机上读取数据。如果客户和服务器支持压缩协议,你能指定--compress在较慢的网络上获得更好的性能。 当在服务器主机上寻找文件时,服务器使用下列规则: 如果给出一个绝对路径名,服务器使用该路径名。 如果给出一个有一个或多个前置部件 的相对路径名,服务器相对服务器的数据目录搜索文件。 如果给出一个没有前置部件的一个文件名,服务器在当前数据库的数据库目录寻找文件。 注意这些规则意味着一个像“./myfile.txt”给出的文件是从服务器的数据目录读取,而作为“myfile.txt”给出的一个 文件是从当前数据库的数据库目录下读取。也要注意,对于下列哪些语句,对db1文件从数据库目录读取,而不是db2: mysql> US E db1;mysql> LOAD DATA INFILE "./data.txt" INTO TABLE db2.my_tabl e; REPLACE和IGNORE关键词控制对现有的唯一键记录的重复的处理。如果你指定REPLACE,新行将代替有相同的唯一键值的 现有行。如果你指定IGNORE,跳过有唯一键的现有行的重复行的输入。如果你不指定任何一个选项,当找到重复键键时,出现一个错误,并且 文本文件的余下部分被忽略时。 如果你使用LOCAL关键词从一个本地文件装载数据,服务器没有办法在操作的当中停止文件的传输,因此缺省 的行为好像IGNORE被指定一样。 LOAD DATA INFILE是SELECT ... INTO OUTFILE的逆操作,见7 .12 SELECT句法。为了将一个数据库的数据写入一个文件,使用SELECT ... INTO OUTFILE,为了将文件读回数 据库,使用LOAD DATA INFILE。两个命令的FIELDS和LINES子句的语法是相同的。两个子句是可选的,但是如果指定两 个,FIELDS必须在LINES之前。 如果你指定一个FIELDS子句,它的每一个子句(TERMINATED BY, [OPTIO NALLY] ENCLOSED BY和ESCAPED BY)也是可选的,除了你必须至少指定他们之一。 如果你不指定一个FIELDS 子句,缺省值与如果你这样写的相同: FIELDS TERMINATED BY ''\t'' ENCLOSED BY '''' ESCAPE D BY ''\\''如果你不指定一个LINES子句,缺省值与如果你这样写的相同: LINES TERMINATED BY ''\n'' 换句话说,缺省值导致读取输入时,LOAD DATA INFILE表现如下: 在换行符处寻找行边界 在定位符处将行分进字段 不要期望 字段由任何引号字符封装 将由“\”开头的定位符、换行符或“\”解释是字段值的部分字面字符 相反,缺省值导致在写入输出时,SELEC T ... INTO OUTFILE表现如下: 在字段之间写定位符 不用任何引号字符封装字段 使用“\”转义出现在字段中的定位符、 换行符或“\”字符 在行尾处写换行符 注意,为了写入FIELDS ESCAPED BY ''\\'',对作为一条单个的反斜线被读取的值 ,你必须指定2条反斜线值。 IGNORE number LINES选项可被用来忽略在文件开始的一个列名字的头: mysql> LO AD DATA INFILE "/tmp/file_name" into table test IGNORE 1 LINES;当你 与LOAD DATA INFILE一起使用SELECT ... INTO OUTFILE将一个数据库的数据写进一个文件并且随后马上 将文件读回数据库时,两个命令的字段和处理选项必须匹配,否则,LOAD DATA INFILE将不能正确解释文件的内容。假定你使用S ELECT ... INTO OUTFILE将由逗号分隔的字段写入一个文件: mysql> SELECT FROM table 1 INTO OUTFILE ''data.txt'' FIELDS TERMINATED BY '','' FROM ...为了将由逗号 分隔的文件读回来,正确的语句将是: mysql> LOAD DATA INFILE ''data.txt'' INTO TABLE t able2 FIELDS TERMINATED BY '','';相反,如果你试图用下面显示的语句读取文件,它不会工作,因为它命令LO AD DATA INFILE在字段之间寻找定位符: mysql> LOAD DATA INFILE ''data.txt'' INTO TABLE table2 FIELDS TERMINATED BY ''\t'';可能的结果是每个输入行将被解释为单个的字段。LOA D DATA INFILE能被用来读取从外部来源获得的文件。例如,以dBASE格式的文件将有由逗号分隔并用双引号包围的字段。如果文 件中的行由换行符终止,下面显示的命令说明你将用来装载文件的字段和行处理选项: mysql> LOAD DATA INFILE ''d ata.txt'' INTO TABLE tbl_name FIELDS TERMINATED BY '','' ENCLOSED BY ''"'' LINES TERMINATED BY ''\n'';任何字段或行处理选项可以指定一个空字符串('''')。如果不是空,FIEL DS [OPTIONALLY] ENCLOSED BY和FIELDS ESCAPED BY值必须是一个单个字符。FIELDS TE RMINATED BY和LINES TERMINATED BY值可以是超过一个字符。例如,写入由回车换行符对(CR+LF)终止的行 ,或读取包含这样行的一个文件,指定一个LINES TERMINATED BY ''\r\n''子句。 FIELDS [OPTIONAL LY] ENCLOSED BY控制字段的包围字符。对于输出(SELECT ... INTO OUTFILE),如果你省略OPTIO NALLY,所有的字段由ENCLOSED BY字符包围。对于这样的输出的一个例子(使用一个逗号作为字段分隔符)显示在下面: "1" ,"a string","100.20""2","a string containing a , comma","102.20"" 3","a string containing a \" quote","102.20""4","a string contain ing a \", quote and comma","102.20"如果你指定OPTIONALLY,ENCLOSED BY字符仅 被用于包围CHAR和VARCHAR字段: 1,"a string",100.202,"a string containing a , comma",102.203,"a string containing a \" quote",102.204,"a stri ng containing a \", quote and comma",102.20注意,一个字段值中的ENCLOSED BY字 符的出现通过用ESCAPED BY字符作为其前缀来转义。也要注意,如果你指定一个空ESCAPED BY值,可能产生不能被LOAD DATA INFILE正确读出的输出。例如,如果转义字符为空,上面显示的输出显示如下。注意到在第四行的第二个字段包含跟随引号的一个 逗号,它(错误地)好象要终止字段: 1,"a string",100.202,"a string containing a , c omma",102.203,"a string containing a " quote",102.204,"a string c ontaining a ", quote and comma",102.20对于输入,ENCLOSED BY字符如果存在,它从字段 值的尾部被剥去。(不管是否指定OPTIONALLY都是这样;OPTIONALLY对于输入解释不起作用)由ENCLOSED BY字符 领先的ESCAPED BY字符出现被解释为当前字段值的一部分。另外,出现在字段中重复的ENCLOSED BY被解释为单个ENCLO SED BY字符,如果字段本身以该字符开始。例如,如果ENCLOSED BY ''"''被指定,引号如下处理: "The ""BIG" " boss" -> The "BIG" bossThe "BIG" boss -> The "BIG" bossThe ""BIG"" boss -> The ""BIG"" bossFIELDS ESCAPED BY控制如何写入或读出特殊字 符。如果FIELDS ESCAPED BY字符不是空的,它被用于前缀在输出上的下列字符: FIELDS ESCAPED BY字符 FIELDS [OPTIONALLY] ENCLOSED BY字符 FIELDS TERMINATED BY和LINES TERM INATED BY值的第一个字符 ASCII 0(实际上将后续转义字符写成 ASCII''0'',而不是一个零值字节) 如果FIELD S ESCAPED BY字符是空的,没有字符被转义。指定一个空转义字符可能不是一个好主意,特别是如果在你数据中的字段值包含刚才给出 的表中的任何字符。 对于输入,如果FIELDS ESCAPED BY字符不是空的,该字符的出现被剥去并且后续字符在字面上作为字段值 的一个部分。例外是一个转义的“0”或“N”(即,\0或\N,如果转义字符是“\”)。这些序列被解释为ASCII 0(一个零值字节) 和NULL。见下面关于NULL处理的规则。 对于更多关于“\”- 转义句法的信息,见7.1 文字:怎样写字符串和数字。 在某些情况 下,字段和行处理选项相互作用: 如果LINES TERMINATED BY是一个空字符串并且FIELDS TERMINATED B Y是非空的,行也用FIELDS TERMINATED BY终止。 如果FIELDS TERMINATED BY和FIELDS EN CLOSED BY值都是空的(''''),一个固定行(非限定的)格式被使用。用固定行格式,在字段之间不使用分隔符。相反,列值只用列的“ 显示”宽度被写入和读出。例如,如果列被声明为INT(7),列的值使用7个字符的字段被写入。对于输入,列值通过读取7个字符获得。固定 行格式也影响NULL值的处理;见下面。注意如果你正在使用一个多字节字符集,固定长度格式将不工作。 NULL值的处理有多种,取决于你 使用的FIELDS和LINES选项: 对于缺省FIELDS和LINES值,对输出,NULL被写成\N,对输入,\N被作为NULL读 入(假定ESCAPED BY字符是“\”)。 如果FIELDS ENCLOSED BY不是空的,包含以文字词的NULL作为它的值的 字段作为一个NULL值被读入(这不同于包围在FIELDS ENCLOSED BY字符中的字NULL,它作为字符串''NULL''读入) 。 如果FIELDS ESCAPED BY是空的,NULL作为字NULL被写入。 用固定行格式(它发生在FIELDS TERMIN ATED BY和FIELDS ENCLOSED BY都是空的时候),NULL作为一个空字符串被写入。注意,在写入文件时,这导致NU LL和空字符串在表中不能区分,因为他们都作为空字符串被写入。如果在读回文件时需要能区分这两者,你应该不使用固定行格式。 一些不被L OAD DATA INFILE支持的情况: 固定长度的行(FIELDS TERMINATED BY和FIELDS ENCLOSED BY都为空)和BLOB或TEXT列。 如果你指定一个分隔符与另一个相同,或是另一个的前缀,LOAD DATA INFILE不能正 确地解释输入。例如,下列FIELDS子句将导致问题: FIELDS TERMINATED BY ''"'' ENCLOSED BY '' "''如果FIELDS ESCAPED BY是空的,一个包含跟随FIELDS TERMINATED BY值之后的FIELDS ENC LOSED BY或LINES TERMINATED BY的字段值将使得LOAD DATA INFILE过早地终止读取一个字段或行。 这是因为LOAD DATA INFILE不能正确地决定字段或行值在哪儿结束。 下列例子装载所有persondata表的行: mys ql> LOAD DATA INFILE ''persondata.txt'' INTO TABLE persondata;没有指定字 段表,所以LOAD DATA INFILE期望输入行对每个表列包含一个字段。使用缺省FIELDS和LINES值。 如果你希望仅仅装 载一张表的某些列,指定一个字段表: mysql> LOAD DATA INFILE ''persondata.txt'' INTO T ABLE persondata (col1,col2,...);如果在输入文件中的字段顺序不同于表中列的顺序,你也必须指定一个字段 表。否则,MySQL不能知道如何匹配输入字段和表中的列。 如果一个行有很少的字段,对于不存在输入字段的列被设置为缺省值。缺省值赋值 在7.7 CREATE TABLE句法中描述。 如果字段值缺省,空字段值有不同的解释: 对于字符串类型,列被设置为空字符串。 对于 数字类型,列被设置为0。 对于日期和时间类型,列被设置为该类型的适当“零”值。见7.3.6 日期和时间类型。 如果列有一个NULL ,或(只对第一个TIMESTAMP列)在指定一个字段表时,如果TIMESTAMP列从字段表省掉,TIMESTAMP列只被设置为当前 的日期和时间。 如果输入行有太多的字段,多余的字段被忽略并且警告数字加1。 LOAD DATA INFILE认为所有的输入是字符串 ,因此你不能像你能用INSERT语句的ENUM或SET列的方式使用数字值。所有的ENUM和SET值必须作为字符串被指定! 如果你正 在使用C API,当LOAD DATA INFILE查询完成时,你可通过调用API函数mysql_info()得到有关查询的信息。 信息字符串的格式显示在下面: Records: 1 Deleted: 0 Skipped: 0 Warnings: 0当值通过IN SERT语句插入时,在某些情况下出现警告(见7.14 INSERT句法),除了在输入行中有太少或太多的字段时,LOAD DATA INFILE也产生警告。警告没被存储在任何地方;警告数字仅能用于表明一切是否顺利。如果你得到警告并且想要确切知道你为什么得到他们, 一个方法是使用SELECT ... INTO OUTFILE到另外一个文件并且把它与你的原版输入文件比较。 对于有关INSERT相 对LOAD DATA INFILE的效率和加快LOAD DATA INFILE的更多信息,见10.5.6 加速INSERT查询。 UPDATE句法UPDATE [LOW_PRIORITY] tbl_name SET col_name1=expr1,col_n ame2=expr2,... [WHERE where_definition] [LIMIT #]UPDATE用新值更新现存表中行 的列,SET子句指出哪个列要修改和他们应该被给定的值,WHERE子句,如果给出,指定哪个行应该被更新,否则所有行被更新。 如果你指 定关键词LOW_PRIORITY,执行UPDATE被推迟到没有其他客户正在读取表时。 如果你从一个表达式的tbl_name存取列, UPDATE使用列的当前值。例如,下列语句设置age为它的当前值加1: mysql> UPDATE persondata SET age=age+1;UPDATE赋值是从左到右计算。例如,下列语句两倍age列,然后加1: mysql> UPDATE perso ndata SET age=age2, age=age+1;如果你设置列为其它当前有的值,MySQL注意到这点并且不更新它。 U PDATE返回实际上被改变的行的数量。在MySQL 3.22或以后版本中,C API函数mysql_info()返回被匹配并且更新 的行数和在UPDATE期间发生警告的数量。 在MySQL3.23中,你可使用LIMIT #来保证只有一个给定数量的行被改变。 U SE句法USE db_name USE db_name语句告诉MySQL使用db_name数据库作为随后的查询的缺省数据库。数据库 保持到会话结束,或发出另外一个USE语句: mysql> USE db1;mysql> SELECT count() FROM mytable; # selects from db1.mytablemysql> USE db2;mysql> SEL ECT count() FROM mytable; # selects from db2.mytable利用USE语句 使得一个特定的数据库称为当前数据库并不阻止你访问在另外的数据库中的表。下面的例子访问db1数据库中的author表和db2数据库中 的editor表: mysql> USE db1;mysql> SELECT author_name,editor_name FR OM author,db2.editor WHERE author.editor_id = db2.editor.editor_i d;USE语句提供了Sybase的兼容性。 FLUSH句法(清除缓存)FLUSH flush_option [,flush_op tion]如果你想要清除一些MySQL使用内部缓存,你应该使用FLUSH命令。为了执行FLUSH,你必须有reload权限。 fl ush_option可以是下列任何东西: HOSTS 清空主机缓存表。如果你的某些主机改变IP数字,或如果你得到错误消息Host ... is blocked,你应该清空主机表。当在连接MySQL服务器时,对一台给定的主机有多于max_connect_erro rs个错误连续不断地发生,MySQL认定某些东西错了并且阻止主机进一步的连接请求。清空主机表允许主机再尝试连接。见18.2.3 H ost ''...'' is blocked错误)。你可用-O max_connection_errors=999999999启动my sqld来避免这条错误消息。 LOGS 关闭并且再打开标准和更新记录文件。如果你指定了一个没有扩展名的更新记录文件,新的更新记录文 件的扩展数字将相对先前的文件加1。 PRIVILEGES 从mysql数据库授权表中重新装载权限。 TABLES 关闭所有打开的表 。 STATUS 重置大多数状态变量到0。 你也可以用mysqladmin实用程序,使用flush-hosts, flush-lo gs, reload或flush-tables命令来访问上述的每一个命令。 KILL句法KILL thread_id 每个对my sqld的连接以一个单独的线程运行。你可以用看SHOW PROCESSLIST命令察看哪个线程正在运行,并且用KILL threa d_id命令杀死一个线程。 如果你有process权限,你能看到并且杀死所有线程。否则,你只能看到并且杀死你自己的线程。 你也可以 使用mysqladmin processlist和mysqladmin kill命令检查并杀死线程。 SHOW句法 (得到表,列 等的信息) SHOW DATABASES [LIKE wild]or SHOW TABLES [FROM db_name] [LI KE wild]or SHOW COLUMNS FROM tbl_name [FROM db_name] [LIKE wild]o r SHOW INDEX FROM tbl_name [FROM db_name]or SHOW STATUSor SHOW VA RIABLES [LIKE wild]or SHOW [FULL] PROCESSLISTor SHOW TABLE STATUS [FROM db_name] [LIKE wild]or SHOW GRANTS FOR userSHOW提供关于数据库、桌子、 列或服务器的信息。如果使用LIKE wild部分,wild字符串可以是一个使用SQL的“%”和“_”通配符的字符串。 你能使用db _name.tbl_name作为tbl_name FROM db_name句法的另一种选择。这两个语句是相等的: mysql> S HOW INDEX FROM mytable FROM mydb;mysql> SHOW INDEX FROM mydb.myta ble;SHOW DATABASES列出在MySQL服务器主机上的数据库。你也可以用mysqlshow命令得到这张表。 SHOW TABLES列出在一个给定的数据库中的表。你也可以用mysqlshow db_name命令得到这张表。 注意:如果一个用户没有一个 表的任何权限,表将不在SHOW TABLES或mysqlshow db_name中的输出中显示。 SHOW COLUMNS列出在一 个给定表中的列。如果列类型不同于你期望的是基于CREATE TABLE语句的那样,注意,MySQL有时改变列类型。见7.7.1 隐 含的列说明变化。 DESCRIBE语句提供了类似SHOW COLUMNS的信息。见7.23 DESCRIBE 句法 (得到列的信息 )。 SHOW TABLE STATUS(在版本3.23引入)运行类似SHOW STATUS,但是提供每个表的更多信息。你也可以使 用mysqlshow --status db_name命令得到这张表。下面的列被返回: 列 含义 Name 表名Type 表的类型 (ISAM,MyISAM或HEAP)Row_format 行存储格式 (固定, 动态, 或压缩)Rows 行数量Avg_row_ length 平均行长度Data_length 数据文件的长度Max_data_length 数据文件的最大长度Index_len gth 索引文件的长度Data_free 已分配但未使用了字节数Auto_increment 下一个 autoincrement( 自动加1)值Create_time 表被创造的时间Update_time 数据文件最后更新的时间Check_time 最后对表运行 一个检查的时间Create_options 与CREATE TABLE一起使用的额外选项 Comment 当创造表时,使用的注释 (或为什么MySQL不能存取表信息的一些信息)。 SHOW FIELDS是SHOW COLUMNS一个同义词,SHOW KEYS是 SHOW INDEX一个同义词。你也可以用mysqlshow db_name tbl_name或mysqlshow -k db_n ame tbl_name 列出一张表的列或索引。SHOW INDEX以非常相似于ODBC的SQLStatistics调用的格式返回 索引信息。下面的列被返回: 列 含义 Table 表名Non_unique 0,如果索引不能包含重复。 Key_name 索引名S eq_in_index 索引中的列顺序号, 从 1 开始。 Column_name 列名。 Collation 列怎样在索引中被排 序。在MySQL中,这可以有值A(升序) 或NULL(不排序)。 Cardinality 索引中唯一值的数量。这可通过运行isam chk -a更改. Sub_part 如果列只是部分被索引,索引字符的数量。NULL,如果整个键被索引。 SHOW STATUS提 供服务器的状态信息(象mysqladmin extended-status一样)。输出类似于下面的显示,尽管格式和数字可以有点不同 : +--------------------------+--------+| Variable_name | Value |+--------------------------+--------+| Aborted_clients | 0 || Aborted_connects | 0 || Connec tions | 17 || Created_tmp_tables | 0 || Delayed_insert_threads | 0 || Delayed_writes | 0 || Delayed_errors | 0 || Flush_commands | 2 || Handler_delete | 2 || Handler _read_first | 0 || Handler_read_key | 1 | | Handler_read_next | 0 || Handler_read_rnd | 35 || Handler_update | 0 || Handler_write | 2 || Key_blocks_used | 0 || Key_read _requests | 0 || Key_reads | 0 || Key_write_requests | 0 || Key_writes | 0 || Max_used_connections | 1 || Not_flushed_key_bl ocks | 0 || Not_flushed_delayed_rows | 0 || Open_tabl es | 1 || Open_files | 2 || Open_streams | 0 || Opened_tables | 1 1 || Questions | 14 || Slow_queries | 0 || Threads_connected | 1 || Threads_ru nning | 1 || Uptime | 149111 |+-- ------------------------+--------+上面列出的状态变量有下列含义: Aborted_clients 由于客户没有正确关闭连接已经死掉,已经放弃的连接数量。 Aborted_connects 尝试已经失败的MySQL服务器的连接的 次数。 Connections 试图连接MySQL服务器的次数。 Created_tmp_tables 当执行语句时,已经被创造了 的隐含临时表的数量。 Delayed_insert_threads 正在使用的延迟插入处理器线程的数量。 Delayed_writ es 用INSERT DELAYED写入的行数。 Delayed_errors 用INSERT DELAYED写入的发生某些错误( 可能重复键值)的行数。 Flush_commands 执行FLUSH命令的次数。 Handler_delete 请求从一张表中删除 行的次数。 Handler_read_first 请求读入表中第一行的次数。 Handler_read_key 请求数字基于键读行 。 Handler_read_next 请求读入基于一个键的一行的次数。 Handler_read_rnd 请求读入基于一个固定位 置的一行的次数。 Handler_update 请求更新表中一行的次数。 Handler_write 请求向表中插入一行的次数。 Key_blocks_used 用于关键字缓存的块的数量。 Key_read_requests 请求从缓存读入一个键值的次数。 K ey_reads 从磁盘物理读入一个键值的次数。 Key_write_requests 请求将一个关键字块写入缓存次数。 Key_ writes 将一个键值块物理写入磁盘的次数。 Max_used_connections 同时使用的连接的最大数目。 Not_fl ushed_key_blocks 在键缓存中已经改变但是还没被清空到磁盘上的键块。 Not_flushed_delayed_row s 在INSERT DELAY队列中等待写入的行的数量。 Open_tables 打开表的数量。 Open_files 打开文件的 数量。 Open_streams 打开流的数量(主要用于日志记载)Opened_tables 已经打开的表的数量。 Questio ns 发往服务器的查询的数量。 Slow_queries 要花超过long_query_time时间的查询数量。 Threads_ connected 当前打开的连接的数量。 Threads_running 不在睡眠的线程数量。 Uptime 服务器工作了多少秒 。 关于上面的一些注释: 如果Opened_tables太大,那么你的table_cache变量可能太小。 如果key_reads 太大,那么你的key_cache可能太小。缓存命中率可以用key_reads/key_read_requests计算。 如果Han dler_read_rnd太大,那么你很可能有大量的查询需要MySQL扫描整个表或你有没正确使用键值的联结(join)。 SHOW VARIABLES显示出一些MySQL系统变量的值,你也能使用mysqladmin variables命令得到这个信息。如果缺省 值不合适,你能在mysqld启动时使用命令行选项来设置这些变量的大多数。输出类似于下面的显示,尽管格式和数字可以有点不同: +-- ----------------------+--------------------------+| Variable_name | Value |+------------------------+- -------------------------+| back_log | 5 || connect_timeout | 5 || basedir | /my/monty/ || datadir | /my/monty/data/ || delayed_insert_limit | 100 || delayed_insert_timeout | 300 || delayed_queue_size | 1000 || join_buffer_size | 131072 || flu sh_time | 0 || interactive_tim eout | 28800 || key_buffer_size | 10 48540 || language | /my/monty/shar e/english/ || log | OFF | | log_update | OFF || long_query _time | 10 || low_priority_updates | OFF || max_allowed_packet | 1048576 || max_connections | 100 || max_connect_errors | 10 || max_d elayed_threads | 20 || max_heap_table_si ze | 16777216 || max_join_size | 4294 967295 || max_sort_length | 1024 || max_tmp_tables | 32 || net_buffer_length | 16384 || port | 3306 || protocol-version | 10 || record_buffer | 131072 || skip_locking | ON || socket | /tmp/mysql.sock || sort_bu ffer | 2097116 || table_cache | 64 || thread_stack | 131072 || tmp_table_size | 1048576 || tmpdir | /machine/tmp/ || ve rsion | 3.23.0-alpha-debug || wait_timeout | 28800 |+------------------------+-- ------------------------+见10.2.3 调节服务器参数。 SHOW PROCESSLIST显示哪个线程正 在运行,你也能使用mysqladmin processlist命令得到这个信息。如果你有process权限, 你能看见所有的线程, 否则,你仅能看见你自己的线程。见7.20 KILL句法。如果你不使用FULL选项,那么每个查询只有头100字符被显示出来。 SHO W GRANTS FOR user列出对一个用户必须发出以重复授权的授权命令。 mysql> SHOW GRANTS FOR ro ot@localhost;+--------------------------------------------------- ------------------+| Grants for root@localhost |+--------------------------------------- ------------------------------+| GRANT ALL PRIVILEGES ON . TO '' root''''localhost'' WITH GRANT OPTION |+--------------------------- ------------------------------------------+ EXPLAIN句法(得到关于SELEC T的信息) EXPLAIN tbl_nameor EXPLAIN SELECT select_optionsEXPLAIN tb l_name是DESCRIBE tbl_name或SHOW COLUMNS FROM tbl_name的一个同义词。 当你在一条S ELECT语句前放上关键词EXPLAIN,MySQL解释它将如何处理SELECT,提供有关表如何联结和以什么次序联结的信息。 借助 于EXPLAIN,你可以知道你什么时候必须为表加入索引以得到一个使用索引找到记录的更快的SELECT。你也能知道优化器是否以一个最 佳次序联结表。为了强制优化器对一个SELECT语句使用一个特定联结次序,增加一个STRAIGHT_JOIN子句。 对于非简单的联结 ,EXPLAIN为用于SELECT语句中的每个表返回一行信息。表以他们将被读入的顺序被列出。MySQL用一边扫描多次联结的方式解决 所有联结,这意味着MySQL从第一个表中读一行,然后找到在第二个表中的一个匹配行,然后在第3个表中等等。当所有的表被处理完,它输出 选择的列并且回溯表列表直到找到一个表有更多的匹配行,从该表读入下一行并继续处理下一个表。 从EXPLAIN的输出包括下面列: ta ble 输出的行所引用的表。 type 联结类型。各种类型的信息在下面给出。 possible_keys possible_key s列指出MySQL能使用哪个索引在该表中找到行。注意,该列完全独立于表的次序。这意味着在possible_keys中的某些键实际上 不能以生成的表次序使用。如果该列是空的,没有相关的索引。在这种情况下,你也许能通过检验WHERE子句看是否它引用某些列或列不是适合 索引来提高你的查询性能。如果是这样,创造一个适当的索引并且在用EXPLAIN检查查询。见7.8 ALTER TABLE句法。为了看 清一张表有什么索引,使用SHOW INDEX FROM tbl_name。 key key列显示MySQL实际决定使用的键。如果没 有索引被选择,键是NULL。 key_len key_len列显示MySQL决定使用的键长度。如果键是NULL,长度是NULL。注 意这告诉我们MySQL将实际使用一个多部键值的几个部分。 ref ref列显示哪个列或常数与key一起用于从表中选择行。 rows rows列显示MySQL相信它必须检验以执行查询的行数。 Extra 如果Extra列包括文字Only index,这意味着信息 只用索引树中的信息检索出的。通常,这比扫描整个表要快。如果Extra列包括文字where used,它意味着一个WHERE子句将被 用来限制哪些行与下一个表匹配或发向客户。 不同的联结类型列在下面,以最好到最差类型的次序: system 桌子仅有一行(=系统表) 。这是const联结类型的一个特例。 const 桌子有最多一个匹配行,它将在查询开始时被读取。因为仅有一行,在这行的列值可被剩下 的优化器认为是常数。 const表很快,因为它们只读取一次! eq_ref 对于每个来自于先前的表的行组合,从该表中读取一行。这可 能是最好的联结类型,除了const类型。它用在一个索引的所有部分被联结使用并且索引是UNIQUE或PRIMARY KEY。 ref 对于每个来自于先前的表的行组合,所有有匹配索引值的行将从这张表中读取。如果联结只使用键的最左面前缀,或如果键不是UNIQUE或P RIMARY KEY(换句话说,如果联结不能基于键值选择单个行的话),使用ref。如果被使用的键仅仅匹配一些行,该联结类型是不错的 。 range 只有在一个给定范围的行将被检索,使用一个索引选择行。ref列显示哪个索引被使用。 index 这与ALL相同,除了 只有索引树被扫描。这通常比ALL快,因为索引文件通常比数据文件小。 ALL 对于每个来自于先前的表的行组合,将要做一个完整的表扫描 。如果表格是第一个没标记const的表,这通常不好,并且通常在所有的其他情况下很差。你通常可以通过增加更多的索引来避免ALL,使得 行能从早先的表中基于常数值或列值被检索出。 通过相乘EXPLAIN输出的rows行的所有值,你能得到一个关于一个联结要多好的提示。 这应该粗略地告诉你MySQL必须检验多少行以执行查询。当你使用max_join_size变量限制查询时,也用这个数字。见10.2. 3 调节服务器参数。 下列例子显示出一个JOIN如何能使用EXPLAIN提供的信息逐步被优化。 假定你有显示在下面的SELECT语 句,你使用EXPLAIN检验: EXPLAIN SELECT tt.TicketNumber, tt.TimeIn, tt.Pro jectReference, tt.EstimatedShipDate, tt.ActualShipDate, tt.Client ID, tt.ServiceCodes, tt.RepetitiveID, tt.CurrentProcess, tt.Curre ntDPPerson, tt.RecordVolume, tt.DPPrinted, et.COUNTRY, et_1.COUNT RY, do.CUSTNAME FROM tt, et, et AS et_1, do WHERE tt.SubmitTime I S NULL AND tt.ActualPC = et.EMPLOYID AND tt.AssignedPC = et_1.EMP LOYID AND tt.ClientID = do.CUSTNMBR;对于这个例子,假定: 被比较的列被声明如下: 表 列 列类 型 tt ActualPC CHAR(10) tt AssignedPC CHAR(10) tt ClientID CHAR(10 ) et EMPLOYID CHAR(15) do CUSTNMBR CHAR(15) 表有显示在下面的索引: 表索引 tt Ac tualPC tt AssignedPC tt ClientID et EMPLOYID(主键)do CUSTNMBR(主键)tt .ActualPC值不是均匀分布的。 开始,在任何优化被施行前,EXPLAIN语句产生下列信息: table type possi ble_keys key key_len ref rows Extraet ALL P RIMARY NULL NULL NULL 74do ALL PRIMAR Y NULL NULL NULL 2135et_1 ALL PRIMARY NULL NULL NULL 74tt ALL AssignedPC,Cli entID,ActualPC NULL NULL NULL 3872 range checked for each reco rd (key map: 35)因为type对每张表是ALL,这个输出显示MySQL正在对所有表进行一个完整联结!这将花相当长的时 间,因为必须检验每张表的行数的乘积次数!对于一个实例,这是74 2135 74 3872 = 45,268,558,7 20行。如果表更大,你只能想象它将花多长时间…… 如果列声明不同,这里的一个问题是MySQL(还)不能高效地在列上使用索引。在本文 中,VARCHAR和CHAR是相同的,除非他们声明为不同的长度。因为tt.ActualPC被声明为CHAR(10)并且et.EMP LOYID被声明为CHAR(15),有一个长度失配。 为了修正在列长度上的不同,使用ALTER TABLE将ActualPC的长度 从10个字符变为15个字符:mysql> ALTER TABLE tt MODIFY ActualPC VARCHAR(15);现 在tt.ActualPC和et.EMPLOYID都是VARCHAR(15),再执行EXPLAIN语句产生这个结果: table t ype possible_keys key key_len ref rows Extratt ALL AssignedPC,ClientID,ActualPC NULL NULL NULL 3872 wh ere useddo ALL PRIMARY NULL NULL NULL 2135 range checked for each record (key map: 1)et_1 ALL PRIMA RY NULL NULL NULL 74 range checked for each record (key map: 1)et eq_ref PRIMARY PRIMARY 15 t t.ActualPC 1这不是完美的,但是是好一些了(rows值的乘积少了一个74一个因子),这个版本在几秒内执行。 第2种改变能 消除tt.AssignedPC = et_1.EMPLOYID和tt.ClientID = do.CUSTNMBR比较的列的长度失 配:mysql> ALTER TABLE tt MODIFY AssignedPC VARCHAR(15), MODIFY Cli entID VARCHAR(15);现在EXPLAIN产生的输出显示在下面: table type possible_ke ys key key_len ref rows Extraet ALL PR IMARY NULL NULL NULL 74tt ref Assig nedPC,ClientID,ActualPC ActualPC 15 et.EMPLOYID 52 where usedet_1 eq_ref PRIMARY PRIMARY 15 tt.AssignedPC 1do eq _ref PRIMARY PRIMARY 15 tt.ClientID 1这“几乎”象它能得到的一 样好。 剩下的问题是,缺省地,MySQL假设在tt.ActualPC列的值是均匀分布的,并且对tt表不是这样。幸好,很容易告诉My SQL关于这些: shell> myisamchk --analyze PATH_TO_MYSQL_DATABASE/ttshel l> mysqladmin refresh现在联结是“完美”的了,而且EXPLAIN产生这个结果: table type po ssible_keys key key_len ref rows Extratt A LL AssignedPC,ClientID,ActualPC NULL NULL NULL 3872 wher e usedet eq_ref PRIMARY PRIMARY 15 tt.ActualPC 1et_1 eq_ref PRIMARY PRIMARY 15 tt.AssignedPC 1do eq_ref PRIMARY PRIMARY 15 tt.ClientID 1注意在从EX PLAIN输出的rows列是一个来自MySQL联结优化器的“教育猜测”;为了优化查询,你应该检查数字是否接近事实。如果不是,你可以 通过在你的SELECT语句里面使用STRAIGHT_JOIN并且试着在在FROM子句以不同的次序列出表,可能得到更好的性能。 DE SCRIBE句法 (得到列的信息){DESCRIBE | DESC} tbl_name {col_name | wild}DESC RIBE提供关于一张表的列的信息。col_name可以是一个列名字或包含SQL的“%”和“_”通配符的一个字符串。 如果列类型不同 于你期望的是基于一个CREATE TABLE语句,注意MySQL有时改变列类型。见7.7.1 隐含的列说明变化。 这个语句为了与 Oracle 兼容而提供的。 SHOW语句提供类似的信息。见7.21 SHOW句法(得到表,列的信息)。 LOCK TABLES /UNLOCK TABLES句法LOCK TABLES tbl_name [AS alias] {READ | [LOW_PRIO RITY] WRITE} [, tbl_name {READ | [LOW_PRIORITY] WRITE} ...]...UNL OCK TABLESLOCK TABLES为当前线程锁定表。UNLOCK TABLES释放被当前线程持有的任何锁。当线程发出另外一 个LOCK TABLES时,或当服务器的连接被关闭时,当前线程锁定的所有表自动被解锁。 如果一个线程获得在一个表上的一个READ锁 ,该线程(和所有其他线程)只能从表中读。如果一个线程获得一个表上的一个WRITE锁,那么只有持锁的线程READ或WRITE表,其他 线程被阻止。 每个线程等待(没有超时)直到它获得它请求的所有锁。 WRITE锁通常比READ锁有更高的优先级,以确保更改尽快被处理 。这意味着,如果一个线程获得READ锁,并且然后另外一个线程请求一个WRITE锁, 随后的READ锁请求将等待直到WRITE线程得 到了锁并且释放了它。当线程正在等待WRITE锁时,你可以使用LOW_PRIORITY WRITE允许其他线程获得READ锁。如果你 肯定终于有个时刻没有线程将有一个READ锁,你应该只使用LOW_PRIORITY WRITE。 当你使用LOCK TABLES时, 你必须锁定你将使用的所有表!如果你正在一个查询中多次使用一张表(用别名),你必须对每个别名得到一把锁!这条政策保证表锁定不会死锁。 注意你应该不锁定任何你正在用INSERT DELAYED使用的表,这是因为在这种情况下,INSERT被一个不同的线程执行。 通常 ,你不必锁定表,因为所有单个UPDATE语句是原语;没有其他线程能防碍任何其它正在执行SQL语句的线程。当你想锁定表,有一些情况: 如果你将在一堆表上运行许多操作,锁定你将使用的表是较快的。当然缺点是,没有其他线程能更新一个READ锁定的表并且没有其他线程能读 一个WRITE-锁定的表。 MySQL不支持事务环境,所以如果你想要保证在一个SELECT和一个UPDATE之间没有其他线程到来, 你必须使用LOCK TABLES。下面显示的例子要求LOCK TABLES以便安全地执行: mysql> LOCK TABLES trans READ, customer WRITE;mysql> select sum(value) from trans wh ere customer_id= some_id;mysql> update customer set total_value=sum_from_previous_statement where customer_id=some_id;mysql> UNLOCK TABLES;没有LOCK TABLES,另外一个线程可能有一个机会在执行SELECT和UPDATE语句之间往trans表中插入一个新行。 通过使用渐增更改(UPDATE customer SET value=value+new_value)或LAST_INSERT_ID()函数,在很多情况下你能使用LOCK TABLES来避免。 你也可以使用用户级锁定函数GET_LOCK()和RELEASE_LOCK()解决一些情况,这些锁保存在服务器的一张哈希表中并且用pthread_mutex_lock()和pthread_mutex_unlock()实现以获得高速度。见7.4.12 其他函数。 有关锁定政策的更多信息,见10.2.8 MySQL 怎样锁定表。 SET OPTION句法SET [OPTION] SQL_VALUE_OPTION= value, ...SET OPTION设置影响服务器或你的客户操作的各种选项。你设置的任何选择保持有效直到当前会话结束,或直到你设置选项为不同的值。 CHARACTER SET character_set_name | DEFAULT 这用给定的映射表从/到客户映射所有字符串。对character_set_name当前唯一的选项是 cp1251_koi8,但是你能容易通过编辑在MySQL源代码分发的“sql/convert.cc”文件增加新的映射。缺省映射能用character_set_name的DEFAULT值恢复。注意设置CHARACTER SET选项的语法不同于设置其他选项目的语法。 PASSWORD = PASSWORD(''some password'') 设置当前用户的口令。任何非匿名的用户能改变他自己的口令! PASSWORD FOR user = PASSWORD(''some password'') 设置当前服务器主机上的一个特定用户的口令。只有具备存取mysql数据库的用户可以这样做。用户应该以user@hostname格式给出,这里user和hostname完全与他们列在mysql.user表条目的User和Host列一样。例如,如果你有一个条目其User和Host字段是''bob''和''%.loc.gov'',你将写成: mysql> SET PASSWORD FOR bob@"%.loc.gov" = PASSWORD("newpass");或mysql> UPDATE mysql.user SET password=PASSWORD("newpass") where user="bob'' and host="%.loc.gov";SQL_AUTO_IS_NULL = 0 | 1 如果设置为1(缺省 ),那么对于一个具有一个自动加1的行的表,用下列构件能找出最后插入的行:WHERE auto_increment_column IS NULL。这被一些 ODBC 程序入Access使用。 SQL_BIG_TABLES = 0 | 1 如果设置为1,所有临时表存在在磁盘上而非内存中。这将更慢一些,但是对需要大的临时表的大SELECT操作,你将不会得到The table tbl_name is full的错误。对于一个新连接的缺省值是0(即,使用内存中的临时表)。 SQL_BIG_SELECTS = 0 | 1 如果设置为0,如果一个SELECT尝试可能花很长的时间,MySQL将放弃。这在一个不妥当的WHERE语句发出时是有用的。一个大的查询被定义为一个将可能必须检验多于max_join_size行的SELECT。对一个新连接的缺省值是1(它将允许所有SELECT语句)。 SQL_LOW_PRIORITY_UPDATES = 0 | 1 如果设置为1,所有INSERT、UPDATE、DELETE和LOCK TABLE WRITE语句等待,直到在受影响的表上没有未解决的SELECT或LOCK TABLE READ。 SQL_SELECT_LIMIT = value | DEFAULT 从SELECT语句返回的记录的最大数量。如果一个SELECT有一个LIMIT子句,LIMIT优先与SQL_SELECT_LIMIT值。对一个新连接的缺省值是“无限”的。如果你改变了限制,缺省值能用SQL_SELECT_LIMIT的一个DEFAULT值恢复。 SQL_LOG_OFF = 0 | 1 如果设置为1,如果客户有process权限,对该客户没有日志记载到标准的日志文件中。这不影响更新日志记录! SQL_LOG_UPDATE = 0 | 1 如果设置为0, 如果客户有process权限,对该客户没有日志记载到更新日志中。这不影响标准日志文件! TIMESTAMP = timestamp_value | DEFAULT 为该客户设置时间。如果你使用更新日志恢复行,这被用来得到原来的时间标记。 LAST_INSERT_ID = # 设置从LAST_INSERT_ID()返回的值。当你在更新一个表的命令中使用LAST_INSERT_ID()时,它存储在更新日志中。 INSERT_ID = # 设置当插入一个AUTO_INCREMENT值时,由INSERT命令使用的值。这主要与更新日志一起使用。 GRANT和REVOKE句法GRANT priv_type [(column_list)] [, priv_type [(column_list)] ...] ON {tbl_name | | . | db_name.} TO user_name [IDENTIFIED BY ''password''] [, user_name [IDENTIFIED BY ''password''] ...] [WITH GRANT OPTION]REVOKE priv_type [(column_list)] [, priv_type [(column_list)] ...] ON {tbl_name | | . | db_name.} FROM user_name [, user_name ...]GRANT在MySQL 3.22.11或以后版本中实现。对于更早MySQL版本,GRANT语句不做任何事情。 GRANT和REVOKE命令允许系统主管在4个权限级别上授权和撤回赋予MySQL用户的权利: 全局级别 全局权限作用于一个给定服务器上的所有数据库。这些权限存储在mysql.user表中。 数据库级别 数据库权限作用于一个给定数据库的所有表。这些权限存储在mysql.db和mysql.host表中。 表级别 表权限作用于一个给定表的所有列。这些权限存储在mysql.tables_priv表中。 列级别 列权限作用于在一个给定表的单个列。这些权限存储在mysql.columns_priv表中。 对于GRANT如何工作的例子,见6.11 为MySQL增加新的用户权限。对于GRANT和REVOKE语句,priv_type可以指定下列的任何一个: ALL PRIVILEGES FILE RELOADALTER INDEX SELECTCREATE INSERT SHUTDOWNDELETE PROCESS UPDATEDROP REFERENCES USAGEALL是ALL PRIVILEGES的一个同义词,REFERENCES还没被实现,USAGE当前是“没有权限”的一个同义词。它能用在你想要创建一个没有权限用户的时候。 为了从一个用户撤回grant的权限,使用GRANT OPTION的一个priv_type值: REVOKE GRANT OPTION ON ... FROM ...;对于表,你能指定的唯一priv_type值是SELECT、INSERT、UPDATE、DELETE、CREATE、DROP、GRANT、INDEX和ALTER。 对于列,你能指定的唯一priv_type值是(即,当你使用一个column_list子句时)是SELECT、INSERT和UPDATE。 你能通过使用ON .语法设置全局权限,你能通过使用ON db_name.语法设置数据库权限。如果你指定ON 并且你有一个当前数据库,你将为该数据库设置权限。(警告:如果你指定ON 而你没有一个当前数据库,你将影响全局权限!)为了容纳对任意主机的用户授予的权利,MySQL支持以user@host格式指定user_name值。如果你想要指定一个特殊字符的一个user字符串(例如“-”),或一个包含特殊字符或通配符的host字符串(例如“%”),你可以用括号括起能用户或主机名字 (例如,''test-user''@''test-hostname'')。 你能在主机名中指定通配符。例如,user@"%.loc.gov"适用于在loc.gov域中任何主机的user,并且user@"144.155.166.%"适用于在144.155.166类 C 子网中任何主机的user。 简单形式的user是user@"%"的一个同义词。注意:如果你允许匿名用户连接MySQL服务器(它是缺省的),你也应该增加所有本地用户如user@localhost,因为否则,当用户试图从本地机器上登录到MySQL服务器时,对于mysql.user表中的本地主机的匿名用户条目将被使用!匿名用户通过插入有User=''''的条目到mysql.user表中来定义。通过执行这个查询,你可以检验它是否作用于你: mysql> SELECT Host,User FROM mysql.user WHERE User='''';目前,GRANT仅支持最长60个字符的主机、表、数据库和列名。一个用户名字能最多到16个字符。 对与一个表或列的权限是由4个权限级别的逻辑或形成的。例如,如果mysql.user表指定一个用户有一个全局select权限,它不能被数据库、表或列的一个条目否认。 对于一个列的权限能如下计算: global privilegesOR (database privileges AND host privileges)OR table privilegesOR column privileges在大多数情况下,你只授予用户一个权限级别上的权限,因此现实通常不象上面所说的那样复杂。:) 权限检查过程的细节在6 MySQL 存取权限系统中给出。 如果你为一个在mysql.user表中不存在的用户/主机名组合授权,一个条目被增加并且保留直到用一个DELETE命令删除。换句话说,GRANT可以创建user表的条目,但是REVOKE将不删除;你必须明确地使用DELETE删除. 在MySQL 3.22.12或以后,如果创建一个新用户或如果你有全局授予权限,用户的口令将被设置为由IDENTIFIED BY子句指定的口令,如果给出一个。如果用户已经有了一个口令,它被一个新的代替。 警告:如果你创造一个新用户但是不指定一个IDENTIFIED BY子句,用户没有口令。这是不安全的。 口令也能用SET PASSWORD命令设置。见7.25 SET OPTION句法。 如果你为一个数据库授权,如果需要在mysql.db表中创建一个条目。当所有为数据库的授权用REVOKE删除时,这个条目被删除。 如果一个用户没有在一个表上的任何权限,当用户请求一系列表时,表不被显示(例如,用一个SHOW TABLES语句)。 WITH GRANT OPTION子句给与用户有授予其他用户在指定的权限水平上的任何权限的能力。你应该谨慎对待你授予他grant权限的用户,因为具有不同权限的两个用户也许能合并权限! 你不能授予其他用户你自己不具备的权限; agree权限允许你放弃你仅仅拥有的那些权限。 要知道,当你将一个特定权限级别上的grant授予其他用户,用户已经拥有(或在未来被授予!)的在该级别上的任何权限也可由该用户授权。假定你授权一个用户在一个数据库上的insert权限,那么如果你授权在数据库上select权限并且指定WITH GRANT OPTION,用户能不仅放弃select权限,还有insert。如果你授权用户在数据库上的update权限,用户能放弃insert、select和update。 你不应该将alter权限授予一个一般用户。如果你这样做,用户可以通过重命名表试图颠覆权限系统!注意,如果你正在使用即使一个用户的表或列的权限,服务器要检查所有用户的表和列权限并且这将使MySQL慢下来一点。 当mysqld启动时,所有的权限被读入存储器。数据库、表和列权限马上生效,而用户级权限在下一次用户连接时生效。你用GRANT或REVOKE对受权表执行的更改立即被服务器知晓。如果你手工修改授权表(使用INSERT、UPDATE等等),你应该执行一个FLUSH PRIVILEGES语句或运行mysqladmin flush-privileges告诉服务器再次装载授权表。见6.9 权限变化何时生效。 ANSI SQL版本的GRANT与MySQL版本之间的最大差别: ANSI SQL 没有全局或数据库级别权限,并且 ANSI SQL 不支持所有MySQL支持的权限。 当你在 ANSI SQL 抛弃一张表时,表的所有权限均被撤消。如果你在 ANSI SQL 撤销权限,所有基于该权限的授权也被也被撤消。在MySQL中,权限只能用明确的REVOKE命令或操作MySQL授权表抛弃。 CREATE INDEX句法CREATE [UNIQUE] INDEX index_name ON tbl_name (col_name[(length)],... )CREATE INDEX语句在MySQL版本 3.22 以前不做任何事情。在 3.22 或以后版本中,CREATE INDEX被映射到一个ALTER TABLE语句来创建索引。见7.8 ALTER TABLE句法。通常,你在用CREATE TABLE创建表本身时创建表的所有索引。见7.7 CREATE TABLE句法。CREATE INDEX允许你把索引加到现有表中。 一个(col1,col2,...)形式的列表创造一个多列索引。索引值有给定列的值串联而成。 对于CHAR和VARCHAR列,索引可以只用一个列的部分来创建,使用col_name(length)句法。(在BLOB和TEXT列上需要长度)。下面显示的语句使用name列的头10个字符创建一个索引: mysql> CREATE INDEX part_of_name ON customer (name(10));因为大多数名字通常在头10个字符不同,这个索引应该不比从整个name列的创建的索引慢多少。另外,在索引使用部分的列能使这个索引成为更小的文件大部分, 它能保存很多磁盘空格并且可能也加快INSERT操作! 注意,如果你正在使用MySQL版本 3.23.2 或更新并且正在使用MyISAM桌子类型,你只能在可以有NULL值的列或一个BLOB/TEXT列上增加一个索引,关于MySQL如何使用索引的更多信息,见10.4 MySQL索引的使用。 DROP INDEX句法DROP INDEX index_name ON tbl_nameDROP INDEX从tbl_name表抛弃名为index_name的索引。DROP INDEX在MySQL 3.22 以前的版本中不做任何事情。在 3.22 或以后,DROP INDEX被映射到一个ALTER TABLE语句来抛弃索引。见7.8 ALTER TABLE句法。 注释句法MySQL服务器支持# to end of line、-- to end of line和/ in-line or multiple-line /注释风格: mysql> select 1+1; # This comment continues to the end of linemysql> select 1+1; -- This comment continues to the end of line mysql> select 1 / this is an in-line comment / + 1;mysql> select 1+/this is amultiple-line comment/1;注意--注释风格要求你在--以后至少有一个空格! 尽管服务者理解刚才描述的注释句法,mysql客户分析/ ... /注释的方式上有一些限制: 单引号和双引号字符被用来标志一个括起来的字符串的开始,即使在一篇注释内。如果引号在主室内没被第2个引号匹配,分析器不知道注释已经结束。如果你正在交互式运行mysql,你能告知有些混乱,因为提示符从mysql>变为''>或">。 一个分号被用来指出当前的SQL语句结束并且跟随它的任何东西表示下一行的开始。 当你交互式运行mysql时和当你把命令放在一个文件中并用mysql < some-file告诉mysql从那个文件读它的输入时,这些限制都适用。MySQL不支持‘--’的ANSI SQL注释风格。见5.4.7 ‘--’作为一篇注释的开始。 CREATE FUNCTION/DROP FUNCTION句法CREATE [AGGREGATE] FUNCTION function_name RETURNS {STRING|REAL|INTEGER} SONAME shared_library_nameDROP FUNCTION function_name一个用户可定义函数(UDF)是用一个像MySQL的原生(内置)函数如ABS()和CONCAT()的新函数来扩展MySQL的方法。 AGGREGATE是MySQL 3.23的一个新选项。一个AGGREGATE函数功能就像一个原生MySQL GROUP函数如SUM或COUNT()。 CREATE FUNCTION在mysql.func系统表中保存函数名、类型和共享库名。你必须对mysql数据库有insert和delete权限以创建和抛弃函数。 所有活跃的函数在每次服务器启动时被重新装载,除非你使用--skip-grant-tables选项启动mysqld,在这种情况下,UDF初始化被跳过并且UDF是无法获得的。(一个活跃函数是一个已经用CREATE FUNCTION装载并且没用DROP FUNCTION删除的函数。) 关于编写用户可定义函数的指令,见14 为MySQL增加新函数。对于UDF的工作机制,函数必须用 C 或 C++ 编写,你的操作系统必须支持动态装载并且你必须动态编译了mysqld(不是静态)。 MySQL对保留词很挑剔吗?一个常见的问题源自于试图使用MySQL内置的数据类型或函数名同名的列来创建数据库表,例如TIMESTAMP或GROUP。你允许这样做(例如,ABS是一个允许的列名),但是当使用其名字也是列名的函数时,在一个函数名和“ ( ”之间不允许白空。下列词明确地在MySQL中被保留。他们的大多数被 ANSI SQL92 禁止作为列或表名(例如,group)。一些被保留因为MySQL需要他们并且正在(当前)使用一个yacc分析器: action add aggregate all alter after and as asc avg avg_row_length auto_increment between bigint bit binary blob bool both by cascade case char character change check checksum column columns comment constraint create cross current_date current_time current_timestamp data database databases date datetime day day_hour day_minute day_second dayofmonth dayofweek dayofyear dec decimal default delayed delay_key_write delete desc describe distinct distinctrow double drop end else escape escaped enclosed enum explain exists fields file first float float4 float8 flush foreign from for full function global grant grants group having heap high_priority hour hour_minute hour_second hosts identified ignore in index infile inner insert insert_id int integer interval int1 int2 int3 int4 int8 into if is isam join key keys kill last_insert_id leading left length like lines limit load local lock logs long longblob longtext low_priority max max_rows match mediumblob mediumtext mediumint middleint min_rows minute minute_second modify month monthname myisam natural numeric no not null on optimize option optionally or order outer outfile pack_keys partial password precision primary procedure process processlist privileges read real references reload regexp rename replace restrict returns revoke rlike row rows second select set show shutdown smallint soname sql_big_tables sql_big_selects sql_low_priority_updates sql_log_off sql_log_update sql_select_limit sql_small_result sql_big_result sql_warnings straight_join starting status string table tables temporary terminated text then time timestamp tinyblob tinytext tinyint trailing to type use using unique unlock unsigned update usage values varchar variables varying varbinary with write when where year year_month zerofill 下列符号(来自上表)被ANSI SQL禁止但是被MySQL允许作为列/表名。这是因为这些名字的一些是很自然的名字并且很多人已经使用了他们。 ACTION BIT DATE ENUM NO TEXT TIME TIMESTAMP |
|