Search code examples
mysqlsqldatabasemariadbworkbench

foreign key constraint is incorrectly formed, but both foreign and reference key column are identical


I was doing a "reverse engineer" from MySQL Workbench to a MariaDB database. When I perform reverse engineer, I got an error of "foreign key constraint is incorrectly formed" on the pivot table, even though both reference and foreign keys has identitcal properties and attributes.

I have 3 tables with 2 being independent tables that has many-to-many relationship using pivot table. The tables are users table, certificates table, and users_has_certificates pivot table. Both users and certificates tables uses id with identitcal types, that is BIGINT(20), NOT NULL, UNSIGNED, and AUTO_INCREMENT. However, I get the error of constraint is incorrectly formed when generating the pivot table.

When running SHOW ENGINE INNODB STATUS, it displays this error specifically.

LATEST FOREIGN KEY ERROR
------------------------
2021-03-15 21:09:31 0x5a8 Error in foreign key constraint of table `database_this`.`if`:

    FOREIGN KEY (`certificate_id`)
    REFERENCES `database_this`.`certificates` (`id`)
    ON DELETE NO ACTION
    ON UPDATE NO ACTION)
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8mb4
COLLATE = utf8mb4_unicode_ci:
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.
Please refer to https://mariadb.com/kb/en/library/foreign-keys/
for correct foreign key definition.
Create table `database_this`.`if` with foreign key constraint failed.
Field type or character set for column 'certificate_id' does not
mach referenced column 'id' near '
    FOREIGN KEY (`certificate_id`)
    REFERENCES `database_this`.`certificates` (`id`)
    ON DELETE NO ACTION
    ON UPDATE NO ACTION)
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8mb4
COLLATE = utf8mb4_unicode_ci'.

Here is the SQL code for generating each tables.

users table:

CREATE TABLE IF NOT EXISTS `database_this`.`users` (
  `id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
  `name` VARCHAR(255) NOT NULL,
  `email` VARCHAR(255) NOT NULL,
  `password` VARCHAR(255) NOT NULL,
  `created_at` TIMESTAMP NULL DEFAULT NULL,
  `updated_at` TIMESTAMP NULL DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE INDEX `users_name_unique` (`name` ASC),
  UNIQUE INDEX `users_email_unique` (`email` ASC))
ENGINE = InnoDB
AUTO_INCREMENT = 2
DEFAULT CHARACTER SET = utf8mb4
COLLATE = utf8mb4_unicode_ci;

certificates table:

CREATE TABLE IF NOT EXISTS `database_this`.`certificates` (
  `id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
  `name` VARCHAR(255) NOT NULL,
  `desc` TEXT NULL DEFAULT NULL,
  `certifiable_type` VARCHAR(255) NOT NULL,
  `certifiable_id` BIGINT(20) UNSIGNED NOT NULL,
  `created_at` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP(),
  `updated_at` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP(),
  `deleted_at` TIMESTAMP NULL DEFAULT NULL,
  PRIMARY KEY (`id`))
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8mb4;

users_has_certificates table:

CREATE TABLE IF NOT EXISTS `database_this`.`users_has_certificates` (
  `user_id` BIGINT(20) UNSIGNED NOT NULL,
  `certificate_id` BIGINT(20) UNSIGNED NOT NULL,
  `expired_date` DATE NULL,
  INDEX `fk_users_has_certificates_certificates1_idx` (`certificate_id` ASC),
  INDEX `fk_users_has_certificates_users1_idx` (`user_id` ASC),
  CONSTRAINT `fk_users_has_certificates_users1`
    FOREIGN KEY (`user_id`)
    REFERENCES `database_this`.`users` (`id`)
    ON DELETE NO ACTION
    ON UPDATE NO ACTION,
  CONSTRAINT `fk_users_has_certificates_certificates1`
    FOREIGN KEY (`certificate_id`)
    REFERENCES `database_this`.`certificates` (`id`)
    ON DELETE NO ACTION
    ON UPDATE NO ACTION)
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8mb4
COLLATE = utf8mb4_unicode_ci;

Solution

  • Apparently, MySQL Workbench didn't like reverse engineering some tables if there are already similiar tables inside the original database. The solution is to drop all tables inside the database so that the database is empty, then perform reverse engineer to that database. I'll mark this one as resolved.