mySQL: What is preventing my foreign key constraint? - mysql

I have tried everything I can think of but I am still having problems creating a table.
I have a user table with a primary key username
+---------------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------------+-------------+------+-----+---------+-------+
| created_at | datetime | YES | | NULL | |
| updated_at | datetime | YES | | NULL | |
| username | varchar(50) | NO | PRI | NULL | |
| administrator | tinyint(1) | YES | | NULL | |
| fullname | text | YES | | NULL | |
| description | text | YES | | NULL | |
| password | varchar(60) | NO | | NULL | |
+---------------+-------------+------+-----+---------+-------+
and I want to create a new table like this:
CREATE TABLE sessions (
created_at DATETIME,
updated_at DATETIME,
token VARCHAR(50) NOT NULL,
username VARCHAR(50),
PRIMARY KEY (token),
FOREIGN KEY(username) REFERENCES users (username)
);
but I get a nasty error:
ERROR 1215 (HY000): Cannot add foreign key constraint
I usually find this error is caused by a mismatch in the data type of the pk/fk pair but this time both are clearly varchar(50) so it looks like the problem is elsewhere.
I have also tried this just in case:
CREATE TABLE sessions (
created_at DATETIME,
updated_at DATETIME,
token VARCHAR(50) NOT NULL,
username varchar(50) NOT NULL, #<- ***added not null***
PRIMARY KEY (token),
FOREIGN KEY(username) REFERENCES users (username)
);
mysql>SHOW ENGINE INNODB STATUS
LATEST FOREIGN KEY ERROR
2016-08-03 15:13:23 a46fcb70 Error in foreign key constraint of table savesdev/sessions:
FOREIGN KEY(username) REFERENCES users (username)):
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.6/en/innodb-foreign-key-constraints.html
for correct foreign key definition.
It seems the error is raised under two circumstances:
1) When there is a mismatch (which I have ruled out)
column types in the table and the referenced table do not match for constraint.
2) When there is no suitable index on the referenced column
Cannot find an index in the referenced table where the referenced columns appear as the first columns
I think both of these are covered so what's the deal?
Can anyone spot my error?

Maybe your columns username have different charset can you try this :
ALTER TABLE sessions MODIFY username VARCHAR(50) CHARACTER SET utf8;
ALTER TABLE users MODIFY username VARCHAR(50) CHARACTER SET utf8;
As suggested by #Graeme Stuart here is a link to see how we can check the charterer set of a database / table or a column : How do I see what character set a MySQL database / table / column is?

Related

Cannot find an index in the referenced table where the referenced columns appear as the first columns

