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;
Related
I'm learning from an online course MySQL using the WampServer and editing code in MySQL Workbench.
Trying to create a table with the following code, the column nome appears to be the primary key from the table, but i'm only using the unique constraint.
When i don't use the unique constraint, the code runs normally and don't give me a primary key.
create table if not exists cursos (
nome varchar(30) not null unique,
descricao text,
carga int unsigned,
totalaulas int unsigned,
ano year default '2016'
) default charset utf8mb4;
Second to this question, when i was trying to drop the constraint primary key i was getting the error Error Code: 1091. Can't DROP 'PRIMARY';
alter table cursos
drop primary key;
So, in resume, i'm trying to use the unique constraint without setting a column has a primary key, and then i'm trying to drop the primary key constraint.
Edit:
When i call describe table i get this, the column nome is defined has primary key whithout i using the constraint.
+------------------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------------+-------------+------+-----+---------+----------------+
| idcurso | int | YES | | NULL | |
| nome | varchar(30) | NO | PRI | NULL | |
+------------------+-------------+------+-----+---------+----------------+
What i'm trying to do is drop the primary key from nome and put on idcurso, but when i use the code
alter table cursos
add primary key idcurso;
I get the error Error Code: 1064. You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line
I tried this on mysql command-line client connected to a MySQL Server 5.5.2. Here is what happens:
mysql> create table if not exists cursos (
-> nome varchar(30) not null unique,
-> descricao text,
-> carga int unsigned,
-> totalaulas int unsigned,
-> ano year default '2016'
-> ) default charset utf8mb4;
Query OK, 0 rows affected (0.08 sec)
mysql>
mysql> desc cursos;
+------------+------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------+------------------+------+-----+---------+-------+
| nome | varchar(30) | NO | PRI | NULL | |
| descricao | text | YES | | NULL | |
| carga | int(10) unsigned | YES | | NULL | |
| totalaulas | int(10) unsigned | YES | | NULL | |
| ano | year(4) | YES | | 2016 | |
+------------+------------------+------+-----+---------+-------+
5 rows in set (0.05 sec)
Note that the field nome has a Key as PRI. But, it is only a description and not a fact. If you try to DROP the primary key you will see an error like below:
mysql> alter table cursos drop primary key;
ERROR 1091 (42000): Can't DROP 'PRIMARY'; check that column/key exists
Add a new column and make it a primary key. Note the DESCRIPTION after that.
mysql> alter table cursos add idcurso int primary key;
Query OK, 0 rows affected (0.09 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> desc cursos;
+------------+------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------+------------------+------+-----+---------+-------+
| nome | varchar(30) | NO | UNI | NULL | |
| descricao | text | YES | | NULL | |
| carga | int(10) unsigned | YES | | NULL | |
| totalaulas | int(10) unsigned | YES | | NULL | |
| ano | year(4) | YES | | 2016 | |
| idcurso | int(11) | NO | PRI | NULL | |
+------------+------------------+------+-----+---------+-------+
6 rows in set (0.05 sec)
At this point, you can drop the primary key using the syntax: alter table cursos drop primary key;. This will drop the primary key constraint only (but, not the column definition).
If you create yet another column, perhaps guid,
that has a UNIQUE constraint,
then you will be able to do what you wish.
(Not sure why you wish it. Whatever.)
A table can have multiple UNIQUE constraints.
Each table should have a PRIMARY KEY (which will of course be UNIQUE).
It affects physical layout of the rows on disk,
which affects retrieval speed and how the query planner behaves.
If you do not use the PRIMARY keyword, then the first UNIQUE column
will effectively be the primary key.
Put another way, to ALTER the table as you wish,
the backend DB will need to be able to promote
some candidate column so it becomes the new PRIMARY KEY.
I am trying to run a foreign key add query as below, with foreign key checks set to 0. Both the columns in the two tables are exactly the same. Also, both are primary keys. None of the solutions here helped in solving this problem. I'm on localhost.
mysql> alter table deliveryaddress
-> add foreign key(oid) references productorder(oid)
-> on delete cascade on update restrict;
ERROR 1822 (HY000): Failed to add the foreign key constaint. Missing index for c
onstraint '' in the referenced table 'productorder'
mysql> desc productorder;
+----------------+--------------+------+-----+-------------------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------------+--------------+------+-----+-------------------+-------+
| primenumber | varchar(15) | NO | PRI | NULL | |
| oid | varchar(10) | NO | PRI | NULL | |
| orderdatetime | timestamp | NO | | CURRENT_TIMESTAMP | |
| addressname | varchar(30) | NO | | NULL | |
| deliverycharge | decimal(8,2) | YES | | 20.00 | |
+----------------+--------------+------+-----+-------------------+-------+
5 rows in set (0.02 sec)
mysql> desc deliveryaddress;
+----------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------+-------------+------+-----+---------+-------+
| oid | varchar(10) | NO | PRI | NULL | |
| pincode | varchar(8) | NO | | NULL | |
| area | varchar(60) | NO | | NULL | |
| city | varchar(60) | NO | | NULL | |
| state | varchar(60) | NO | | NULL | |
| landmark | varchar(60) | YES | | NULL | |
| phone | varchar(15) | NO | | NULL | |
| locality | varchar(60) | NO | | NULL | |
+----------+-------------+------+-----+---------+-------+
8 rows in set (0.00 sec)
mysql>
It looks like productorder.oid is part of a multi-column primary key, and it's not the leftmost column in the primary key. (In the future, please include the result of SHOW CREATE TABLE <tablename> because it is more clear than DESCRIBE about things like multi-column keys.)
When you declare a foreign key, you must reference the leftmost column of the primary key.
When you reference a multi-column primary key, the foreign key must have the same number of columns in the same order.
Wrong (not enough columns, and referencing second column of primary key):
CREATE TABLE parent (x INT, y INT, PRIMARY KEY (x, y));
CREATE TABLE child (y INT, FOREIGN KEY (y) REFERENCES parent(y));
Wrong (individual foreign keys each referencing part of the composite primary key):
CREATE TABLE parent (x INT, y INT, PRIMARY KEY (x, y));
CREATE TABLE child (x INT, y INT,
FOREIGN KEY (x) REFERENCES parent(x),
FOREIGN KEY (y) REFERENCES parent(y)
);
Right (same columns):
CREATE TABLE parent (x INT, y INT, PRIMARY KEY (x, y));
CREATE TABLE child (x INT, y INT, FOREIGN KEY (x, y) REFERENCES parent(x, y));
Re your comment:
I'm now thinking that your real problem is that you have the relationship reversed. You are trying to declare a foreign key in deliveryaddress referencing productorder, but I would expect the reference to go the other direction.
ALTER TABLE productorder ADD FOREIGN KEY (oid) REFERENCES deliveryaddress (oid);
Then you have no error, because the primary key of deliveryaddress is just one column.
I believe this relationship makes more sense in a typical e-commerce application. There are many orders that might reference the same address. The opposite relationship is probably not what you want, because it makes no sense for many addresses to reference a single product order.
You have a composite primary key -- it consists of two keys together, (oid, primenumber).
You should use both keys to define the foreign key definition.
Alternatively, define an auto-incremented primary key and use that.
I recreated the table with index on oid that was generating missing index problem.
mysql> create table productorder
-> (
-> primenumber varchar(15) not null,
-> oid varchar(10) not null,
-> orderdatetime timestamp not null default current_timestamp,
-> addressname varchar(30) not null,
-> deliverycharge decimal(8,2) not null default 20,
-> primary key(oid, primenumber), index(oid), index(primenumber),
-> foreign key(primenumber) references user(primenumber) on delete cascade
n update restrict
-> );
Query OK, 0 rows affected (1.52 sec)
mysql> alter table deliveryaddress
-> add foreign key(oid) references productorder(oid)
-> on delete cascade on update restrict;
Query OK, 0 rows affected (0.19 sec)
Records: 0 Duplicates: 0 Warnings: 0
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?
I am creating a database table. Specifically this code will not add the two foreign keys for some reason, it says cannot add foreign key constraints, I'll show you the tables that I'm referring to.
mysql> ALTER TABLE PROGRAM
-> ADD SeriesName varchar(100) NOT NULL, ADD StartYear char(4) NOT NULL,
-> ADD CONSTRAINT program_seriesname_fk
-> FOREIGN KEY(SeriesName) REFERENCES SERIES(SeriesName),
-> ADD CONSTRAINT program_startyear_fk
-> FOREIGN KEY(StartYear) REFERENCES SERIES(StartYear);
ERROR 1215 (HY000): Cannot add foreign key constraint
SERIES table has PROGRAM table which means it is a 1:N (one-to-many relationship). So therefore, the two primary keys in SERIES become the two foreign keys in PROGRAM.
mysql> describe series;
+------------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------+--------------+------+-----+---------+-------+
| SeriesName | varchar(100) | NO | PRI | | |
| StartYear | char(4) | NO | PRI | | |
| EndYear | char(4) | YES | | NULL | |
+------------+--------------+------+-----+---------+-------+
3 rows in set (0.07 sec)
mysql> describe program;
+-------------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------+--------------+------+-----+---------+-------+
| ProgramName | varchar(50) | NO | PRI | | |
| Description | varchar(255) | YES | | NULL | |
| Recorded | date | NO | | NULL | |
+-------------+--------------+------+-----+---------+-------+
3 rows in set (0.01 sec)
You have composite PK on series table, so you can't use this fields separately in FK constraint
ADD CONSTRAINT program_seriesname_fk
FOREIGN KEY(SeriesName, StartYear) REFERENCES SERIES(SeriesName, StartYear)
To create a foreign key to a single column in InnoDB, the column you reference needs to be the first column in at least one index.
ALTER TABLE program
ADD CONSTRAINT program_startyear_fk
FOREIGN KEY(StartYear) REFERENCES SERIES(StartYear);
will not work, since SERIES(StartYear) is the second column in the primary key index on SERIES. If you add an index first though;
CREATE INDEX ix_program ON series(StartYear);
ALTER TABLE program
ADD CONSTRAINT program_startyear_fk
FOREIGN KEY(StartYear) REFERENCES SERIES(StartYear);
...it will will work.
Now if what you're really looking for is really a composite index, #Parado's answer is what you want, just wanted to point out that the index doesn't have to be composite.
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.