MySQL drop unique key: needed in a foreign key constraint - mysql

Hello I`ve a table which look like this
CREATE TABLE `ratings` (
`id` bigint NOT NULL,
`profile_id` bigint NOT NULL,
`stars` enum('1','2','3','4','5') CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
`email` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
`token` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
`deleted_at` timestamp NULL DEFAULT NULL,
`created_at` timestamp NULL DEFAULT NULL,
`updated_at` timestamp NULL DEFAULT NULL,
`survey_id` bigint DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `ratings_profile_id_email_unique` (`profile_id`,`email`),
UNIQUE KEY `ratings_token_unique` (`token`),
KEY `survey_id` (`survey_id`),
CONSTRAINT `ratings_ibfk_1` FOREIGN KEY (`survey_id`) REFERENCES `surveys` (`id`),
CONSTRAINT `ratings_profile_id_foreign` FOREIGN KEY (`profile_id`) REFERENCES `profiles` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
My goal is to delete the ratings_profile_id_email_unique key. I tried this statement
alter table ratings drop key ratings_profile_id_email_unique;
This produces: Cannot drop index 'ratings_profile_id_email_unique': needed in a foreign key constraint
What is wrong? How can a unique key needed in a fk constraint?

In SQL, in general, a foreign key constraint can refer to either a primary key or a unique key. MySQL extends this to any indexed column(s), but that is not relevant here.
Somewhere in your data model, you have a foreign key reference using these two keys instead of id. You need to fix such references in order to delete the index.
If you don't know where this is, you can use the information_schema tables, such as information_schema.referential_constraints and information_schema.key_column_usage.
For instance, this gets foreign key constraints that reference t:
select *
from information_schema.referential_constraints rc
where rc.referenced_table_name = 't'
(You may want to include the schema in them.) This is probably enough information, but if you need more key_column_usage can be more specific on the keys being used.

Related

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;
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.

Error 1215 on adding foreign key. Help me with what I haven't tried

I'm trying to set a foreign key relationship between two existing table but for some reason which I'm missing I keep getting this error 1215.
The relevant fields of the two tables are:
CREATE TABLE `approvals` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`id_contract` int(11) NOT NULL,
`id_user` int(11) NOT NULL,
`lang` varchar(8) NOT NULL,
`request_ts` datetime NOT NULL,
`version` int(11) NOT NULL,
-- more nullable columns here with no indexing/relationships
PRIMARY KEY (`id`),
KEY `approval_id_user` (`id_user`),
KEY `version` (`version`,`lang`,`id_contract`),
CONSTRAINT `approval_id_user` FOREIGN KEY (`id_user`)
REFERENCES `users` (`iduser`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=1079 DEFAULT CHARSET=utf8
CREATE TABLE `version` (
`idversion` int(11) NOT NULL,
`idcontract` int(11) NOT NULL,
`language` varchar(8) NOT NULL,
PRIMARY KEY (`idversion`,`idcontract`,`language`),
KEY `fk_version_contracts_idx` (`idcontract`),
CONSTRAINT `fk_kidversion_contracts` FOREIGN KEY (`idcontract`)
REFERENCES `contracts` (`id_contract`)
ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=utf8
What have I tried
First thing I checked is the persistency:
SELECT * FROM approvals a
WHERE NOT EXISTS (
SELECT 1 FROM version v
WHERE v.idcontract = a.id_contract AND v.language = a.lang
AND v.idversion = a.version);
which resulted in 0 rows returned out of 701, ok my db should be good from the data pov.
So I checked the collation and for some reason the version table was latin1 vs utf8_generic_ci, ok so I restored the version table to utf8 with this.
ALTER TABLE `kidversion`
COLLATE = utf8_general_ci;
-- and for good measure
ALTER TABLE `kidversion`
CHANGE COLUMN `language` `language` VARCHAR(8)
CHARACTER SET 'utf8' COLLATE 'utf8_general_ci' NOT NULL;
But at this point I'm still getting an error while trying to create the foreign key:
ALTER TABLE `approvals`
ADD CONSTRAINT `approval_ibfk_1`
FOREIGN KEY (`version` , `lang` , `id_contract`)
REFERENCES `version` (`idversion` , `language` , `idcontract`)
ON DELETE NO ACTION
ON UPDATE NO ACTION;
And that results in a 1215 in every step I made. Surely I'm missing something.. can anyone help me out with this?
FOREIGN KEY (version , lang , id_contract) REFERENCES version (idversion , language , idcontract) AND PRIMARY KEY (idversion,idcontract,language) don't match fields have to be in the same order as well as same type.
'In the referencing table, there must be an index where the foreign key columns are listed as the first columns in the same order.' - https://dev.mysql.com/doc/refman/5.6/en/create-table-foreign-keys.html

Fail on foreign constraint key

I'm trying to create a foreign key between the field review_id in table Reviews and id in table Sentences. The structure of the tables is the following:
CREATE TABLE `Reviews` (
`review_id` varchar(255) CHARACTER SET utf8 NOT NULL,
`package_name` varchar(255) CHARACTER SET utf8 DEFAULT NULL,
`review_content` text CHARACTER SET utf8,
`review_date` date DEFAULT NULL,
`star_rating` int(11) DEFAULT NULL,
`app_version_id` int(11) NOT NULL,
PRIMARY KEY (`review_id`),
KEY `app_version_id` (`app_version_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE `Sentences` (
`id` varchar(255) NOT NULL DEFAULT '',
`review` text,
`category` varchar(255) DEFAULT NULL,
`topic` varchar(255) DEFAULT NULL,
KEY `rev-id` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
I'm facing with the following error and I don't understand what the problem could be.
ALTER TABLE `Reviews` ADD CONSTRAINT `rev-to-sents` FOREIGN KEY (`review_id`) REFERENCES `Sentences` (`id`)
Foreign key constraint fails for table `msr test db`.`#sql-75_d`:
,
CONSTRAINT `rev-to-sents` FOREIGN KEY (`review_id`) REFERENCES `Sentences` (`id`)
Trying to add in child table, in index PRIMARY tuple:
DATA TUPLE: 8 fields;
0: len 36; hex 37626532323335652d616663392d313165362d383935342d633462333031636466363237; asc 7be2235e-afc9-11e6-8954-c4b301cdf627;;
...
The problem sounds like you are trying to add a foreign key with rows that don't match. If so your first task is to find the non-matching rows and determine the scope of the problem In other words you have cases where Reviewes.review_id does not match any value in Sentences.id
You need to find and fix your data first. This means:
SELECT review_id FROM Reviews
LEFT JOIN Sentences ON review_id = Sentences.id
WHERE Sentences.id IS NULL;
Since you have a NOT NULL constraint on Sentences.id, only when the join condition fails, will the id be null.
Try this:
ALTER TABLE Reviews
ADD CONSTRAINT rev-to-sents
ADD FOREIGN KEY (review_id)
REFERENCES Sentences (id)

Foreign key constraint is incorrectly formed?

I got this error when create table: Foreign key constraint is incorrectly formed?
create table comment(
Comment_ID int UNSIGNED AUTO_INCREMENT not null,
User_1 varchar(50) not null,
Note_ID int(11) UNSIGNED not null,
PRIMARY key(Comment_ID),
CONSTRAINT `fk_1` FOREIGN KEY (`User_1`) REFERENCES `user` (`Dev_ID`),
CONSTRAINT `fk_2` FOREIGN KEY (`User_2`) REFERENCES `user` (`Dev_ID`),
CONSTRAINT `fk_3` FOREIGN KEY (`Note_ID`) REFERENCES `note`(`Note_ID`)
)ENGINE=InnoDB DEFAULT CHARSET=utf8;
it's OK when I remove fk_3.
This my note table
CREATE TABLE `note` (
`Dev_ID` varchar(50) NOT NULL,
`Note_ID` int(11) UNSIGNED NOT NULL,
`Title` varchar(200) NOT NULL,
`Time` datetime NOT NULL,
`Mood` int(11) NOT NULL,
`Body` varchar(3000) NOT NULL,
`Visible` tinyint(1) NOT NULL DEFAULT '1',
`Share` tinyint(1) NOT NULL DEFAULT '0',
`Update` tinyint(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`Dev_ID`,`Note_ID`),
CONSTRAINT `fk_note_user` FOREIGN KEY (`Dev_ID`)
REFERENCES `user` (`Dev_ID`) ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8
Thanks for help!
That's because the primary key of the note table is (Dev_ID,Note_ID) but you are only referencing one of those columns (Note_ID) in your constraint.
A FK constraint must always consist of all PK columns.
Also make sure that both tables are innoDB.
In addition to the answers that have been given, you would also get this error if the field types did not match. For example, if you tried to create a foreign key constraint between a varchar field and an int field.
This problem occur because the column
`Note_ID` int(11) UNSIGNED NOT NULL
Is neither primary nor unique.
Just make it
`Note_ID` int(11) UNSIGNED NOT NULL UNIQUE
And it will work.
One more addition: charsets of the fields must match.
In the referenced table I had ascii as a default charset: DEFAULT CHARSET=ascii was reported by show create table. I tried to create the referencing table with DEFAULT CHARSET=utf and I got 'Foreign key constraint is incorrectly formed'.
After I changed this to DEFAULT CHARSET=ascii on the new table (the referencing one), it was created successfully.
Ensure the collation is the same on both fields. I had the same problem when one was latin-general-ci and the other was utf8_unicode_ci. Not sure why the collation changed on the one table but fixing this resolved the issue.

What is the difference between these two SQL queries?

I've created table Address with this SQL query:
CREATE TABLE `address` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`Street` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`Number` smallint(6) DEFAULT NULL,
`other_id` bigint(20) NOT NULL,
PRIMARY KEY (`id`),
FOREIGN KEY (`other_id`) REFERENCES `other` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
But there's also this query:
CREATE TABLE `address` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`Street` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`Number` smallint(6) DEFAULT NULL,
`other_id` bigint(20) NOT NULL,
PRIMARY KEY (`id`),
KEY `other_id` (`other_id`),
CONSTRAINT `adress_ibfk_1` FOREIGN KEY (`other_id`) REFERENCES `other` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci$$
and it seems that booth query create identical tables.
So can anyone explain to me what does this line do:
KEY `other_id` (`other_id`),
and what is the difference between these two lines:
FOREIGN KEY (`other_id`) REFERENCES `other` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
and
CONSTRAINT `adress_ibfk_1` FOREIGN KEY (`other_id`) REFERENCES `other` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
If the difference between last two lines is that latter gives name 'adress_ibfk_1' to foreign key ? If that's true - should I do it ? I mean, why should I name foreign keys ? Will I ever need their names ?
Thanks ! :)
MySQL interprets KEY as an index, so the second query creates an index on the column other_id.
The difference between the two FK declaration is that you manually set the name in the second line. In the first line, MySQL automatically sets a name.
They do need names, but you don't necessarily have to be aware of them. Some more advanced RDBMS use them to be more explicit when a query raises an error.
KEY is a synonym for INDEX, so that is creating an index on the other_id column.
The only difference in the foreign key construction is that the latter constraint version allows you to name the constraint, whereas the former will be given a system generated name.
This name can be seen in the INFORMATION_SCHEMA TABLE_CONSTRAINTS table.