正向工程中一些新关系在填充数据库中失败(错误150)

时间:2014-10-07 13:23:38

标签: mysql database mysql-workbench mysql-error-1005

这是创建表线程上的另一个错误1005,错误150。我见过很多,但没有一个能回答我的问题。

我在mysql workbench中有一个数据库,它是正向工程并填充数据。然后,我从模型视图创建一个新表。然后,我在这个新表和我数据库中的现有表之间添加了一个n:m关系。

最后,我尝试同步我的数据库。为创建两个新表而生成的代码是:

SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;
SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='TRADITIONAL,ALLOW_INVALID_DATES';

CREATE TABLE IF NOT EXISTS `mydb`.`SEntences` (
  `idSEntences` INT(11) NOT NULL,
  PRIMARY KEY (`idSEntences`))
ENGINE = InnoDB
DEFAULT CHARACTER SET = latin1
COLLATE = latin1_bin;

CREATE TABLE IF NOT EXISTS `mydb`.`Tips_has_SEntences` (
  `Tips_idTips` VARCHAR(45) NOT NULL,
  `SEntences_idSEntences` INT(11) NOT NULL,
  PRIMARY KEY (`Tips_idTips`, `SEntences_idSEntences`),
  INDEX `fk_Tips_has_SEntences_SEntences1_idx` (`SEntences_idSEntences` ASC),
  INDEX `fk_Tips_has_SEntences_Tips1_idx` (`Tips_idTips` ASC),
  CONSTRAINT `fk_Tips_has_SEntences_Tips1`
    FOREIGN KEY (`Tips_idTips`)
    REFERENCES `mydb`.`Tips` (`idTips`)
    ON DELETE NO ACTION
    ON UPDATE NO ACTION,
  CONSTRAINT `fk_Tips_has_SEntences_SEntences1`
    FOREIGN KEY (`SEntences_idSEntences`)
    REFERENCES `mydb`.`SEntences` (`idSEntences`)
    ON DELETE NO ACTION
    ON UPDATE NO ACTION)
ENGINE = InnoDB
DEFAULT CHARACTER SET = latin1
COLLATE = latin1_bin;


SET SQL_MODE=@OLD_SQL_MODE;
SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;

我收到一条错误,包含此日志:

Executing SQL script in server
ERROR: Error 1005: Can't create table 'mydb.Tips_has_SEntences' (errno: 150)


CREATE TABLE IF NOT EXISTS `mydb`.`Tips_has_SEntences` (
  `Tips_idTips` VARCHAR(45) NOT NULL,
  `SEntences_idSEntences` INT(11) NOT NULL,
  PRIMARY KEY (`Tips_idTips`, `SEntences_idSEntences`),
  INDEX `fk_Tips_has_SEntences_SEntences1_idx` (`SEntences_idSEntences` ASC),
  INDEX `fk_Tips_has_SEntences_Tips1_idx` (`Tips_idTips` ASC),
  CONSTRAINT `fk_Tips_has_SEntences_Tips1`
    FOREIGN KEY (`Tips_idTips`)
    REFERENCES `mydb`.`Tips` (`idTips`)
    ON DELETE NO ACTION
    ON UPDATE NO ACTION,
  CONSTRAINT `fk_Tips_has_SEntences_SEntences1`
    FOREIGN KEY (`SEntences_idSEntences`)
    REFERENCES `mydb`.`SEntences` (`idSEntences`)
    ON DELETE NO ACTION
    ON UPDATE NO ACTION)
ENGINE = InnoDB
DEFAULT CHARACTER SET = latin1
COLLATE = latin1_bin

SQL script execution finished: statements: 3 succeeded, 1 failed

Fetching back view definitions in final form.
Nothing to fetch

从终端运行mysql,使用SHOW ENGINE INNODB STATUS \ G命令,从最近的外键错误字段中获取此输出:

