Issues with creating a foreign key - mysql

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

Related

Error on creating foreign key relationship between non-primary key

I have two table
CREATE TABLE `abc` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`ref_id` varchar(20) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `ref_id_UNIQUE` (`ref_id`)
)
CREATE TABLE `xyz` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`ref_id` varchar(20) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `ref_id_UNIQUE` (`ref_id`)
)
I want to make foreign key relation ship between xyz's ref_id and abc's ref_id .But Mysql gives error 1215.
You should make the foreign key relationships to the primary keys. I know that MySQL allows foreign key relationships to anything with an index. But the correct practice is to use primary keys.
So declare the table like this:
CREATE TABLE `xyz` (
`id` int(11) NOT NULL AUTO_INCREMENT,
abc_id int DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `ref_id_UNIQUE` (`abc_id`),
ADD CONSTRAINT fk_xyz_abc FOREIGN KEY (abc_id) REFERENCES abc(id)
);
If you want the ref_id for an xyz row, then use JOIN to get the information.
Take a look at Gordon Linoff's answer, his suggestion makes sense, even though it does not answer the question. So what can cause an error when you intend to create a foreign key relationship? The obvious possibility is syntax error and typo, so you will need to check against those and fix any such problems.
Another possibility is that you have inconsistency, that is, you try to create a foreign key constraint in one of your tables, but not all the values have exact matches. So, assuming that you have Foo and Bar table and you intend Foo.lorem to be a foreign key referencing Bar.ipsum, then you will need to ensure that all the values you have for Foo.lorem has a Bar.ipsum pair with the exact same values (except null). If that's not true, then your foreign key constraint will not be successfully created. Find such inconsistencies:
select distinct Foo.lorem
from Foo
where not (Foo.lorem is null) and
not exists (select 1 from Bar where Foo.lorem = Bar.ipsum);
Read the lines carefully and make sure you fix any such Foo.lorem values.

How can I delete the rows of a table which stores foreign keys?

