第 29.1 节:错误代码 1064:语法错误

SELECT LastName, FirstName, FROM Person;

返回消息:

Error Code: 1064. You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'from Person' at line 2.

从 MySQL 收到 "1064 error" 消息意味着查询无法被解析,存在语法错误。换句话说,MySQL 无法理解该查询。

错误消息中的引号从查询中 MySQL 无法解析的第一个字符开始。在此示例中,MySQL 在 from Person 的上下文中无法理解。这里,在 from Person 之前有一个多余的逗号。该逗号告诉 MySQL 在 SELECT 子句中期望另一个列描述。

语法错误总是显示 ... near '...'。引号开头的内容非常接近错误位置。要定位错误,请查看引号中的第一个标记以及引号之前的最后一个标记。

有时你会看到 ... near '',即引号内没有内容。这意味着 MySQL 无法理解的第一个字符恰好在语句的末尾或开头。这通常表明查询包含不平衡的引号(' 或 ")或不平衡的括号,或者你没有正确终止语句。

对于存储过程,你可能忘记了正确使用 DELIMITER。

因此,当你遇到错误 1064 时,请查看查询文本,找到错误消息中提到位置。在该位置附近仔细检查查询文本。

如果你请别人帮忙排查错误 1064,最好提供完整的查询文本和错误消息文本。

第 29.2 节:错误代码 1175:安全更新

当尝试更新或删除记录时,如果没有包含使用 KEY 列的 WHERE 子句,会出现此错误。

要强制执行删除或更新,可以设置:

SET SQL_SAFE_UPDATES = 0;

要重新启用安全模式:

SET SQL_SAFE_UPDATES = 1;

第 29.3 节:错误代码 1215:无法添加外键

当表的结构不足以处理开发者所要求的外键快速查找验证时,会发生此错误。

CREATE TABLE `gtType` (
    `type` CHAR(2) NOT NULL,
    `description` VARCHAR(1000) NOT NULL,
    PRIMARY KEY (`type`)
) ENGINE=InnoDB;

CREATE TABLE `getTogethers` (
    `id` INT(11) NOT NULL AUTO_INCREMENT,
    `type` CHAR(2) NOT NULL,
    `eventDT` DATETIME NOT NULL,
    `location` VARCHAR(1000) NOT NULL,
    PRIMARY KEY (`id`),
    KEY `fk_gt2type` (`type`),   -- 参见下面的 Note1
    CONSTRAINT `gettogethers_ibfk_1` FOREIGN KEY (`type`) REFERENCES `gtType` (`type`)
) ENGINE=InnoDB;

Note1:如果由于后面行的 FK 定义需要,这样的 KEY 会自动创建。开发者可以跳过它,必要时会自动添加 KEY(索引)。下面 someOther 示例中展示了开发者跳过它的情形。

到目前为止一切正常,直到以下调用:

CREATE TABLE `someOther` (
    `id` INT(11) NOT NULL AUTO_INCREMENT,
    `someDT` DATETIME NOT NULL,
    PRIMARY KEY (`id`),
    CONSTRAINT `someOther_dt` FOREIGN KEY (`someDT`) REFERENCES `getTogethers` (`eventDT`)
) ENGINE=InnoDB;

错误:Error Code: 1215. Cannot add foreign key constraint

本例中失败的原因是,被引用表 getTogethers 中缺少用于快速查找 eventDT 的索引。解决方法如下:

CREATE INDEX `gt_eventdt` ON getTogethers (`eventDT`);

getTogethers 表被修改后,someOther 的创建将成功。

从 MySQL 手册《使用外键约束》中:

MySQL 要求外键和引用键上有索引,以便外键检查能够快速进行,而不需要全表扫描。在引用表中,必须有一个索引,其中外键列以相同的顺序作为第一列列出。如果不存在这样的索引,它会在引用表上自动创建。

外键和引用键中的对应列必须具有相似的数据类型。整数类型的大小和符号必须相同。字符串类型的长度不必相同。对于非二进制(字符)字符串列,字符集和排序规则必须相同。

InnoDB 允许外键引用任何索引列或列组。但是,在被引用表中,必须有一个索引,其中被引用的列以相同的顺序作为第一列列出。

请注意上面最后一点关于第一(最左)列的要求,以及不强制要求主键(尽管强烈建议有主键)。

成功创建引用(子)表后,可以使用如下命令查看自动为你创建的任何键:

SHOW CREATE TABLE someOther;

遇到此错误的其他常见情况包括(如文档所述,但应强调):

  • 看似微小的差异,例如 INT 指向 INT UNSIGNED。
  • 开发人员难以理解多列(复合)键和第一(最左)列顺序要求。

第 29.4 节:1067、1292、1366、1411 —— 数字、日期、默认值等错误的值

  • 1067:可能与 TIMESTAMP 默认值有关,这些默认值随时间发生了变化。请参阅日期和时间页面中的 TIMESTAMP 默认值。
  • 1292/1366 DOUBLE/Integer:检查是否有字母或其他语法错误。检查列对齐;也许你认为你插入的是 VARCHAR,但实际对齐的是数字列。
  • 1292 DATETIME:检查是否日期太远或太远。检查在夏令时更改的早晨 2 点到 3 点之间。检查是否有错误的语法,例如 +00 时区内容。
  • 1292 VARIABLE:检查你要 SET 的变量的允许值。
  • 1292 LOAD DATA:查看“错误”的行。检查转义符号等。查看数据类型。
  • 1411 STR_TO_DATE:日期格式不正确?

第 29.5 节:1045 访问被拒绝

请参阅“GRANT”和“恢复 root 密码”中的讨论。

第 29.6 节:1236 复制中的“不可能的位置”

通常这意味着主库崩溃且 sync_binlog 设置为 OFF。解决方法是在从库上执行 CHANGE MASTER TO POS=0 指向下一个 binlog 文件(请查看主库)。

原因:主库在刷新到其 binlog 之前(当 sync_binlog=OFF 时)将复制项发送给从库。如果主库在刷新前崩溃,从库在逻辑上已经越过了 binlog 的文件结尾。当主库再次启动时,它会启动一个新的 binlog,因此 CHANGE 到该 binlog 的开头是目前可用的最佳解决方案。

更长期的解决方案是设置 sync_binlog=ON,如果你能承受它带来的额外 I/O。

(如果你使用了 GTID,可能有所不同?)

第 29.7 节:2002、2003 无法连接

检查是否有防火墙阻止端口 3306。

一些可能的诊断和/或解决方案:

  • 服务器是否真的在运行?
  • service firewall stop 和 systemctl disable firewall
  • telnet master 3306
  • 检查 bind-address
  • 检查 skip-name-resolve
  • 检查 socket

第 29.8 节:126、127、134、144、145

当你尝试访问 MySQL 数据库中的记录时,可能会收到这些错误消息。这些错误消息是由于 MySQL 数据库损坏引起的。以下为错误类型:

  • MySQL 错误代码 126 = 索引文件已崩溃
  • MySQL 错误代码 127 = 记录文件已崩溃
  • MySQL 错误代码 134 = 记录已被删除(或记录文件已崩溃)
  • MySQL 错误代码 144 = 表已损坏且上次修复失败
  • MySQL 错误代码 145 = 表被标记为已损坏,应进行修复

MySQL 错误、病毒攻击、服务器崩溃、不当关闭、表损坏都是导致此损坏的原因。当表损坏时,它将变得不可访问,你无法再访问它们。为了获得可访问性,最好从更新的备份中恢复数据。但是,如果你没有更新或任何有效的备份,则可以进行 MySQL 修复。

如果表引擎类型是 MyISAM,对表执行 CHECK TABLE,然后执行 REPAIR TABLE。

然后认真考虑转换为 InnoDB,这样这个错误就不会再发生了。

语法:

CHECK TABLE <table_name>;     -- 检查数据库损坏程度
REPAIR TABLE <table_name>;    -- 修复表

第 29.9 节:139

错误 139 可能意味着表定义中字段的数量和大小超过了一些限制。解决方法:

  • 重新思考模式
  • 规范化一些字段
  • 垂直分区表

第 29.10 节:1366

这通常意味着客户端和服务器之间的字符集处理不一致。请参阅其他章节以获得进一步帮助。

第 29.11 节:24、126、1054、1146、1062 等

24 - 无法打开文件(Too many open files)

open_files_limit 来自操作系统设置。table_open_cache 需要小于该值。

以下情况可能导致此错误:

  • 在存储过程中未能 DEALLOCATE PREPARE。
  • 使用 PARTITION 表且分区数量很大,同时 innodb_file_per_table = ON。建议对一个表不超过 50 个分区(出于多种原因)。(当“本地分区”可用时,此建议可能会改变。)

明显的解决方法是增加操作系统限制:要允许更多文件,请更改 ulimit 或 /etc/security/limits.conf 或在 sysctl.conf 中(kern.maxfiles 和 kern.maxfilesperproc)或其他与操作系统相关的设置。然后增加 open_files_limit 和 table_open_cache。

从 5.6.8 开始,open_files_limit 会根据 max_connections 自动调整,但也可以更改默认值。

1062 - 重复条目

此错误主要出现在以下两种原因:

  1. 重复值 - Error Code: 1062. Duplicate entry '12' for key 'PRIMARY'

主键列是唯一的,不接受重复条目。因此,当你试图插入表中已存在的新行时,会产生此错误。

解决方法:将主键列设置为 AUTO_INCREMENT。插入新行时,忽略主键列或为 PRIMARY KEY 插入 NULL 值。

```sql CREATE TABLE userDetails ( userId INT(10) NOT NULL AUTO_INCREMENT, firstname VARCHAR(50), lastname VARCHAR(50), isActive INT(1) DEFAULT 0, PRIMARY KEY (userId) );

-- 插入时 INSERT INTO userDetails VALUES (NULL, 'John', 'Doe', 1); ```

  1. 唯一数据字段 - Error Code: 1062. Duplicate entry 'A' for key 'code'

你可能将某列指定为唯一列,并且试图插入该列已有值的新行。

解决方法:使用 INSERT IGNORE 代替普通的 INSERT。如果新行不重复现有记录,MySQL 将正常插入。如果记录重复,IGNORE 关键字会丢弃它而不产生任何错误。

sql INSERT IGNORE INTO userDetails VALUES (NULL, 'John', 'Doe', 1);