------------------------
LATEST FOREIGN KEY ERROR
------------------------
141007 14:18:53 Error in foreign key constraint of table mydb/Tips_has_SEntences:

    FOREIGN KEY (`Tips_idTips`)
    REFERENCES `mydb`.`Tips` (`idTips`)
    ON DELETE NO ACTION
    ON UPDATE NO ACTION,
  CONSTRAINT `fk_Tips_has_SEntences_SEntences1`
    FOREIGN KEY (`SEntences_idSEntences`)
    REFERENCES `mydb`.`SEntences` (`idSEntences`)
    ON DELETE NO ACTION
    ON UPDATE NO ACTION)
ENGINE = InnoDB
DEFAULT CHARACTER SET = latin1
COLLATE = latin1_bin:
Cannot find an index in the referenced table where the
referenced columns appear as the first columns, or column types
in the table and the referenced table do not match for constraint.
Note that the internal storage type of ENUM and SET changed in
tables created with >= InnoDB-4.1.12, and such columns in old tables
cannot be referenced by such columns in new tables.
See http://dev.mysql.com/doc/refman/5.5/en/innodb-foreign-key-constraints.html
for correct foreign key definition.

在研究了我的问题之后,我无法弄清楚出了什么问题。所有数据类型都是相同的,外键在主键上(主键上有主键)等。我研究了这个错误的各种堆栈溢出答案,并查看了这个页面,链接在其中一个:MySQL Error Number 1005 Can’t create table ‘.\mydb#sql-328_45.frm’ (errno: 150)我搜索过虽然我尽可能彻底,但答案可能还在那里。在这种情况下,我很抱歉。

也许它必须对旧表(Tips)中已有数据这一事实做些什么。同步1:n关系,在旧表中添加外键(提示)虽然奇怪地起作用。如果数据是问题,这将无效,正如我在这篇文章中所发现的那样:How to add foreign key to MySQL table?

另一方面,添加1:n关系,这需要将旧表(Tips)的外键添加到新表中,生成相同的错误和日志(除了引用类似的表)这个:'。\ mydb#sql-328_45.frm')。

我应该注意,这些问题出现在我的任何旧表中(数据库中已有数据的表)。另外,在我继续填充数据并尝试添加这些新表之前,我相当确定我更新了mysql工作台,之后我用数据填充了数据库。它现在是版本6并在kubuntu,linux中运行。

这里有什么问题,怎么治疗?是极端的,例如导出数据库,丢弃和导入它的唯一方法是什么?即使在这种情况下,我该怎么办呢?请记住,这是一个包含许多数据条目的数据库,大约100000个。

如果您需要更多信息,我会从这里提供。

提示表创建代码:

SHOW CREATE TABLE mydb.Tips;

