MYSQL creates index automatically when - mysql

I have the following main table:
CREATE TABLE IF NOT EXISTS `table_1` (
`id` BIGINT UNSIGNED NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
And the following table:
CREATE TABLE IF NOT EXISTS `table_2` (
`id_1` BIGINT UNSIGNED NOT NULL,
`id_2` BIGINT UNSIGNED NOT NULL,
PRIMARY KEY (`id_1`,`id_2`),
FOREIGN KEY (`id_1`) REFERENCES table_1(`id`) ON DELETE CASCADE,
FOREIGN KEY (`id_2`) REFERENCES table_2(`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
For some reason when creating the above tables, I get the following index created automatically by MYSQL:
Keyname Type Unique Packed Column Cardinality Collation Null
id_2 BTREE No No id_2 94695 A No
So MYSQL is creating an index on the second column called id_2 in table_2. Strange enough, it's not created on both foreign keys and if I create only 1 foreign key, MYSQL wouldn't create an index like this.
I tried to drop the index and got the following error:
Cannot drop index 'id_2': needed in a foreign key constraint
So why does MYSQL need to create an index like this and why it's created on both keys??

Unlike other databases, MySQL creates indexes for foreign key constraints. As explained in the documentation:
index_name represents a foreign key ID. The index_name value is
ignored if there is already an explicitly defined index on the child
table that can support the foreign key. Otherwise, MySQL implicitly creates a foreign key index that is named according to the following rules:
. . .
In your case, one of the foreign key declarations is handled by the primary key index, because id_1 is the first key in both of them.

Related

Why does MySQL Workbench automatically create multiple keys when creating relationships between tables?

Check out the image below. In the movie_custom table you'll see that when I added a 1:m relationship between plist_field and movie_custom, MySQL Workbench added keys for the attached tables of plist_type and plist_view_type in additional to the key I was expecting.
Why is that?
Can/should I remove them?
Or if I should keep them, how do I auto-insert the key values from the deeper tables when doing an insert into movie_custom and I know a key of plist_field?
If we execute this schema creation:
create table parent
( pid int auto_increment primary key,
theirName varchar(100) not null
);
drop table if exists child;
create table child
( cid int auto_increment primary key,
theirName varchar(100) not null,
pid int not null,
foreign key `fk_c2p` (pid) references parent(pid)
);
Examine what happened to the child:
mysql> show create table child \G;
CREATE TABLE `child` (
`cid` int(11) NOT NULL AUTO_INCREMENT,
`theirName` varchar(100) NOT NULL,
`pid` int(11) NOT NULL,
PRIMARY KEY (`cid`),
KEY `fk_c2p` (`pid`), -- ******************** AUTO created by mysql
CONSTRAINT `child_ibfk_1` FOREIGN KEY (`pid`) REFERENCES `parent` (`pid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
From the manual page Using FOREIGN KEY Constraints:
... index_name represents a foreign key ID. The index_name value is
ignored if there is already an explicitly defined index on the child
table that can support the foreign key. Otherwise, MySQL implicitly
creates a foreign key index that is named according to the following
rules:
If defined, the CONSTRAINT symbol value is used. Otherwise, the
FOREIGN KEY index_name value is used.
If neither a CONSTRAINT symbol or FOREIGN KEY index_name is defined,
the foreign key index name is generated using the name of the
referencing foreign key column.
So, back to your questions.
A. Why are they created? They are created because mysql creates them as specified above. They facilitate speedy reversal lookups. When a parent row is to be deleted, a fast non-table scan of children is mandated to allow or disallow the parent row removal. The auto-generated key (or one already satisfying it) is used for this purpose.
B. Should you delete them? No. Why not? Read A.
C. How do you "auto-insert the key values from the deeper tables": you acquire the id of the parent (anywhere in the hierarchy) ahead of time such as using LAST_INSERT_ID() or other program logic.

MySQL Foreign Keys ALTER statement

MySQL 5.6.16
Two tables. Altering Table 1 to have a foreign key to Table 2's primary key. SQL Error 1215.
If I drop Table 1 and incorporate the foreign key constraint into the build, it accepts the constraint just fine. Only altering the tables after creation causes a problem.
Any ideas? Below are two attempts at writing the alter statement, followed by the creation script.
ALTER TABLE c_users ADD FOREIGN KEY fk_user_prof_position_tid(professional_position_tid) REFERENCES d_taxonomy(tid);
ALTER TABLE c_users ADD CONSTRAINT fk_user_prof_position_tid FOREIGN KEY (professional_position_tid) REFERENCES d_taxonomy(tid);
CREATE TABLE c_users (
user_id INT(11) NOT NULL AUTO_INCREMENT COMMENT 'Primary, auto-generated key',
professional_position_tid INT(11),
...
PRIMARY KEY (user_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE INDEX i_user_id ON c_users (user_id) USING BTREE;
CREATE TABLE d_taxonimy (
tid INT(11) NOT NULL COMMENT '',
...
PRIMARY KEY (tid)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE INDEX i_tid ON d_taxonimy (tid) USING BTREE;
Typos:
ALTER TABLE [...snip...] REFERENCES d_taxonomy(tid);
^----
CREATE TABLE d_taxonimy (
^----
Plus, if you're running the statements in that order, you can't alter a table which doesn't exist yet, or create a foreign key when the foreign field/table don't exist yet either.

MySQL: Can't create table

I tried to create a table in MySQL using the CREATE TABLE statement below:
CREATE TABLE `visit` (
`visit_id` int(11) NOT NULL,
`site_id` int(11) DEFAULT NULL,
PRIMARY KEY (`visit_id`),
CONSTRAINT `FK_visit_site` FOREIGN KEY (`site_id`) REFERENCES `site` (`site_id`),
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
I received this error:
ERROR 1005 (HY000): Can't create table 'fooschema.visit' (errno: 121)
I used SHOW ENGINE INNODB STATUS command. This is the error message:
------------------------
LATEST FOREIGN KEY ERROR
------------------------
140222 7:03:17 Error in foreign key constraint creation for table `fooschema`.`visit`.
A foreign key constraint of name `fooschema/FK_visit_site`
already exists. (Note that internally InnoDB adds 'databasename/'
in front of the user-defined constraint name).
Note that InnoDB's FOREIGN KEY system tables store
constraint names as case-insensitive, with the
MySQL standard latin1_swedish_ci collation. If you
create tables or databases whose names differ only in
the character case, then collisions in constraint
names can occur. Workaround: name your constraints
explicitly with unique names.
Then, I used the query below to list all available constraints:
select *
from information_schema.table_constraints
where constraint_schema = 'fooschema'
I didn't see any constraint with name 'FK_visit_site' in the result.
The FK_visit_site constraint was a foreign key constraint of table visit. I dropped the visit table and attempted to recreate it.
Is there a way I can drop this foreign key constraint even when the table it was associated to doesn't exist?
your foreign key already exist , so either drop existed foreign key or rename your second key.
ALTER TABLE `site` DROP FOREIGN KEY `FK_visit_site`;
or rename to other new one.
CREATE TABLE `visit` (
`visit_id` int(11) NOT NULL PRIMARY KEY,
`site_id` int(11) NOT NULL,
CONSTRAINT `FK_visit_site` FOREIGN KEY (`site_id`) REFERENCES `site` (`site_id`),
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Added PRIMARY KEY to the visit_id line.
Note:
make sure that site_id in the site table have exact same datatype of site_id in visit table.
like that
`site_id` int(11) DEFAULT NULL --//in the `site` table
The two keys you're coupling must have the exact same datatype ( INT NOT NULL), even signedness
AFAIK, you will get this error when you're trying to add a constraint with a name that's already used somewhere else. Means, in your case FK FK_visit_site had already been used before.
If the table you're trying to create includes a foreign key constraint, and you've provided your own name for that constraint, remember that it must be unique within the database.
You can run the below query to find out the same
SELECT
constraint_name,
table_name
FROM
information_schema.table_constraints
WHERE
constraint_type = 'FOREIGN KEY'
AND table_schema = DATABASE()
ORDER BY
constraint_name;
Taken from the post here
http://www.thenoyes.com/littlenoise/?p=81
Try using a different name for your FK like
CREATE TABLE `visit` (
`visit_id` int(11) NOT NULL,
`site_id` int(11) DEFAULT NULL,
PRIMARY KEY (`visit_id`),
CONSTRAINT `FK_visit_site_New` FOREIGN KEY (`site_id`)
REFERENCES `site` (`site_id`),
)

Foreign Key constraints missing after phpmyadmin export

I create a table in mysql using the following script:
CREATE TABLE IF NOT EXISTS users_x_activities(
id int NOT NULL auto_increment,
id_user int unsigned NOT NULL,
id_attivita int unsigned NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (id_user) REFERENCES utente(id),
FOREIGN KEY (id_attivita) REFERENCES attivita(id)
) ENGINE = INNODB;
When I export the created table from phpMyAdmin, I obtain the following script
CREATE TABLE IF NOT EXISTS `users_x_activities` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`id_user` int(10) unsigned NOT NULL,
`id_attivita` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`),
KEY `id_user` (`id_user`),
KEY `id_attivita` (`id_attivita`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
So the question are: where is my foreign key constraints? does KEY refer to FK? Seems that the two tables utente and attivita are no longer referenced in the new generated script. where am I doing wrong?
EDIT
In phpMyAdmin, configuring the export of the table I found the option "Display Foreign Key Relationship"
If I flag this option I otain also this code in the script
--
-- RELATIONS FOR TABLE `users_x_activity`:
-- `id_user`
-- `utente` -> `id`
-- `id_attivita`
-- `attivita` -> `id`
--
--
-- Constraints for dumped tables
--
--
-- Constraints for table `users_x_activity`
--
ALTER TABLE `users_x_activity`
ADD CONSTRAINT `users_x_activities_ibfk_1` FOREIGN KEY (`id_user`) REFERENCES `utente` (`id`),
ADD CONSTRAINT `users_x_activities_ibfk_2` FOREIGN KEY (`id_attivita`) REFERENCES `attivita` (`id`);
This means that if I add the option "Display Foreign Key Relationship" I obtain also the FK constrains? in other case not?
So the question are: where is my foreign key constraints?
They are defined in the database. The output from SHOW CREATE TABLE users_x_activities will include the foreign key constraint definitions.
The definitions of the foreign key constraints likely appear in separate ALTER TABLE statements at the end of the generated script.
does KEY refer to FK?
No. KEY id_user (id_user) here refers to an index.
Seems that the two tables utente and attivita are no longer referenced in the new generated script.
Yes, you are correct. The foreign key constraints are not included in the CREATE TABLE statement.
where am I doing wrong?
A MySQL SHOW CREATE TABLE users_x_activities will include the foreign key constraints.
The foreign key constraints are likely included in the script generated by phpMyAdmin, but at the end of the script, in separate ALTER TABLE statements.
There are two type of constraints when you managing your tables with phpmyadmin:
internal: when you set constraints with phpmyadmin designer for example the constraints stored as internal,that will not be included in export.
innoDB: these constraints included in export check out linked video about it
Setting up a foreign key constraint
Follow the following steps :
phpmyadmin configuration
export time customer configuration

MySQL Cannot drop index needed in a foreign key constraint

I need to ALTER my existing database to add a column. Consequently I also want to update the UNIQUE field to encompass that new column. I'm trying to remove the current index but keep getting the error MySQL Cannot drop index needed in a foreign key constraint
CREATE TABLE mytable_a (
ID TINYINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
Name VARCHAR(255) NOT NULL,
UNIQUE(Name)
) ENGINE=InnoDB;
CREATE TABLE mytable_b (
ID TINYINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
Name VARCHAR(255) NOT NULL,
UNIQUE(Name)
) ENGINE=InnoDB;
CREATE TABLE mytable_c (
ID TINYINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
Name VARCHAR(255) NOT NULL,
UNIQUE(Name)
) ENGINE=InnoDB;
CREATE TABLE `mytable` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`AID` tinyint(5) NOT NULL,
`BID` tinyint(5) NOT NULL,
`CID` tinyint(5) NOT NULL,
PRIMARY KEY (`ID`),
UNIQUE KEY `AID` (`AID`,`BID`,`CID`),
KEY `BID` (`BID`),
KEY `CID` (`CID`),
CONSTRAINT `mytable_ibfk_1` FOREIGN KEY (`AID`) REFERENCES `mytable_a` (`ID`) ON DELETE CASCADE,
CONSTRAINT `mytable_ibfk_2` FOREIGN KEY (`BID`) REFERENCES `mytable_b` (`ID`) ON DELETE CASCADE,
CONSTRAINT `mytable_ibfk_3` FOREIGN KEY (`CID`) REFERENCES `mytable_c` (`ID`) ON DELETE CASCADE
) ENGINE=InnoDB;
mysql> ALTER TABLE mytable DROP INDEX AID;
ERROR 1553 (HY000): Cannot drop index 'AID': needed in a foreign key constraint
You have to drop the foreign key. Foreign keys in MySQL automatically create an index on the table (There was a SO Question on the topic).
ALTER TABLE mytable DROP FOREIGN KEY mytable_ibfk_1 ;
Step 1
List foreign key ( NOTE that its different from index name )
SHOW CREATE TABLE <Table Name>
The result will show you the foreign key name.
Format:
CONSTRAINT `FOREIGN_KEY_NAME` FOREIGN KEY (`FOREIGN_KEY_COLUMN`) REFERENCES `FOREIGN_KEY_TABLE` (`id`),
Step 2
Drop (Foreign/primary/key) Key
ALTER TABLE <Table Name> DROP FOREIGN KEY <Foreign key name>
Step 3
Drop the index.
If you mean that you can do this:
CREATE TABLE mytable_d (
ID TINYINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
Name VARCHAR(255) NOT NULL,
UNIQUE(Name)
) ENGINE=InnoDB;
ALTER TABLE mytable
ADD COLUMN DID tinyint(5) NOT NULL,
ADD CONSTRAINT mytable_ibfk_4
FOREIGN KEY (DID)
REFERENCES mytable_d (ID) ON DELETE CASCADE;
> OK.
But then:
ALTER TABLE mytable
DROP KEY AID ;
gives error.
You can drop the index and create a new one in one ALTER TABLE statement:
ALTER TABLE mytable
DROP KEY AID ,
ADD UNIQUE KEY AID (AID, BID, CID, DID);
A foreign key always requires an index. Without an index enforcing the constraint would require a full table scan on the referenced table for every inserted or updated key in the referencing table. And that would have an unacceptable performance impact.
This has the following 2 consequences:
When creating a foreign key, the database checks if an index exists. If not an index will be created. By default, it will have the same name as the constraint.
When there is only one index that can be used for the foreign key, it can't be dropped. If you really wan't to drop it, you either have to drop the foreign key constraint or to create another index for it first.
Because you have to have an index on a foreign key field you can just create a simple index on the field 'AID'
CREATE INDEX aid_index ON mytable (AID);
and only then drop the unique index 'AID'
ALTER TABLE mytable DROP INDEX AID;
I think this is easy way to drop the index.
set FOREIGN_KEY_CHECKS=0; //disable checks
ALTER TABLE mytable DROP INDEX AID;
set FOREIGN_KEY_CHECKS=1; //enable checks
drop the index and the foreign_key in the same query like below
ALTER TABLE `your_table_name` DROP FOREIGN KEY `your_index`;
ALTER TABLE `your_table_name` DROP COLUMN `your_foreign_key_id`;
Dropping FK is tedious and risky. Simply create the new index with new columns and new index name, such as AID2. After the new Unique Index is created, you can drop the old one with no issue. Or you can use the solution given above to incorporate the "drop index, add unique index" in the same alter table command. Both solutions will work
In my case I dropped the foreign key and I still could not drop the index. That was because there was yet another table that had a foreign key to this table on the same fields. After I dropped the foreign key on the other table I could drop the indexes on this table.
If you are using PhpMyAdmin sometimes it don't show the foreign key to delete.
The error code gives us the name of the foreign key and the table where it was defined, so the code is:
ALTER TABLE your_table DROP FOREIGN KEY foreign_key_name;
You can show Relation view in phpMyAdmin and first delete foreign key. After this you can remove index.
You can easily check it with DBeaver. Example:
As you can see there are 3 FKs but only 2 FK indexes. There is no index for FK_benefCompanyNumber_beneficiaries_benefId as UK index provide uniqueness for that FK.
To drop that UK you need to:
DROP FK_benefCompanyNumber_beneficiaries_benefId
DROP UK
CREATE FK_benefCompanyNumber_beneficiaries_benefId
The current most upvoted answer is not complete.
One needs to remove all the foreign keys whose "source" column is also present in the UNIQUE KEY declaration.
So in this case, it is not enough to remove mytable_ibfk_1 for the error to go away, mytable_ibfk_2 and mytable_ibfk_3 must be deleted as well.
This is the complete answer:
ALTER TABLE mytable DROP FOREIGN KEY mytable_ibfk_1;
ALTER TABLE mytable DROP FOREIGN KEY mytable_ibfk_2;
ALTER TABLE mytable DROP FOREIGN KEY mytable_ibfk_3;
Its late now but I found a solution which might help somebody in future.
Just go to table's structure and drop foreign key from foreign keys list. Now you will be able to delete that column.