THE SOLUTION IS BELOW
I have three tables like the following:
CREATE TABLE `t_arch_layer` (
`arch_layer_id` int(11) NOT NULL AUTO_INCREMENT,
`arch_layer_name` varchar(45) NOT NULL,
PRIMARY KEY (`arch_layer_id`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8;
CREATE TABLE `t_tech` (
`tech_id` int(11) NOT NULL AUTO_INCREMENT,
`tech_name` varchar(45) DEFAULT NULL,
`tech_type_id` int(11) NOT NULL,
`tech_icon` text,
PRIMARY KEY (`tech_id`),
KEY `fk_t_tech_t_tech_type1_idx` (`tech_type_id`),
CONSTRAINT `fk_t_tech_t_tech_type1` FOREIGN KEY (`tech_type_id`) REFERENCES `t_tech_type` (`tech_type_id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=33 DEFAULT CHARSET=utf8;
CREATE TABLE `t_arch_layer_tech` (
`arch_layer_id` int(11) NOT NULL,
`tech_id` int(11) NOT NULL,
PRIMARY KEY (`tech_id`,`arch_layer_id`),
KEY `fk_t_layer_has_t_tech_t_tech1_idx` (`tech_id`),
KEY `fk_t_layer_has_t_tech_t_layer1_idx` (`arch_layer_id`),
CONSTRAINT `fk_t_layer_has_t_tech_t_layer1` FOREIGN KEY (`arch_layer_id`) REFERENCES `t_arch_layer` (`arch_layer_id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `fk_t_layer_has_t_tech_t_tech1` FOREIGN KEY (`tech_id`) REFERENCES `t_tech` (`tech_id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Basically it's a tipical situation where one table use two foreign keys from another two different tables. This table stores the possible combinations between the layers and technologies so it can't store any combination of layer_id and tech_id which is not in both.
But there is a problem, I need to delete whenever I want some row from t_arch_layer_tech. This it's impossible due to the foreign keys, I know it.
My question is, is there something to use the foreign key as a reference to forbide insert values that there aren't into t_tech or t_arch_layer and also to be consider as "own fields" (I can't explain better) of the table in order to delete any row of the t_arch_layer_tech table? Delete t_tech and t_arch_layer tables to avoid the foreign keys and then set the limits into the t_arch_layer_tech is not a solution.
SOLUTION
When that error appears it's neccesary to check the DB relationships and read carefully the provided message. It seems useless but it helped me to understand what's happening with the t_arch_layer_tech FK. I was using them into another table BUT separately, not as a compound FK. This is the reason because I could insert some rows into t_arch_layer_tech and delete only specific pairs.
So, summarizing, if you are going to use FKs that exist together (as my pair "arch_layer_id, tech_id") create ONLY ONE FK which is a compound FK that uses the mentioned.

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 Errno 150

I'm creating a few simple tables and I can't get passed this foreign key error and I'm not sure why. Here's the script below.
create TABLE Instructors (
ID varchar(10),
First_Name varchar(50) NOT NULL,
Last_Name varchar(50) NOT NULL,
PRIMARY KEY (ID)
);
create table Courses (
Course_Code varchar(10),
Title varchar(50) NOT NULL,
PRIMARY KEY (Course_Code)
);
create table Sections (
Index_No int,
Course_Code varchar(10),
Instructor_ID varchar(10),
PRIMARY KEY (Index_No),
FOREIGN KEY (Course_Code) REFERENCES Courses(Course_Code)
ON DELETE cascade
ON UPDATE cascade,
FOREIGN KEY (Instructor_ID) REFERENCES Instructors(ID)
ON DELETE set default
);
Error Code: 1005. Can't create table '336_project.sections' (errno: 150)
My data types seem identical and the syntax seems correct. Can anyone point out what I'm not seeing here?
I'm using MySQL Workbench 5.2
This error also occurs if you are relating columns of different types, eg. int in the source table and BigInt in the destination table.
If you're using the InnoDB engine, the ON DELETE SET DEFAULT is your problem. Here's an excerpt from the manual:
While SET DEFAULT is allowed by the MySQL Server, it is rejected as invalid by InnoDB. CREATE TABLE and ALTER TABLE statements using this clause are not allowed for InnoDB tables.
You can use ON DELETE CASCADE or ON DELETE SET NULL, but not ON DELETE SET DEFAULT. There's more information here.
You can run
SHOW ENGINE INNODB STATUS
to read the reason of the failure in a human readable format
e.g.
------------------------
LATEST FOREIGN KEY ERROR
------------------------
150331 15:51:01 Error in foreign key constraint of table foobar/#sql-413_81:
FOREIGN KEY (`user_id`) REFERENCES `foobar`.`users`(`id`) ON DELETE SET NULL ON UPDATE CASCADE:
You have defined a SET NULL condition though some of the columns are defined as NOT NULL.
In order to create a FOREIGN KEY with reference to another table, the keys from both tables should be PRIMARY KEY and with the same datatype.
In your table sections, PRIMARY KEY is of different datatype i.e INT but in another table, it's of type i.e VARCHAR.
It may also be the case if you are not specifying the ON DELETE at all but are trying to reference a MYISAM table from InnoDB table:
CREATE TABLE `table1`(
`id` INT UNSIGNED NOT NULL,
`name` VARCHAR(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MYISAM CHARACTER SET UTF8;
CREATE TABLE `table2`(
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`table1_id` INT UNSIGNED NOT NULL,
`some_value` VARCHAR(255) NOT NULL,
PRIMARY KEY (`id`),
KEY `fk_table1_id`(`table1_id`),
CONSTRAINT FOREIGN KEY (`table1_id`) REFERENCES `table1`(`id`)
) ENGINE=INNODB CHARACTER SET UTF8;
The above will throw errno 150. One need to change the first table to InnoDB too for this to work.
It is failing on the
ON DELETE set default
I have not come across that before and I am not seeing it in the manuals either ( but then it is late )
Update
just seen this in the manual
While SET DEFAULT is allowed by the MySQL Server, it is rejected as
invalid by InnoDB. CREATE TABLE and ALTER TABLE statements using this
clause are not allowed for InnoDB tables.
I guess you may be using InnoDB tables ?
For completeness sake - you will also get this error if you make a foreign reference to a table that isn't defined at the time;
Here Problem is in database engine ( table1 MYISAM and table2 ENGINE).
To set FOREIGN KEYs,
Both table must be in same ENGINE and same charset.
PK column in parent and FK column must be in same data type and same collation type.
Hope you got an idea.
Make sure that table type is InnoDB, MyISAM does not support foreign key, afaik.

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.