I am learning about relational databases and I have a problem when relating two tables with a helper with a many-to-many relationship.
I am trying to relate two tables that have a varchar field as primary key generating an auxiliary table but it gives me an errorCannot add foreign key constraint
I have a series of doubts: 1º Is it possible to make this relationship with a varchar field type? I have tested it by changing the fields to INT and it works correctly.
2º I have tried to relate a table with another from 1 to many and with the varchar data type if it works.
Attached image of the model. Thank you and greetings.
EDIT1:
I copy the creation is the sentence.
-- MySQL Workbench Forward Engineering
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';
-- -----------------------------------------------------
-- Schema inver
-- -----------------------------------------------------
-- -----------------------------------------------------
-- Schema inver
-- -----------------------------------------------------
CREATE SCHEMA IF NOT EXISTS `inver` DEFAULT CHARACTER SET utf8 ;
USE `inver` ;
-- -----------------------------------------------------
-- Table `inver`.`users`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `inver`.`users` (
`id_user` INT(11) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(45) NULL DEFAULT NULL,
`surname` VARCHAR(45) NULL DEFAULT NULL,
`email` VARCHAR(45) NULL DEFAULT NULL,
`password` VARCHAR(230) NULL DEFAULT NULL,
`role` VARCHAR(45) NULL DEFAULT NULL,
PRIMARY KEY (`id_user`))
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8;
-- -----------------------------------------------------
-- Table `inver`.`greenhouse`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `inver`.`greenhouse` (
`fiwareServicePath` VARCHAR(45) NOT NULL,
`metros` VARCHAR(45) NULL,
`lugar` VARCHAR(45) NULL,
`users_id_user` INT(11) NOT NULL,
INDEX `fk_greenhouse1_users1_idx` (`users_id_user` ASC),
PRIMARY KEY (`fiwareServicePath`),
CONSTRAINT `fk_greenhouse1_users1`
FOREIGN KEY (`users_id_user`)
REFERENCES `inver`.`users` (`id_user`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `inver`.`sensors`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `inver`.`sensors` (
`entityId` VARCHAR(45) NOT NULL,
`sensor_name` VARCHAR(45) CHARACTER SET 'utf8' COLLATE 'utf8_spanish_ci' NULL DEFAULT NULL,
PRIMARY KEY (`entityId`))
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8
COLLATE = utf8_spanish_ci;
-- -----------------------------------------------------
-- Table `inver`.`sensors_has_greenhouse`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `inver`.`sensors_has_greenhouse` (
`sensors_entityId` VARCHAR(45) NOT NULL,
`greenhouse_fiwareServicePath` VARCHAR(45) NOT NULL,
PRIMARY KEY (`greenhouse_fiwareServicePath`, `sensors_entityId`),
INDEX `fk_sensors_has_greenhouse_greenhouse1_idx` (`greenhouse_fiwareServicePath` ASC),
INDEX `fk_sensors_has_greenhouse_sensors1_idx` (`sensors_entityId` ASC),
CONSTRAINT `fk_sensors_has_greenhouse_sensors1`
FOREIGN KEY (`sensors_entityId`)
REFERENCES `inver`.`sensors` (`entityId`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `fk_sensors_has_greenhouse_greenhouse1`
FOREIGN KEY (`greenhouse_fiwareServicePath`)
REFERENCES `inver`.`greenhouse` (`fiwareServicePath`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8
COLLATE = utf8_spanish_ci;
SET SQL_MODE=@OLD_SQL_MODE;
SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;
EDIT2
I add the error:
Executing SQL script in server
ERROR: Error 1215: Cannot add foreign key constraint
SQL Code:
-- -----------------------------------------------------
-- Table `inver`.`sensors_has_greenhouse`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `inver`.`sensors_has_greenhouse` (
`sensors_entityId` VARCHAR(45) NOT NULL,
`greenhouse_fiwareServicePath` VARCHAR(45) NOT NULL,
PRIMARY KEY (`greenhouse_fiwareServicePath`, `sensors_entityId`),
INDEX `fk_sensors_has_greenhouse_greenhouse1_idx` (`greenhouse_fiwareServicePath` ASC),
INDEX `fk_sensors_has_greenhouse_sensors1_idx` (`sensors_entityId` ASC),
CONSTRAINT `fk_sensors_has_greenhouse_sensors1`
FOREIGN KEY (`sensors_entityId`)
REFERENCES `inver`.`sensors` (`entityId`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `fk_sensors_has_greenhouse_greenhouse1`
FOREIGN KEY (`greenhouse_fiwareServicePath`)
REFERENCES `inver`.`greenhouse` (`fiwareServicePath`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8
COLLATE = utf8_spanish_ci
SQL script execution finished: statements: 8 succeeded, 1 failed
Fetching back view definitions in final form.
Nothing to fetch
The error is that the related tables do not have the same property
COLLATE
.The documentation says the following about it:
So the tables:
sensors
andsensors_has_greenhouse
have the followingCOLLATE
in theCREATE TABLE
:But
sensors_has_greenhouse
it is related to tablegreenhouse
, which does not haveCOLLATE = utf8_spanish_ci
.Two non-binary columns (columns of type String such as
VARCHAR
) cannot participate in a relationship between tables if they have differentCOLLATE
. That is precisely what happens in your case.Solution
Either you grant
COLLATE = utf8_spanish_ci
the tablegreenhouse
(alreadyusers
, because otherwise you would have the same problem between the latter two), or you remove theCOLLATE = utf8_spanish_ci
from the two tables that have it.I have done a proof of concept correcting those details and it has not thrown me the error:
What if it still fails?
Since you have been running a
CREATE TABLE
before, some of the tables may have already been created, before the relationship creation failed. So you have several possibilities.The simplest, if your tables are new and don't already have data , would be to run one
DROP TABLE IF EXISTS ...nombre-de-tabla...
of each of them, before theCREATE TABLE
to start over. But run that only once , to prevent your tables from being created all over again with the correct settings.Either you can modify the COLLATE through another type of query such as
ALTER TABLE
, or directly in the graphical interface of your DBMS.Note:
In general, it is not recommended to relate the tables using columns of type
VARCHAR
. To do this you must be very sure that this value uniquely represents each record. And they also have to assess the cost that this may entail in terms of database performance.Always use relationships with a numeric identifier, it is much better at sorting the data in the NM table. Yes, it is possible, as you have been told, but it is not the most recommended, in addition to the fact that it would not have much logic since you want that when you see that table there is a logical order of the data, and you achieve that by ordering that relation with a ID that brings together both foreign keys.
A quick example I have lying around of NM table: