MySQL常见错误问答

18.2.1 MySQL server has gone away 错误

本小节也涉及有关Lost connection to server during query 的错误。

MySQL server has gone away 错误最常见的原因是服务器超时了并且关闭了连接。缺省地,如果没有事情发生,服务器在 8个小时后关闭连接。你可在启动mysqld时通过设置wait_timeout 变量改变时间限制。

你可以通过执行mysqladmin version 并且检验正常运行的时间来检查MySQL 还没死掉。

如果你有一个脚本,你只须再发出查询让客护进行一次自动的重新连接。

在这种请下,你通常能获得下列错误代码(你得到的是OS相关的):

CR_SERVER_GONE_ERROR 客户不能发送一个问题给服务器。
CR_SERVER_LOST 当写服务器时,客户没有出错,但是它没有得到对问题的一个完整的答案(或任何答案)。

如果你向服务器发送不正确的或太大的查询,你也可能得到这些错误。如果mysqld 得到一个太大或不正常的包,它认为客户出错了并关闭连接。如果你需要较大的查询(例如,如果你正在处理较大的BLOB 列),你可以使用-O max_allowed_packet=# 选项(缺省1M)启动mysqld 以增加查询限制。多余的内存按需分配,这样mysqld 只有在你发出较大差询时或mysqld 必须返回较大的结果行时,才使用更多的内存!

18.2.2 Can't connect to [local] MySQL server 错误

一个MySQL 客户可以两种不同的方式连接mysqld 服务器:Unix套接字,它通过在文件系统中的一个文件(缺省“/tmp/mysqld.sock” )进行连接;或TCP/IP,它通过一个端口号连接。Unix套接字比TCP/IP更快,但是只有用在连接同一台计算机上的服务器。如果你不指定主机名或如果你指定特殊的主机名localhost ,使用Unix套接字。

错误(2002)Can't connect to ... 通常意味着没有一个MySQL 服务器运行在系统上或当试图连接mysqld 服务器时,你正在使用一个错误的套接字文件或TCP/IP端口。

由检查(使用ps )在你的服务器上有一个名为mysqld 的进程启动!如果没有任何mysqld 过程,你应该启动一个。见4.15.2 启动MySQL服务器的问题。

如果一个mysqld 过程正在运行,你可以通过尝试这些不同的连接来检查服务器(当然,端口号和套接字路径名可能在你的安装中是不同的):

shell> mysqladmin version
shell> mysqladmin variables
shell> mysqladmin -h `hostname` version variables
shell> mysqladmin -h `hostname` --port=3306 version
shell> mysqladmin -h 'ip for your host' version
shell> mysqladmin --socket=/tmp/mysql.sock version