I'm creating mysql table following the link https://dev.mysql.com/doc/refman/5.7/en/create-table-foreign-keys.html
But I keep getting this error
FOREIGN KEY (serial_no) REFERENCES tag_master(orig_serial_no) ON UPDATE CASCADE ON DELETE RESTRICT:
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 http://dev.mysql.com/doc/refman/5.7/en/innodb-foreign-key-constraints.html for correct foreign key definition.
Here are tables:
create table tag_master(
orig_part_no VARCHAR(70) CHARACTER SET ascii NOT NULL,
orig_serial_no VARCHAR(56) CHARACTER SET ascii NOT NULL,
regist_part_no VARCHAR(70) CHARACTER SET ascii,
regist_serilal_no VARCHAR(56) CHARACTER SET ascii,
regist_comment VARCHAR(126) CHARACTER SET ascii,
PRIMARY KEY (orig_part_no, orig_serial_no)
) ENGINE=INNODB;
create table reader_table(
reader_id VARCHAR(70) CHARACTER SET ascii NOT NULL,
name VARCHAR(128) CHARACTER SET ascii,
PRIMARY KEY (reader_id)
) ENGINE=INNODB;
create table tag_log(
id BIGINT AUTO_INCREMENT,
part_no VARCHAR(70) CHARACTER SET ascii NOT NULL,
serial_no VARCHAR(56) CHARACTER SET ascii NOT NULL,
access_date DATE,
latitude FLOAT,
longitude FLOAT,
reader_id VARCHAR(70) CHARACTER SET ascii NOT NULL,
current_part_no VARCHAR(105) CHARACTER SET ascii,
current_serial_no VARCHAR(70) CHARACTER SET ascii,
current_comment VARCHAR(128) CHARACTER SET ascii,
PRIMARY KEY (id),
INDEX (part_no, serial_no),
INDEX (reader_id),
FOREIGN KEY(part_no, serial_no) REFERENCES tag_master(orig_part_no, orig_serial_no) ON UPDATE CASCADE ON DELETE RESTRICT,
FOREIGN KEY(reader_id) REFERENCES reader_table(reader_id)
) ENGINE=INNODB;
The foreign key for the part_no and reader_id work but somehow I can't create foreign key serial_no to orig_serial_no.
I tried ALTER TABLE tag_log ADD FOREIGN KEY (serial_no) REFERENCES tag_master(orig_serial_no) ON UPDATE CASCADE ON DELETE RESTRICT; but it's still doesn't work, it doesn't make any sense.
The desc tag_log table look like this:
+-------------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------------+--------------+------+-----+---------+----------------+
| id | bigint(20) | NO | PRI | NULL | auto_increment |
| part_no | varchar(70) | NO | MUL | NULL | |
| serial_no | varchar(56) | NO | | NULL | |
| access_date | date | YES | | NULL | |
| latitude | float | YES | | NULL | |
| longitude | float | YES | | NULL | |
| reader_id | varchar(70) | NO | MUL | NULL | |
| current_part_no | varchar(105) | YES | | NULL | |
| current_serial_no | varchar(70) | YES | | NULL | |
| current_comment | varchar(128) | YES | | NULL | |
+-------------------+--------------+------+-----+---------+----------------+
OS:
Ubuntu 18.04
MySQL:
mysql Ver 14.14 Distrib 5.7.29, for Linux (x86_64) using EditLine wrapper
Server version: 5.7.29-0ubuntu0.18.04.1 (Ubuntu)
This foreign key...
FOREIGN KEY (serial_no)
REFERENCES tag_master(orig_serial_no)
ON UPDATE CASCADE ON DELETE RESTRICT
... requires an index on tag_master(orig_serial_no), or at least a compound index where orig_serial_no appears first. This is not the case in your current set up, where the primary key of tag_master is (part_no, serial_no) (the concerned column appears in second position, not first).
One way around this would be to change the order of the columns in the primary key of tag_master:
PRIMARY KEY (orig_serial_no, orig_part_no)
This requires you to also change the order of columns in the compound foreign key in tag_log that references both columns:
FOREIGN KEY(serial_no, part_no)
REFERENCES tag_master(orig_serial_no, orig_part_no)
ON UPDATE CASCADE ON DELETE RESTRICT
Then you can create the additional foreign key, as demonstrated in this db fiddle.
But, that being said, I just do not see the point for creating this additional foreign key, since you already have another key that covers it (FOREIGN KEY(serial_no, part_no)). Most likely, you just do not need that additional constraint, since the functionalities it offers are aleardy provided by the compound key.
Alright, I know this question is kinda old but I had a tough time finding this out and practically nothing on the internet could helped me.
What I did to solve mine was instead of giving the column on the parent table(the referenced table) a primary key, I gave it a unique key instead. Then on the child table(the referencing table) I always give the column referencing an index key. When defining the constraint, use a another constraint if one has already been used to reference to the parent child. Using the same constraint might not work as it didn't work for me.
This solved my problem quite fairly and I hope it worked for you as well...

MYSQL can't add a foreign key

