mysql drop table and cascade delete to all references to the table - mysql

I'm developing a new system from an old system. The new system is using MySQL and java. I want to start with a reduced number of tables. When I delete a table lets say X, how can I cause all references to X to be deleted as well, so if table Y has an FK to table X then on table Y the FK and the column used in the FK get deleted as well?
simplified example:
CREATE TABLE `Y` (
`yID` int(11) NOT NULL AUTO_INCREMENT,
`yName` varchar(50) NOT NULL,
...
) ENGINE=InnoDB;
CREATE TABLE `user` (
`userID` int(11) NOT NULL AUTO_INCREMENT,
`userName` varchar(50) NOT NULL,
`givenName` varchar(50) DEFAULT NULL,
`sourceYID` int(11) NOT NULL,
CONSTRAINT `USER_FK_sourceYID` FOREIGN KEY (`sourceYID`) REFERENCES `Y` (`yID`)
) ENGINE=InnoDB;
I would like to preferably issue one command that will
DROP TABLE `Y`
and on the user table
remove the CONSTRAINT USER_FK_sourceYID
remove the column sourceYID
remove any KEY/INDEX definitions based on sourceYID as well if included (not included in this example)

There is no single command that can do this. The simplest way to handle this is to drop the constraint and then drop the parent table. Without the constraint, you can do this freely.
ALTER TABLE `user` DROP FOREIGN KEY `USER_FK_sourceYID`;
DROP TABLE `Y`;
Dropping the column automatically removes it from any indexes it belongs to. Even if it's a compound index, it leaves an index with the remaining columns. Here are some hypothetical example indexes, and we'll see what happens when we remove the column:
CREATE INDEX y1 ON `user` (sourceYID);
CREATE INDEX y2 ON `user` (userID, sourceYID);
CREATE INDEX y3 ON `user` (sourceYID, userID);
ALTER TABLE `user` DROP COLUMN `sourceYID`;
The result is that index y1 is gone, and both y2 and y3 are reduced to single-column indexes containing just the userID column:
SHOW CREATE TABLE `user`\G
CREATE TABLE `user` (
`userID` int(11) NOT NULL AUTO_INCREMENT,
`userName` varchar(50) NOT NULL,
`givenName` varchar(50) DEFAULT NULL,
PRIMARY KEY (`userID`),
KEY `y2` (`userID`),
KEY `y3` (`userID`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
Therefore these two are now identical indexes, and you should run pt-duplicate-key-checker to analyze your schema for such cases.

SET FOREIGN_KEY_CHECKS = 0;
drop table if exists <your_1st_table>;
drop table if exists <your_2nd_table>;
SET FOREIGN_KEY_CHECKS = 1;

If you have a foreign key, then you wan't be able to remove parent table, the foreign key relation won't allow it. To do this you should do these steps:
remove all children records, there are two ways: using ON DELETE CASCADE foreign key option, or using multi-table DELETE statement.
remove foreign key if it exists.
drop parent table.

Related

Drop foreign key MySQL does not exist

I have a table in MySQL like this (this is returned from using show create table user_org_contacts):
CREATE TABLE `user_org_contacts` (
`user_org_contacts_id` int(11) NOT NULL AUTO_INCREMENT,
`from_user_id` int(11) DEFAULT NULL,
`to_org_user_id` int(11) DEFAULT NULL,
`suggested_vacancy_id` int(11) DEFAULT NULL,
`contact_date` datetime NOT NULL,
`message` text,
PRIMARY KEY (`user_org_contacts_id`),
KEY `FK_Reference_53` (`from_user_id`),
KEY `FK_Reference_54` (`to_org_user_id`),
KEY `FK_Reference_55` (`suggested_vacancy_id`)
) ENGINE=InnoDB AUTO_INCREMENT=18 DEFAULT CHARSET=latin1
I have noticed that my FK_Reference_54 is wrong and points to the wrong table. So I would like to change this one by the correct FK.
This is what I tried:
ALTER TABLE `user_org_contacts`
DROP FOREIGN KEY `FK_Reference_54`;
ALTER TABLE `user_org_contacts`
ADD CONSTRAINT `FK_Reference_54`
FOREIGN KEY (`to_org_user_id`) REFERENCES `users` (`user_id`) ON DELETE CASCADE;
This produces the following error:
1091 - Can't DROP 'FK_Reference_54'; check that column/key exists
The problem is that you are confusing indexes with primary keys.
The keyword KEY is actually showing you indexes while primary keys use the keywords CONSTRAINT ... FOREIGN KEY ...
Example:
CONSTRAINT `FK_name` FOREIGN KEY (`current_field_name`)
REFERENCES `external_table_name` (`external_field_name`) ON DELETE CASCADE ON UPDATE CASCADE
So in your case, if you want to remove your INDEX you just need to call this query
ALTER TABLE `user_org_contacts`
DROP INDEX `FK_Reference_54`;
Next time I suggest you using some UI for mysql like mysql workbench, with that you would have noticed the issue immediatly.
First Try To remove that column
ALTER TABLE tablename DROP COLUMN columname;
Then:
ALTER TABLE tablename ADD columnname datatype.
Or you can try this Modify option like.
ALTER TABLE tablename MODIFY COLUMN columnname datatype;
Hope This will help you.

Issues with creating a foreign key

I'm having issues with setting up a relation between 2 tables called Customer and Customer_Number. I have both tables set to InnoDB both have indexes, but when I go to create the foreign key, I get a "no index defined" error. Below are some screen shots
Here Is the Customer table.
Here is the Customer_Number table.
And here is my error message when trying to create the foreign key.
And lastly, this is the error I get when trying to create the relationship manually.
I just can't seem to figure out the issue, and it's driving me nuts!
the output for SHOW CREATE TABLE Customer is
CREATE TABLE `Customer` (
`Customer_ID` int(11) NOT NULL AUTO_INCREMENT,
`First` varchar(255) NOT NULL,
`Last` varchar(255) NOT NULL,
PRIMARY KEY (`Customer_ID`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1
and the output for SHOW CREATE TABLE Customer_Number is
CREATE TABLE `Customer_Number` (
`Num_ID` int(11) NOT NULL AUTO_INCREMENT,
`Customer_ID` int(11) NOT NULL,
`Number` varchar(255) NOT NULL,
PRIMARY KEY (`Num_ID`),
KEY `Customer_ID` (`Customer_ID`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1
The two CREATE TABLE statements as posted are correct and should be able to accept a new FOREIGN KEY constraint on Customer_Number.Customer_ID since the necessary criteria are met (same data type as referenced column, comparable index or primary key on referenced column).
An ALTER statement succeeds in my testing:
ALTER TABLE Customer_Number ADD FOREIGN KEY (Customer_ID) REFERENCES Customer (Customer_ID);
Being unfamiliar with how PhpMyAdmin abstracts some RDBMS errors, it is hard to say for sure what exactly has gone wrong in the GUI. But if you run the ALTER statement manually and encounter errors about failed foreign key constraints, that's an indication the referencing table already contains values in the column which do not reference a valid row value in the parent table. To uncover those rows so you can address them, execute a query like:
SELECT * FROM Customer_Number WHERE Customer_ID NOT IN (SELECT Customer_ID FROM Customer)
Once you have found the problematic rows, you can either delete them (if unneeded) or update their values to the value of a valid row value in the referenced table. If the column's definition allowed NULL (which yours does not) you could also UPDATE them to set them NULL then run the ALTER statement again.
It is also possible to disable foreign key checks temporarily, add the constraint, update the rows to match valid parent table values, the reenable foreign key checks.
please try this.
alter table Customer_Number add foreign key(customer_ID) references Customer (Customer_ID);

phpMyAdmin throws No Index Defined! even though indexes and PK's exist

UPDATE: I have a ticket into my hosting provider (FatCow) as they are able to duplicate the issue. I will post any conclusions here.
I have a MySQL database like so:
table || pk
-----------
performers -> pID
genres -> gID
venues -> vID
I also have an events table that looks something like this:
eID (PK)
ePerformer (INDEX)
eGenre (INDEX)
eVenue (INDEX)
They are all the same type: INT(11). All of the tables are InnoDB. I want to setup the relationships in phpMyAdmin using the Relation View on the events table, but when I try to save:
ePerformer: performers->pID ON DELETE RESTRICT, ON UPDATE RESTRICT
eGenre: genres->gID ON DELETE RESTRICT, ON UPDATE RESTRICT
etc...
I get this error back for each field: No index defined!
I thought perhaps I was doing it backwards, so I tried setting each relationship from the other tables but I'm getting the same error.
What gives?
Using a similar structure I am able to create the relations. You've already checked several of the obvious things (primary key on the referenced keys, InnoDB, etc).
When I first created the events table, using the phpMyAdmin dropdown to select INDEX for each of the three fields you indicate, it created a composite index on all three fields, which didn't work; I had to remove that index and manually create an INDEX on each field individually.
The composite index:
The working individual indexes:
You could try the Designer feature (which requires you to set up the "phpMyAdmin configuration storage"); I find it superior to the Relation View when manipulating relations.
From the events table (I know, you already said you were on the proper table), click the Structure tab and next the Relation View link, you should be able to do this:
In this case I had already created the events_ibfk_1 relationship through Designer and fk_venue through Relation View; this screenshot was taken just prior to creating the fk_performer one so what you see here is exactly what I had in place before clicking "Save".
Not sure if that helps any, but I'm able to do it with what you've provided...so maybe if it still doesn't work you can export your complete existing table structure and I'll try to make that work.
For what it's worth, here's the export of the table structure I had working:
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
SET time_zone = "+00:00";
CREATE TABLE IF NOT EXISTS `events` (
`eID` int(11) NOT NULL,
`ePerformer` int(11) NOT NULL,
`eGenre` int(11) NOT NULL,
`eVenue` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE IF NOT EXISTS `genres` (
`gID` int(11) NOT NULL,
`g` varchar(255) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE IF NOT EXISTS `performers` (
`pID` int(11) NOT NULL,
`p` varchar(255) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE IF NOT EXISTS `venues` (
`vID` int(11) NOT NULL,
`v` varchar(255) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
ALTER TABLE `events`
ADD PRIMARY KEY (`eID`), ADD KEY `i_perf` (`ePerformer`), ADD KEY `i_genre` (`eGenre`), ADD KEY `i_venue` (`eVenue`);
ALTER TABLE `genres`
ADD PRIMARY KEY (`gID`);
ALTER TABLE `performers`
ADD PRIMARY KEY (`pID`);
ALTER TABLE `venues`
ADD PRIMARY KEY (`vID`);
ALTER TABLE `events`
ADD CONSTRAINT `fk_performer` FOREIGN KEY (`ePerformer`) REFERENCES `performers` (`pID`),
ADD CONSTRAINT `events_ibfk_1` FOREIGN KEY (`eGenre`) REFERENCES `genres` (`gID`),
ADD CONSTRAINT `fk_venue` FOREIGN KEY (`eVenue`) REFERENCES `venues` (`vID`);

mysql alter int column to bigint with foreign keys

I want to change the datatype of some primary-key columns in my database from INT to BIGINT. The following definition is a toy-example to illustrate the problem:
CREATE TABLE IF NOT EXISTS `owner` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`thing_id` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `thing_id` (`thing_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ;
DROP TABLE IF EXISTS `thing`;
CREATE TABLE IF NOT EXISTS `thing` (
`id` int(11) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ;
ALTER TABLE `owner`
ADD CONSTRAINT `owner_ibfk_1` FOREIGN KEY (`thing_id`) REFERENCES `thing` (`id`);
Now when i try to execut one of the following commands:
ALTER TABLE `thing` CHANGE `id` `id` BIGINT NOT NULL AUTO_INCREMENT;
ALTER TABLE `owner` CHANGE `thing_id` `thing_id` BIGINT NOT NULL;
i'm running into an error
#1025 - Error on rename of './debug/#[temp-name]' to './debug/[tablename]' (errno: 150)
SHOW INODB STATUS outputs:
LATEST FOREIGN KEY ERROR
------------------------
120126 13:34:03 Error in foreign key constraint of table debug/owner:
there is no index in the table which would contain
the columns as the first columns, or the data types in the
table do not match the ones in the referenced table
or one of the ON ... SET NULL columns is declared NOT NULL. Constraint:
,
CONSTRAINT "owner_ibfk_1" FOREIGN KEY ("thing_id") REFERENCES "thing" ("id")
I'm guessing that the foreign key definition blocks changing the column type on either side. The naive approach to solve this problem would be to delete the foreign key definitions, alter the columns and re-define the foreign keys. is there a better solution?
Even with SET foreign_key_checks = 0, you can't alter the type of the constraint column.
From MySQL doc : http://dev.mysql.com/doc/refman/5.5/en/innodb-foreign-key-constraints.html
However, even if foreign_key_checks = 0, InnoDB does not permit the creation of a foreign key constraint where a column references a nonmatching column type.
So, I agree with the comment of Devart. Just drop it and create it again.
I could suggest you to rename such fields in GUI tool - dbForge Studio for MySQL (free trial edition):
Just select the field you want to rename in the Database Explorer, click on Refactoring->Rename command, enter new name in openned window, and press OK, it will rename the field and recreate all foreign keys automatically.
Even though you changed the column size of id and thing_id, the raw data in the rows is still 4 byte integers instead of 8 byte integers. But you can convert the data.
Try this solution instead. I had to do something similar recently on a large data set, converting INT columns to BIGINT when the data set threatened to grow too large.
ALTER TABLE `owner`
DROP FOREIGN KEY `owner_ibfk_1`;
ALTER TABLE `thing` CHANGE `id` `id` BIGINT NOT NULL AUTO_INCREMENT;
ALTER TABLE `owner` CHANGE `thing_id` `thing_id` BIGINT NOT NULL;
UPDATE `thing` SET `id` = CAST(`id` AS UNSIGNED INTEGER);
UPDATE `owner` SET `thing_id` = CAST(`thing_id` AS UNSIGNED INTEGER);
-- Now the data are BIGINTs; re-create the foreign key constraint
ALTER TABLE `owner`
ADD CONSTRAINT `owner_ibfk_1` FOREIGN KEY (`thing_id`) REFERENCES `thing` (`id`);
I had a similar problem the solution is the change clause:
ALTER TABLE table_name CHANGE id id BIGINT(20) NOT NULL AUTO_INCREMENT;
That worked for me.

Foreign key between MySQL InnoDB tables not working...why?

I have the following tables:
specie (MyIsam)
image (InnoDB)
specie_map (InnoDB)
The specie_map table should map an image to a specie, and therefore has the following columns:
specie_id
image_id
Both are int 11, just like the id columns of the specie and image tables. I know I can't create a foreign key between specie_id and specie=>id, since the specie table is a MyIsam table. However, I would expect it to be possible to create a foreign key between image_id and image=>id.
I can create that foreign key and it will save it, however, the CASCADE action I have associated with it does not work. When I delete an image, it does not delete the specie_map entry that is associated with it. I would expect this to work, as this foreign key is between InnoDB tables. Both columns are indexed and of the same data type.
Is this a limitation of MySQL, or am I doing something else wrong?
Update: as requested hereby the table definitions. I have snipped unimportant columns:
-- ----------------------------
-- Table structure for `image`
-- ----------------------------
DROP TABLE IF EXISTS `image`;
CREATE TABLE `image` (
`id` int(11) NOT NULL auto_increment,
`guid` char(36) default NULL,
`title` varchar(255) NOT NULL,
`description` text,
`user_id` int(11) NOT NULL,
`item_id` int(11) default NULL,
`date_uploaded` timestamp NOT NULL default '0000-00-00 00:00:00',
`date_created` timestamp NOT NULL default '0000-00-00 00:00:00',
`date_modified` timestamp NOT NULL default '0000-00-00 00:00:00',
`status` enum('softdeleted','tobedeleted','active') default 'active',
PRIMARY KEY (`id`),
KEY `image_user` (`user_id`),
KEY `image_item` (`item_id`),
KEY `image_mod_by` (`moderated_by`),
CONSTRAINT `image_mod_by` FOREIGN KEY (`moderated_by`) REFERENCES `user` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `image_user` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='stores image data (not file data)';
-- ----------------------------
-- Table structure for `specie`
-- ----------------------------
DROP TABLE IF EXISTS `specie`;
CREATE TABLE `specie` (
`id` int(11) NOT NULL auto_increment,
`name` varchar(256) NOT NULL,
`commonname` varchar(256) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=22 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;
-- ----------------------------
-- Table structure for `specie_map`
-- ----------------------------
DROP TABLE IF EXISTS `specie_map`;
CREATE TABLE `specie_map` (
`id` int(11) NOT NULL auto_increment,
`image_id` int(11) NOT NULL,
`specie_id` int(11) NOT NULL,
`user_id` int(11) NOT NULL,
`karma` int(11) NOT NULL,
`date_created` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `image_id` (`image_id`),
KEY `specie_id` (`specie_id`),
CONSTRAINT `specie_map_ibfk_1` FOREIGN KEY (`image_id`) REFERENCES `image` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Foreign keys works only with InnoDb in mysql. MyISAM doesn't support them (the statements are ignored).
And is there any reason why you mix multiple DB engines?
I think you should post the exact DDL statements you used when you attempted to create these tables and the foreign key. Foreign keys between innodb tables work fine, but there are still a few things to look out for:
0) Both tables must be InnoDB. This was already highlighted by the other posters and this is probably the immediate cause of your problem.
1) the data type of the referencing columns (those that make up the foreign key) and their respective referenced columns should be the same. For example, you can't create a foreign key constrain on an INT UNSIGNED column to a plain INT column.
2) if the foreign key is created as part of the table DDL, be sure to put the foreign key definition in the constraints section, that is, below all column definitions. For example:
CREATE TABLE parent (
id int unsigned PRIMARY KEY
);
CREATE TABLE child (
parent_id int unsigned
, foreign key (parent_id)
references parent (id)
);
will work but this:
CREATE TABLE child (
parent_id int unsigned
foreign key references parent (id)
);
won't. It will fail silently because MySQL's parser ignores these types of constraint definitions even before InnoDB gets to create the table (silly, but that's how it is)
3) There must be an index over all the referenced columns. Usually the referenced columns will together make up a primary key or a unique constraint anyway, but it is your job to define this before defining the foreign key.
Final word of advice: if you think your DDL is ok but you still get an error when you execute it, for example like this:
ERROR 1005 (HY000): Can't create table 'test.child' (errno: 150)
Warning (Code 150): Create table 'test/child' with foreign key constraint failed. There is no index in the referenced table where the referenced columns appear as the first columns.
Error (Code 1005): Can't create table 'test.child' (errno: 150)
Then these errors may still not reveal the true nature of the error (silly again, but that's how it is). To shed more light on it, run this command immediately after your attempt to create the foreign key:
SHOW ENGINE INNODB STATUS;
This will give you a bunch of status info, and one section there looks like this:
------------------------
LATEST FOREIGN KEY ERROR
------------------------
120122 11:38:28 Error in foreign key constraint of table test/child:
foreign key (parent_id) references parent (id) ):
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.
As you can see, this gives a bit more information and reveals the true problem, namely "column types in the table and the referenced table do not match for constraint"
So please, post your actual DDL, I'm sure there is a problem in there somewhere.