注意hostname 命令使用反引号“`”而非正引号“'”;这些导致hostname 输出(即,当前主机名)被代替进mysqladmin 命令中。

这是可能造成Can't connect to local MySQL server 错误的一些原因:

  • mysqld 不在运行。
  • 你正在使用MIT-pthreads的一个系统上运行。如果正在运行在一个没有原生线程的系统上,mysqld 使用 MIT-pthreads 软件包。见4.2 由MySQL支持的操作系统。然而,MIT-pthreads不支持Unix套接字,因此当与服务器连接时,在这样一个系统上,你总是必须明确地指定主机名。试试使用这个命令检查到服务器的连接:
    shell> mysqladmin -h `hostname` version
    
  • 某人删除了mysqld 使用的Unix套接字(缺省“/tmp/mysqld.sock” )。你可能有一个cron 任务删除了MySQL 套接字(例如,一个把旧文件从“/tmp” 目录中删除的任务)。你总是可以运行mysqladmin version 并且检查mysqladmin 正在试图使用的套接字确实存在。在这种情况下,修复方法是删除cron 任务而不删除“mysqld.sock 或将套接字放在其他地方。你能用这个命令在MySQL 配置时指定一个不同的套接字地点:
    shell> ./configure --with-unix-socket-path=/path/to/socket
    

    你也可以使用--socket=/path/to/socket 选项启动safe_mysqld 和在启动你的MySQL 客户前设置环境变量MYSQL_UNIX_PORT 为套接字路径名。你可用--socket=/path/to/socket 选项启动mysqld 服务器。如果你改变了服务器的套接字路径名,你也必须通知MySQL 客户关于新路径的情况。你可以通过设置环境变量MYSQL_UNIX_PORT 为套接字路径名或由提供套接字路径名作为客户的参数做到。你可用这个命令测试套接字:

    shell> mysqladmin --socket=/path/to/socket version
    
  • 你正在使用 Linux和线程已经死了(核心倾倒了)。在这种情况中,你必须杀死其它mysqld 线程(例如在启动一个新的MySQL 服务器之前,可以用mysql_zap 脚本)。见18.1 如果MySQL总是崩溃怎么办。

如果你得到错误Can't connect to MySQL server on some_hostname ,你可以尝试下列步骤找出问题是什么:

  • 通过执行telnet your-host-name tcp-ip-port-number 并且按几次回车来检查服务器是否正常运行。如果有一个MySQL 运行在这个端口上,你应该得到一个包含正在运行的MySQL 服务器的版本号的应答。如果你得到类似于telnet: Unable to connect to remote host: Connection refused 的一个错误,那么没有服务器在使用的端口上运行。
  • 尝试连接本地机器上的mysqld 守护进程,并用mysqladmin variables 检查mysqld被配置使用的TCP/IP端口(变量port )。
  • 检查你的mysqld 服务器没有用--skip-networking 选项启动。

18.2.3 Host '...' is blocked 错误

如果你得到象这样的一个错误:

Host 'hostname' is blocked because of many connection errors.
Unblock with 'mysqladmin flush-hosts'

这意味着,mysqld 已经得到了大量(max_connect_errors )的主机'hostname' 的在中途被中断了的连接请求。在max_connect_errors 次失败请求后,mysqld 认定出错了(象来字一个黑客的攻击),并且阻止该站点进一步的连接,直到某人执行命令mysqladmin flush-hosts

缺省地,mysqld 在10个连接错误后阻塞一台主机。你可以通过象这样启动服务器很容易地调整它:

shell> safe_mysqld -O max_connect_errors=10000 &

注意,对给定的主机,如果得到这条错误消息,你应该首先检查该主机的TCP/IP连接有没有问题。如果你的TCP/IP连接不在运行,增加max_connect_errors 变量的值对你也不会有帮助!

18.2.4 Too many connections 错误

如果在你试土连接MySQL 时,你得到错误Too many connections ,这意味着已经有max_connections 个客户连接了mysqld服务器。

如果你需要比缺省(100)更多的连接,那么你应该重启mysqld ,用更大的 max_connections 变量值。

注意,mysqld 实际上允许(max_connections+1)个客户连接。最后一个连接是为一个用Process 权限的用户保留的。通过不把这个权限给一般用户(他们不应该需要它),有这个权限一个管理员可以登录并且使用SHOW PROCESSLIST 找出什么可能出错。见7.21 SHOW 句法(得到表,列的信息)。

18.2.5 Out of memory 错误

如果你发出查询并且得到类似于下面的错误:

mysql: Out of memory at line 42, 'malloc.c'
mysql: needed 8136 byte (8k), memory in use: 12481367 bytes (12189k)
ERROR 2008: MySQL client ran out of memory

注意,错误指向了MySQL户mysql 。这个错误的原因很简单,客户没有足够的内存存储全部结果。

为了修正这个问题,首先检查你的查询是否正确。它应该返回这么多的行,这合理吗?如果是这样,你可以使用mysql --quick ,它使用mysql_use_result() 检索结果集合。这将较少的负担放在了客户端(只是服务器更多)。

18.2.6 Packet too large 错误

当一个MySQL 客户或mysqld 服务器得到一个比max_allowed_packet 个字节长的包,它发出一个Packet too large 错误并终止连接。

如果你正在使用mysql 客户,你可以通过用mysql --set-variable=max_allowed_packet=8M 指定一个更大的缓冲区来启动客户程序。

如果你正在使用不允许你指定最大包大小的其他客户(例如 DBI ),你需要在你启动服务器时设置包大小。你可以使用mysqld 的命令行选项设置max_allowed_packet 为一个更大的尺寸。例如,如果你正期望将一个全长的BLOB 存入一张表中,你将需要用--set-variable=max_allowed_packet=24M 选项来启动服务器。

 

18.2.7 The table is full 错误

这个错误发生在内存临时表变得比tmp_table_size 字节大时。为了避免这个问题,你可以使用mysqld -O tmp_table_size=# 选项来增加临时表的大小,或在你发出有疑问的查询之前使用SQL选项SQL_BIG_TABLES 。见7.25 SET OPTION 句法。

你也可以使用--big-tables 选项启动mysqld 。这与为所有查询使用SQL_BIG_TABLES 完全相同。

18.2.8 Commands out of sync in client错误

如果你在你的客户代码中得到Commands out of sync; You can't run this command now ,你正在以错误的次序调用客户函数!

这可能发生,例如,如果你正在使用mysql_use_result() 并且在你已经调用了mysql_free_result() 之前试图执行新查询。如果你在mysql_use_result() mysql_store_result() 之间试图执行返回数据的2个查询,它也可能发生。

18.2.9 Ignoring user 错误

如果你得到下列错误:

Found wrong password for user: 'some_user@some_host' ; Ignoring user

这意味着在mysqld 启动时或在它再次装载权限表时,它在user 表中找到了一个有一个无效口令的条目。结果,条目简单地被权限系统忽略。

可能导致这个问题的原因和修正:

  • 你可能正在运行一个有一个老的user 表的新版本mysqld 。你可以通过执行mysqlshow mysql user 看看口令字段是否少于 16个字符来检查它。如果是这样,你可以通过运行scripts/add_long_password 脚本改正这种情况。
  • 用户有一个老式的口令(8个字符长)并且你没使用--old-protocol 选项启动mysqld 。用一个新口令更新在user 表中的用户或用--old-protocol 重启mysqld
  • 你没有使用PASSWORD() 函数在在user 表中指定了一个口令。使用mysql 以一个新口令更新在user 表中的用户。确保使用PASSWORD() 函数:
    mysql> update user set password=PASSWORD('your password')
               where user='XXX';
    

18.2.10 Table 'xxx' doesn't exist 错误

如果你得到错误Table 'xxx' doesn't exist Can't find file: 'xxx' (errno: 2) ,这意味着在当前数据库中没有名为xxx 的表存在。

注意,因为MySQL 使用目录和文件存储数据库和表,数据库和表名件是区分大小写的 !(在Win32上,数据库和表名不是区分大小写的,但是在查询中对所有表的引用必须使用相同的大小写!)

你可以用SHOW TABLES 检查你在当前数据库中有哪个表。见7.21 SHOW 句法(得到表、列的信息)。

18.3 MySQL怎样处理一个溢出的磁盘

当出现一个磁盘溢出的情况时,MySQL 做下列事情:

  • 它每分钟检查一次看是否有足够空间写入当前行。如果有足够的空间,它继续好像发生什么事情。
  • 每6分钟它将有关磁盘溢出的警告写入日志文件。

为了缓和这个问题,你可以采取下列行动:

  • 继续,你只需释放足够的空闲磁盘空间以便插入所有记录。
  • 放弃线程,你必须发一个mysqladmin kill 到线程。在下一次检查磁盘时,线程将被放弃(在1分钟内)。
  • 注意,其他线程可能正在等待引起“磁盘溢出”条件的表。如果你有几个“锁定的”的线程,杀死正在等待磁盘溢出条件的那个线程将允许其他线程继续。

18.4 如何从一个文本文件运行SQL命令

一般地,mysql 客户被交互性地使用,象这样:

shell> mysql database

然而,也可以把你的SQL命令放在一个文件中并且告诉mysql 从该文件读取其输入。要想这样做,创造一个文本文件“text_file” ,它包含你想要执行的命令。然后如下那样调用mysql

shell> mysql database < text_file

你也能启动有一个USE db_name 语句的文本文件。在这种情况下,在命令行上指定数据库名是不必要的:

shell> mysql < text_file
见12.1 不同的MySQL程序概述。 

18.5 MySQL在哪儿存储临时文件

MySQL 使用TMPDIR 环境变量的值作为存储临时文件的目录的路径名。如果你没有设置TMPDIR MySQL 使用系统缺省值,它通常是“/tmp” “/usr/tmp” 。如果包含你的临时文件目录的文件系统太小,你应该编辑safe_mysqld 设定TMPDIR 指向你有足够空间的一个文件系统!你也可以使用mysqld的--tmpdir 选项目设置临时目录。

MySQL 以“隐含文件”创建所有临时文件。这保证了如果mysqld 被终止,临时文件也将被删除。使用隐含文件的缺点是你将看不到一个大的临时文件填满了临时文件目录所在的文件系统。

当排序(ORDER BY GROUP BY )时,MySQL 通常使用一个或两个临时文件。最大磁盘空间需求是:

(存储东西的长度 + sizeof (数据库指针))
* 匹配的行数
* 2

sizeof(数据库指针) 通常是4,但是在未来对确实很大的表可能增加。

对一些SELECT 查询,MySQL 也创建临时SQL表。这些没被隐含且有“SQL_*” 格式的名字。

ALTER TABLE OPTIMIZE TABLE 在原数据库表的同一个目录中创建一张临时表。

18.6 怎样保护“/tmp/mysql.sock ” 不被删除

如果你有这个问题,事实上任何人可以删除MySQL 通讯套接字“/tmp/mysql.sock” ,在Unix的大多数版本上,你能通过为其设置sticky (t)位来保护你的“/tmp” 文件系统。作为root 登录并且做下列事情:

shell> chmod +t /tmp

这将保护你的“/tmp” 文件系统使得文件仅能由他们的所有者或超级用户(root )删除。

你能执行ls -ld /tmp 检查sticky 位是否被设置,如果最后一位许可位是t ,该位被设置了。

18.7 Access denied 错误

见6.6 权限系统如何工作。并且特别要看6.13 引起Access denied 错误的原因。

18.8 怎样作为一个一般用户运行MySQL

MySQL 服务器mysqld 能被任何用户启动并运行。为了将mysqld 改由Unix用户user_name 来运行,你必须做下列事情:

  1. 如果它正在运行,停止服务器(使用mysqladmin shutdown )。
  2. 改变数据库目录和文件以便user_name 有权限读和写文件(你可能需要作为Unix的root 用户才能做到):
    shell> chown -R user_name /path/to/mysql/datadir
    

    如果在MySQL 数据目录中的目录或文件是符号链接,你也将需要顺着那些链接并改变他们指向的目录和文件。chown -R 不能跟随符号链接。

  3. user_name 用户启动服务器,或如果你正在使用MySQL 3.22或以后版本,以Unix root 用户启动mysqld 并使用--user=user_name 选项,mysqld 将在接受任何连接之前切换到以Unix user_name 用户运行。
  4. 如果在系统被重新启动时,你使用mysql.server 脚本启动mysqld ,你应该编辑mysql.server su 以用户user_name 运行mysqld ,或使用--user 选项调用mysqld 。(不改变safe_mysqld 是必要的。)

现在,你的mysqld 进程应该正在作为Unix用户user_name 运行,并运行完好。尽管有一件事情没有变化:权限表的内容。缺省 地(就在运行了脚本mysql_install_db 安装的权限表后),MySQL 用户root 是唯一有存取mysql 数据库或创建或抛弃数据库权限的用户。除非你改变了那些权限,否则他们仍然保持。当你作为一个Unix用户而不是root 登录时,这不应该阻止你作为MySQL root 用户来存取MySQL ;只要为客户程序指定-u root 的选项。

注意通过在命令行上提供-u root ,作为root 存取MySQL ,与作为Unix root 用户或其他Unix用户运行MySQL 没有关系MySQL 的存取权限和用户名与Unix用户名字是完全分开的。唯一与Unix用户名有关的是,如果当你调用一个客户程序时,你不提供一个-u 选项,客户将试图使用你的Unix登录名作为你的MySQL 用户名进行连接。

如果你的Unix机器本身不安全,你可能应该至少在存取表中为MySQL root 用户放上一个口令。否则,在那台机器上有一个帐号的任何用户能运行mysql -u root db_name 并且做他喜欢做的任何事情。

18.9 怎样重新设置一个忘记的口令

如果你忘记了MySQLroot 用户的口令,你可以用下列过程恢复它。

  1. 通过发送一个kill (不是kill -9 )到mysqld 服务器来关闭mysqld服务器。pid 被保存在一个.pid 文件中,通常在MySQL 数据库目录中:
    kill `cat /mysql-data-directory/hostname.pid`
    

    你必须是一个UNIX root 用户或运行服务器的相同用户做这个。

  2. 使用--skip-grant-tables 选项重启mysqld
  3. mysql -h hostname mysql 连接mysqld服务器并且用一条GRANT 命令改变口令。见7.26 GRANT REVOKE 句法。你也可以用mysqladmin -h hostname -u user password 'new password' 进行。
  4. mysqladmin -h hostname flush-privileges 或用SQL命令FLUSH PRIVILEGES 来装载权限表。

18.10 文件许可权限问题

如果你有与文件许可有关的问题,例如,如果当你创建一张表时,mysql 发出下列错误消息:

ERROR: Can't find file: 'path/with/filename.frm' (Errcode: 13) 

那么可能是在mysqld 启动时,环境变量UMASK 可能设置不正确。缺省的umask值是0660 。你可以如下启动safe_mysqld 改变其行为:

shell> UMASK=384  # = 600 in octal
shell> export UMASK
shell> /path/to/safe_mysqld &

18.11 文件没找到

如果你从MySQL 得到ERROR '...' not found (errno: 23) , Can't open file: ... (errno: 24) 或任何其他有errno 23 errno 24 的错误,它意味着,你没有为MySQL 分配足够的文件描述符。你能使用perror 实用程序得到错误号含义是什么的描述:

shell> perror 23
File table overflow
shell> perror 24
Too many open files

这里的问题是mysqld 正在试图同时保持打开太多的文件。你也可以告诉mysqld 一次不打开那么多的文件,或增加mysqld 可得到的文件描述符数量。

为了告诉mysqld 一次保持打开更少的文件,你可以通过使用safe_mysqld -O table_cache=32 选项(缺省值是64)使表缓冲更小。减小max_connections 值也将减少打开文件的数量(缺省值是90)。

要想改变mysqld 可用的文件描述符数量,修改safe_mysqld 脚本。脚本中有一条注释了的行ulimit -n 256 。你可以删除'#' 字符来去掉该行的注释,并且改变数字256改变为mysqld 可用的文件描述符的数量。

ulimit 能增加文件描述符的数量,但是只能到操作系统强加的限制。如果你需要增加每个进程可用的文件描述符数量的OS限制,参见你的操作系统文档。

注意,如果你运行tcsh 外壳,ulimit 将不工作!当你请求当前限制时,tcsh 也将报告不正确的值!在这种情况下,你应该用sh 启动safe_mysqld

18.12 使用DATE 列的问题

一个DATE 值的格式是'YYYY-MM-DD' 。根据ANSI SQL,不允许其他格式。你应该在UPDATE 表达式和SELECT 语句的WHERE子句中使用这个格式。例如:

mysql> SELECT * FROM tbl_name WHERE date >= '1997-05-05';

为了方便,如果日期用在数字上下文,MySQL 自动变换一个日期到一个数字(并且反过来也如此)。当更新时和将一个日期与TIMESTAMP DATE DATETIME 列比较的一个WHERE 子句中,也是足够灵活以允许一种“宽松”的字符串格式。(宽松格式意味着任何标点字符用作在部件之间的分割符。例如,'1998-08-15' '1998#08#15' 是等价的。)MySQL 也能变换不包含分割符的一个字符串(例如 '19980815' ),如果它作为一个日期说得通。

特殊日期'0000-00-00' 可以作为'0000-00-00' 被存储和检索 当通过MyODBC 使用一个'0000-00-00' 日期时,在MyODBC 2.50.12和以上版本,它将自动被转换为NULL ,因为ODBC不能处理这种日期。

因为MySQL 实行了上述的变换,下列语句可以工作:

mysql> INSERT INTO tbl_name (idate) VALUES (19970505);
mysql> INSERT INTO tbl_name (idate) VALUES ('19970505');
mysql> INSERT INTO tbl_name (idate) VALUES ('97-05-05');
mysql> INSERT INTO tbl_name (idate) VALUES ('1997.05.05');
mysql> INSERT INTO tbl_name (idate) VALUES ('1997 05 05');
mysql> INSERT INTO tbl_name (idate) VALUES ('0000-00-00');

mysql> SELECT idate FROM tbl_name WHERE idate >= '1997-05-05';
mysql> SELECT idate FROM tbl_name WHERE idate >= 19970505;
mysql> SELECT mod(idate,100) FROM tbl_name WHERE idate >= 19970505;
mysql> SELECT idate FROM tbl_name WHERE idate >= '19970505';

然而,下列将不工作:

mysql> SELECT idate FROM tbl_name WHERE STRCMP(idate,'19970505')=0;

STRCMP() 是字符串函数,因此它将idate 转换为一个字符串并且实施字符串比较。它不将'19970505' 转换为一个日期并实施日期比较。

注意,MySQL 不检查日期是否正确。如果你存储一个不正确的日期,例如'1998-2-31' ,错误的日期将被存储。如果日期不能被变换到任何合理的值,在DATE 字段中存储一个0 。这主要是一个速度问题并且我们认为检查日期是应用程序的责任,而不服务器。

18.13 时区问题

如果你有一个问题,SELECT NOW() 以GMT时间返回值而不是你的本地时间,你必须设定TZ 环境变量为你的当前时区。这应该在服务器运行的环境进行,例如在safe_mysqld mysql.server 中。

18.14 在搜索中的大小写敏感性

缺省地,MySQL 搜索是大小写不敏感的(尽管有一些字符集从来不是忽略大小写的,例如捷克语 )。这意味着,如果你用col_name LIKE 'a%' 搜寻,你将得到所有以A a 开始的列值。如果你想要使这个搜索大小写敏感,使用象INDEX(col_name, "A")=0 检查一个前缀。或如果列值必须确切是"A" ,使用STRCMP(col_name, "A") = 0

简单的比较操作(>=、>、= 、< 、<= 、排序和聚合)是基于每个字符的“排序值”。有同样排序值的字符(象E,e和'e)被视为相同的字符!

LIKE 比较在每个字符的大写值上进行(E==e 但是E<>'e)。

如果你想要一个列总是被当作大小写敏感的方式,声明它为BINARY 。见7.7 CREATE TABLE 句法。

如果你使用以所谓的big5编码的中文数据,你要使所有的字符列是BINARY ,它可行,是因为big5编码字符的排序顺序基于 ASCII代码的顺序。

18.15 NULL 值问题

NULL 值的概念是造成SQL的新手的混淆的普遍原因,他们经常认为NULL 是和一个空字符串'' 的一样的东西。不是这样的!例如,下列语句是完全不同的:

mysql> INSERT INTO my_table (phone) VALUES (NULL);
mysql> INSERT INTO my_table (phone) VALUES ("");

两个语句把值插入到phone 列,但是第一个插入一个NULL 值而第二个插入一个空字符串。第一个的含义可以认为是“电话号码不知道”,而第二个则可意味着“她没有电话”。

在SQL中,NULL 值在于任何其他值甚至NULL 值比较时总是假的(FALSE)。包含NULL 的一个表达式总是产生一个NULL 值,除非在包含在表达式中的运算符和函数的文档中指出。在下列例子,所有的列返回NULL

mysql> SELECT NULL,1+NULL,CONCAT('Invisible',NULL);

如果你想要寻找值是NULL 的列,你不能使用=NULL 测试。下列语句不返回任何行,因为对任何表达式,expr = NULL 是假的:

mysql> SELECT * FROM my_table WHERE phone = NULL;

要想寻找NULL 值,你必须使用IS NULL 测试。下例显示如何找出NULL 电话号码和空的电话号码:

mysql> SELECT * FROM my_table WHERE phone IS NULL;
mysql> SELECT * FROM my_table WHERE phone = "";

MySQL 中,就像很多其他的SQL服务器一样,你不能索引可以有NULL 值的列。你必须声明这样的列为NOT NULL ,而且,你不能插入NULL 到索引的列中。

当用LOAD DATA INFILE 读取数据时,空列用'' 更新。如果你想要在一个列中有NULL 值,你应该在文本文件中使用\N 。字面上的词'NULL' 也可以在某些情形下使用。见7.16 LOAD DATA INFILE 句法。

当使用ORDER BY 时,首先呈现NULL 值。如果你用DESC 以降序排序,NULL 值最后显示。当使用GROUP BY 时,所有的NULL 值被认为是相等的。

为了有助于NULL 的处理,你能使用IS NULL IS NOT NULL 运算符和IFNULL() 函数。

对某些列类型,NULL 值被特殊地处理。如果你将NULL 插入表的第一个TIMESTAMP 列,则插入当前的日期和时间。如果你将NULL 插入一个AUTO_INCREMENT 列,则插入顺序中的下一个数字。

 

18.16 alias 问题

你可以在GROUP BY ORDER BY 或在HAVING 部分中使用别名引用列。别名也可以用来为列取一个更好点的名字:

SELECT SQRT(a*b) as rt FROM table_name GROUP BY rt HAVING rt > 0;
SELECT id,COUNT(*) AS cnt FROM table_name GROUP BY id HAVING cnt > 0;
SELECT id AS "Customer identity" FROM table_name;

注意,你的 ANSI SQL 不允许你在一个WHERE 子句中引用一个别名。这是因为在WHERE 代码被执行时,列值还可能没有终结。例如下列查询是不合法

SELECT id,COUNT(*) AS cnt FROM table_name WHERE cnt > 0 GROUP BY id;

WHERE 语句被执行以确定哪些行应该包括GROUP BY 部分中,而HAVING 用来决定应该只用结果集合中的哪些行。

18.17 从关联的表中删除行

因为MySQL 不支持子选择或在DELETE 语句中使用多个表,你应该使用下列方法从2个关联的表中删除行:

  1. 在主表中基于某个WHERE 条件SELECT 行。
  2. 在主表中基于相同的条件DELETE 行。
  3. DELETE FROM related_table WHERE related_column IN (selected_rows)

如果在related_column 查询中的字符的全部数量超过1,048,576(缺省值max_allowed_packet ),你应该分成更小的部分并且执行多个DELETE 语句。如果related_column 是一个索引,你每次只删除100-1000个related_column id将可能使得DELETE 最快。如果related_column 不是一个索引,速度与IN 子句中参数的数量无关。

18.18 解决没有匹配行的问题

如果你有一个复杂的查询,涉及多个表,但没有返回任何行,你应该使用下列过程查找你的询问有什么不对:

  1. EXPLAIN 测试查询并且检查你是否能找出显然是错误的一些东西。见7.22 EXPLAIN 句法(得到关于一个SELECT 的信息)。
  2. 仅选择那些在WHERE 子句中使用的字段。
  3. 一次从查询中删除一个表,直到它返回一些行。如果表很大,对查询使用LIMIT 10 是一个好主意。
  4. 对应该已经匹配一行的列做一个SELECT ,针对从询问中做后被删除的表。
  5. 如果你将FLOAT DOUBLE 列与有小数的数字进行比较,你不能使用= !。这个问题在大多数计算机语言是常见的,因为浮点值不是准确的值。
    mysql> SELECT * FROM table_name WHERE float_column=3.5;
       ->
    mysql> SELECT * FROM table_name WHERE float_column between 3.45 and 3.55;
    

    在大多数情况下,将FLOAT 改成一个DOUBLE 将修正它!

  6. 如果你仍然不能发现错误是什么,创建一个最小的可运行mysql test < query.sql 的测试来显示你的问题。你可以用mysqldump --quick database tables > query.sql 创建一个测试文件,在一个编辑器编辑文件,删除一些插入行(如果有太多这些语句)并且在文件末尾加入你的选择语句。测试你仍然有问题,可以这样做:
    shell> mysqladmin create test2
    shell> mysql test2 < query.sql
    

    使用mysqlbug 的邮寄测试文件到mysql@lists.mysql.com

18.19 与ALTER TABLE 有关的问题

如果ALTER TABLE 死于这样一个错误:

Error on rename of './database/name.frm' to './database/B-a.frm' (Errcode: 17)

问题可能是MySQL 在前一个ALTER TABLE 中已经崩溃并且留下了一个名为“A-xxx” “B-xxx” 的老的数据库表。在这种情况下,到MySQL 数据目录中并删除所有名字以A- B- 开始的文件。(你可以把他们移到别的地方而不是删除他们)。

ALTER TABLE 工作方式是:

  • 以要求的改变创建一个名为“A-xxx” 的新表。
  • 从老表把所有行拷贝到“A-xxx”
  • 老表被改名为“B-xxx”
  • “A-xxx” 被改名为你的老表的名字。
  • “B-xxx” 被删除。

如果某些改名操作出错,MySQL 试图还原改变。如果出错严重(当然,这不应该发生。),MySQL 可能留下了老表为“B-xxx” 但是一个简单改名就应该恢复你的数据。

18.20 怎样改变一张表中列的顺序

SQL的要点是中抽象应用程序以避免数据存储格式。你应该总是以你想要检索数据的意愿指定顺序。例如:

SELECT col_name1, col_name2, col_name3 FROM tbl_name;

将以col_name1 col_name2 col_name3 的顺序返回列,而:

SELECT col_name1, col_name3, col_name2 FROM tbl_name; 

将以col_name1 col_name3 col_name2 的顺序返回列。

在一个应用程序中,你应该决不 基于他们的位置使用SELECT * 检索列,因为被返回的列的顺序永远不能 保证;对你的数据库的一个简单改变可能导致你的应用程序相当有戏剧性地失败。

不管怎样,如果你想要改变列的顺序,你可以这样做:

  1. 以正确的列顺序创建一张新表。
  2. 执行INSERT INTO new_table SELECT fields-in-new_table-order FROM old_table .
  3. 删除或改名old_table
  4. ALTER TABLE new_table RENAME old_table
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值