I really can't get a clue, as everything seems to be ok. This is the command I'm trying:
ALTER TABLE dashboard ADD CONSTRAINT FOREIGN KEY (app_name, app_parent, client)
REFERENCES apps(app_name, app_parent, client) ON DELETE CASCADE ON UPDATE CASCADE;
This is the error I get:
ERROR 1215 (HY000): Cannot add foreign key constraint
Using an explicit name for the FK doesn't help. This is the referenced table:
mysql> SHOW COLUMNS IN apps;
+------------+------------------+------+-----+------------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------+------------------+------+-----+------------+-------+
| app_name | varchar(20) | NO | PRI | | |
| app_parent | varchar(20) | NO | PRI | | |
| client | varchar(12) | NO | PRI | NULL | |
| order_idx | int(10) unsigned | YES | | 100 | |
...
And this is the referencing table:
mysql> SHOW COLUMNS IN dashboard;
+------------+----------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------+----------------------+------+-----+---------+-------+
| app_name | varchar(20) | NO | | | |
| app_parent | varchar(20) | NO | | | |
| client | varchar(12) | NO | | NULL | |
| widget | varchar(20) | YES | | NULL | |
...
Both tables have InnoDB as the engine. And this is the (rather laconic) clue I'm getting from SHOW ENGINE InnoDB STATUS:
LATEST FOREIGN KEY ERROR
------------------------
2014-06-20 11:49:57 10ec Error in foreign key constraint of table the_db/#sql-128c_2:
FOREIGN KEY (app_name, app_parent, client)
REFERENCES apps(app_name, app_parent, client) ON DELETE CASCADE ON UPDATE CASCADE:
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.6/en/innodb-foreign-key-constraints.html
for correct foreign key definition.
What does it mean it doesn't find an index on apps? I'm referencing primary keys! And the types are clearly the same.
EDIT: this is the CREATE command for apps:
CREATE TABLE `apps` (
`app_name` varchar(20) NOT NULL DEFAULT '',
`app_parent` varchar(20) NOT NULL DEFAULT '',
`client` varchar(12) NOT NULL,
`order_idx` int(10) unsigned DEFAULT '100',
...,
PRIMARY KEY (`app_name`,`app_parent`,`client`),
KEY `client` (`client`),
CONSTRAINT `apps_ibfk_1` FOREIGN KEY (`client`) REFERENCES `clients` (`name`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `apps_ibfk_2` FOREIGN KEY (`app_name`, `app_parent`) REFERENCES `app_list` (`name`, `parent`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=latin1
I must add that I actually managed to create a foreign key on the same columns on another table:
mysql> SHOW COLUMNS IN user_apps;
+------------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------+-------------+------+-----+---------+-------+
| app_name | varchar(20) | NO | PRI | | |
| app_parent | varchar(20) | NO | PRI | | |
| username | varchar(20) | NO | PRI | | |
| client | varchar(12) | YES | | NULL | |
...
Here, app_name, app_parent and client reference to the same named columns in apps.
This is probably the sneakiest of the mistakes: the problem was the default character set, which is latin1 for apps and utf8 for dashboard.
This solved my problem:
ALTER TABLE dashboard CONVERT TO CHARACTER SET latin1;
You better have posted output of
show create table apps
I am not sure if the referenced parent columns are indexed.
But for them to be eligible for referring from other child tables, they MUST have INDEXed
As per documentation on foreign key constraints:
REFERENCES tbl_name (index_col_name,...)
Define an INDEXes on columns app_name, app_parent, client of apps table.
If not already defined, then use following command:
ALTER TABLE apps
ADD INDEX ix_app_name( app_name )
, ADD INDEX ix_app_parent( app_parent )
, ADD INDEX ix_app_client( client )
And other primary constraints are that,
The child column definition MUST match with that of parent column.
Database ENGINE type must be same.
Refer to:
MySQL ALTER TABLE Syntax
MySQL Using FOREIGN KEY Constraints
[CONSTRAINT [symbol]] FOREIGN KEY
[index_name] (index_col_name, ...)
REFERENCES tbl_name (index_col_name,...)
[ON DELETE reference_option]
[ON UPDATE reference_option]
reference_option:
RESTRICT | CASCADE | SET NULL | NO ACTION

drop primary key from table in mysql [duplicate]

This question already has answers here:
Changing MySQL primary key when foreign key contraints exist
(2 answers)
Closed 8 years ago.
i created a flight class and here is the description of it.
mysql> desc flight_class;
+----------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------+--------------+------+-----+---------+-------+
| FID | varchar(5) | YES | MUL | NULL | |
| amount | decimal(7,2) | YES | | NULL | |
| no_seats | decimal(2,0) | YES | | NULL | |
| class_id | int(11) | NO | PRI | 0 | |
+----------+--------------+------+-----+---------+-------+
then i want to make the class_id to a foreign key.
to drop the primary key i said
mysql> alter table flight_class drop primary key;
ERROR 1025 (HY000): Error on rename of '.\flysafe\#sql-76c_1' to '.\flysafe\flight_class' (errno: 150)
i am a newbie to this. can any one tell me where i went wrong. or is it other tables that are affecting this table?
please do give some resource for learning these right.
thanks anirudh.
Without an index, maintaining an autoincrement column becomes too expensive, that's why MySQL requires an autoincrement column to be a leftmost part of an index.
You should remove the autoincrement property before dropping the key:
ALTER TABLE flight_class MODIFY id INT NOT NULL;
ALTER TABLE flight_class DROP PRIMARY KEY;
Note that you have a composite PRIMARY KEY which covers all three columns and id is not guaranteed to be unique.
If it happens to be unique, you can make it to be a PRIMARY KEY and AUTO_INCREMENT again:
ALTER TABLE flight_class MODIFY id INT NOT NULL PRIMARY KEY AUTO_INCREMENT;

How can I see that it is indeed a foreign key and the parent table?

I have created a table which has a foreign key as follows:
CREATE TABLE interests
(
int_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
an_interest VARCHAR(50) NOT NULL,
contact_id INT NOT NULL,
CONSTRAINT my_contacts_contact_id_fk
FOREIGN KEY (contact_id)
REFERENCES my_contacts (contact_id)
);
When I do DESC I see:
mysql> desc interests;
+------------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+-------------+------+-----+---------+----------------+
| int_id | int(11) | NO | PRI | NULL | auto_increment |
| interest | varchar(50) | NO | | NULL | |
| contact_id | int(11) | NO | MUL | NULL | |
+------------+-------------+------+-----+---------+----------------+
3 rows in set (0.02 sec)
I know what MUL is but how would I explicitely see that contact_id is defined as a foreign key and which is the parent table via CLI?
Also why can't I use my_contacts_contact_id_fk to drop the foreign key constraint?
UPDATE
mysql> ALTER TABLE interests DROP CONSTRAINT my_contacts_contact_id_fk;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use n
ear 'CONSTRAINT my_contacts_contact_id_fk' at line 2
mysql>
Constraints are database objects in themselves so it doesn't surprise me that the full description of the constraint is not shown when you run
desc [interests].
Try desc [my_contacts_contact_id_fk]?
You should be able to execute alter table [interests] drop constraint [my_contacts_contact_id_fk]. If you are having trouble dropping can you post your alter table SQL and the response from the server?

MySQL What Happens to an Index if I Alter the Column it's on?

I'm in the process of updating my AUTO_INCREMENT PRIMARY KEY ID columns from INT to BIGINT. I'm using MySQL version 5.0.82 with InnoDB tables. They look something like:
FactTable
+-------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+----------------+
| ID | int(11) | NO | PRI | NULL | auto_increment |
| Path | varchar(64) | NO | | NULL | |
+-------+-------------+------+-----+---------+----------------+
AttemptTable
+---------+----------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------+----------+------+-----+---------+----------------+
| ID | int(11) | NO | PRI | NULL | auto_increment |
| TriedOn | datetime | NO | | NULL | |
| FactID | int(11) | NO | MUL | NULL | |
+---------+----------+------+-----+---------+----------------+
Where AttemptTable has KEY FK1 (FactID) and CONSTRAINT FK1 FOREIGN KEY (FactID) REFERENCES FactTable (ID). So the course of my updates has been:
ALTER TABLE AttemptTable DROP FOREIGN KEY FK1,
MODIFY ID BIGINT(20) NOT NULL AUTO_INCREMENT,
MODIFY FactID BIGINT(20) NOT NULL;
ALTER TABLE FactTable MODIFY ID BIGINT(20) NOT NULL AUTO_INCREMENT;
ALTER TABLE AttemptTable ADD CONSTRAINT FK1 FOREIGN KEY (FactID)
REFERENCES FactTable (ID);
Now, I've noticed that when doing these modifications, the key FK1 is still present after the constraint is dropped, and I assume it's still applicable after the constraint is recreated. But my question is, does MySQL update this key to be applicable for BIGINTs, or does it maintain only INT capabilities?
I looked through the MySQL reference guide for ALTER TABLE, and I found mention that if the size of a column is decreased to less than an index's length then the index will be shortened, but I couldn't find anything indicating what would happen to an index if the underlying column grows in size. (I'd like to know if I should be dropping and recreating the indexes, too, or if MySQL will do what I'm hoping.)
Basically, it rebuilds the index when you change a column's data type.
Actually, it rebuilds all the indexes in that table.
Some types of ALTER TABLE statements in MySQL result in a table restructure:
Lock the table.
Create a new empty table with the new definition for columns.
Copy all the data, row by row, from the old table to the new table. This naturally fills indexes in the new table, just as you would if you were INSERTing new data.
Swap the names on the tables.
Drop the original table.
Unlock the table.
This is especially true when you change the primary key column in an InnoDB table, since every InnoDB table is stored as a clustered index for its primary key.
So if you change the data type of a column, that applies to the new table, and it fills the index as it copies rows from the original table to the new table.