CREATE TABLE `Tips` (
  `idTips` varchar(45) CHARACTER SET latin1 NOT NULL,
  `like_count` int(10) unsigned DEFAULT NULL,
  `text` longtext CHARACTER SET latin1,
  `created_at` bigint(19) unsigned DEFAULT NULL,
  `url` varchar(100) CHARACTER SET latin1 DEFAULT NULL,
  `todo_count` bigint(19) unsigned DEFAULT NULL,
  `save_count` bigint(19) unsigned DEFAULT NULL,
  `Venues_idVenues` varchar(45) CHARACTER SET latin1 NOT NULL,
  PRIMARY KEY (`idTips`),
  KEY `fk_Tips_Venues1` (`Venues_idVenues`),
  CONSTRAINT `fk_Tips_Venues1` FOREIGN KEY (`Venues_idVenues`) REFERENCES `Venues` (`idVenues`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_bin

1 个答案:

答案 0 :(得分:2)

TL;博士

imho您需要同步Tips.idTips列和Tips_has_SEntences.Tips_idTips列的定义。

特别是列的字符集和排序规则不对应。

分辨率

因此,在代码中,执行以下操作之一:

  • 定义Tips_has_SEntences.Tips_idTips列的字符集或排序规则 明确。

    `Tips_idTips` VARCHAR(45) CHARACTER SET latin1 NOT NULL,
    

    `Tips_idTips` VARCHAR(45) COLLATE latin1_swedish_ci NOT NULL,
    
  • 删除Tips_has_SEntences表上的显式默认排序规则。

    COLLATE = latin1_bin -- remove this section
    
  • 删除Tips.idTips列上的显式字符集定义。

    `idTips` varchar(45) NOT NULL,
    
  • latin1_bin列上指定Tips.idTips归类。

    `idTips` varchar(45) COLLATE latin1_bin NOT NULL,
    

请注意:如果在使用ALTER TABLE查询时,“to”和“from”字符集不兼容,则最后两个选项可能会导致数据丢失。
您应该是安全的,因为latin1_binlatin1_swedish_ci排序规则使用相同的字符集(latin1)。

解释

实验

当我在Tips_has_SEntences CREATE TABLE声明中禁用令人不安的外键时:

--  CONSTRAINT `fk_Tips_has_SEntences_Tips1`
--    FOREIGN KEY (`Tips_idTips`)
--    REFERENCES `mydb`.`Tips` (`idTips`)
--    ON DELETE NO ACTION
--    ON UPDATE NO ACTION,

执行查询并在SHOW CREATE TABLETips表上执行Tips_has_SEntences,我发现外键耦合的两列的定义有所不同。

    ...
    `idTips` varchar(45) CHARACTER SET latin1 NOT NULL,
    ...
    `Tips_idTips` varchar(45) COLLATE latin1_bin NOT NULL,
    ...

Tips.idTips列上明确设置了字符集,并在Tips_has_SEntences.Tips_idTips列上设置了表格的默认整理

我的猜测是,当涉及的两列的排序规则或字符集不完全相同时,不能轻易比较外键的列,并且不支持引用完整性。

进一步调查

接下来,我运行SHOW FULL COLUMN以显示相关列的详细信息。

Field           Type            Collation          Null    Key
idTips          varchar(45)     latin1_swedish_ci  NO      PRI
...
Tips_idTips     varchar(45)     latin1_bin         NO      PRI

为什么校对有差异?

当我进一步阅读character sets and collations on columns时,MySQL文档说:

  
      
  • 如果指定了CHARACTER SET X而没有COLLATE,则使用字符集X及其默认排序规则。
  •   
  • 如果指定COLLATE Y而没有CHARACTER SET,则使用与Y和排序规则Y关联的字符集。
  •   

要查看我运行SHOW COLLATION的默认排序规则和关联字符集:

Collation               Charset Id      Default Compiled        Sortlen
...
latin1_german1_ci       latin1  5               Yes             1
latin1_swedish_ci       latin1  8       Yes     Yes             1
latin1_danish_ci        latin1  15              Yes             1
latin1_german2_ci       latin1  31              Yes             2
latin1_bin              latin1  47              Yes             1
latin1_general_ci       latin1  48              Yes             1
latin1_general_cs       latin1  49              Yes             1
latin1_spanish_ci       latin1  94              Yes             1
...

现在我们可以看到MySQL将Tips.idTips列的排序规则解析为latin1_swedish_ci,因为这是显式设置的latin1字符集的默认排序规则。

排序规则将由字符集解析,而不是从表继承,因为字符集是在列上显式设置的。这正是文档中指定的方式,因此这可能是期望的行为。

更进一步

现在我知道Tips.idTips列的排序规则是latin1_swedish_ci。因此,我认为我还可以将排序规则更改为Tips_has_SEntences.Tips_idTips,而不是显式更改latin1_swedish_ci列的字符集。

`Tips_idTips` VARCHAR(45) COLLATE latin1_swedish_ci NOT NULL,

这也有效 有趣的是,SHOW CREATE TABLE现在说该列是/应该用这一行创建的:

`Tips_idTips` varchar(45) CHARACTER SET latin1 NOT NULL,

结论

字符集,整理外键一起是地狱 当我有选择时,我更喜欢外键的整数列,而不是字符串/文本类型。现在我知道为什么:)

查看您发布的代码,这似乎是数据库中所有“旧”表的问题,因为所有文本列似乎都明确定义了字符集latin1