PHP MySQL Error creating table: Cannot add foreign key constraint - php

I am trying to write a PHP script to create 2 tables in the same database, which should be linked through a 1 (table category) to many (table page) relationship. Hence, primary key 'category_id' from the 'category' table should be the foreign key in the table 'page'.
The table 'category' creates successfully without problems:
$sql="CREATE TABLE category(
category_id SMALLINT NOT NULL AUTO_INCREMENT,
category VARCHAR(30) NOT NULL,
PRIMARY KEY (category_id),
UNIQUE (category)
)ENGINE=InnoDB DEFAULT CHARSET=utf8";
Then I am trying to create the second table 'page':
$sql="CREATE TABLE page(
page_id MEDIUMINT UNSIGNED NOT NULL AUTO_INCREMENT,
category_id SMALLINT UNSIGNED NOT NULL,
title VARCHAR(100) NOT NULL,
description TINYTEXT NOT NULL,
content LONGTEXT NOT NULL,
date_created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (page_id),
FOREIGN KEY (category_id) REFERENCES category (category_id)
)ENGINE=InnoDB DEFAULT CHARSET=utf8";
And I get the following error:
Error creating table: Cannot add foreign key constraint
Could you please tell me what's wrong with my code? Thanks a lot in advance.

Per the MySql manual at http://dev.mysql.com/doc/refman/5.6/en/create-table-foreign-keys.html:
Corresponding columns in the foreign key and the referenced key must have similar data types.
The size and sign of integer types must be the same.
The problem is that you're specifying your foreign key as UNSIGNED, while your primary is not. Make sure that your foreign key matches the specifications of its parent.

From the MySQL Using FOREIGN KEY Constraints documentation:
Corresponding columns in the foreign key and the referenced key must have similar data types. The size and sign of integer types must be the same.
In your page table, the category_id is SMALLINT UNSIGNED, but in category it's just SMALLINT. They need to be exactly the same.

The columns used for your foreign key must have a matching specification. Here you have one category_id column signed, while the other is unsigned. Change one.

you problem is the UNSIGNED in category_id.
try to remove it

try
$sql="CREATE TABLE page(
page_id MEDIUMINT UNSIGNED NOT NULL AUTO_INCREMENT,
category_id SMALLINT NOT NULL,
title VARCHAR(100) NOT NULL,
description TINYTEXT NOT NULL,
content LONGTEXT NOT NULL,
date_created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (page_id),
FOREIGN KEY (page.category_id) REFERENCES category (category.category_id)
)ENGINE=InnoDB DEFAULT CHARSET=utf8";

Related

Referencing multiple tables in mysql

How do I reference multiple tables for one table ?
In the assignment, I have to create 5 tables with each table having INT id:
Owners, homes, home_owners, installation, house_type.
Owners can have multiple homes and homes can have multiple owners.
Home needs to have installations and house_type(both need to be VARCHAR type).
I wrote this to sql but it returns an
error: errno: 150 "Foreign key constraint is incorrectly formed"
CREATE TABLE owners (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
created DATETIME,
modified DATETIME
);
CREATE TABLE homes (
id INT AUTO_INCREMENT PRIMARY KEY,
created DATETIME,
modified DATETIME,
home_types_group VARCHAR(255) NOT NULL
);
CREATE TABLE home_owners (
id INT AUTO_INCREMENT PRIMARY KEY,
created DATETIME,
modified DATETIME,
owners_num INT NOT NULL,
FOREIGN KEY owners_num_key (owners_num) REFERENCES owners(id)
);
CREATE TABLE installation (
id INT AUTO_INCREMENT PRIMARY KEY,
brands VARCHAR(255) NOT NULL,
created DATETIME,
modified DATETIME,
FOREIGN KEY brands_key (brands) REFERENCES homes(home_types_group)
);
CREATE TABLE types (
id INT AUTO_INCREMENT PRIMARY KEY,
types VARCHAR(255) NOT NULL,
created DATETIME,
modified DATETIME,
FOREIGN KEY brands_key (types) REFERENCES homes(home_types_group)
);
The problem is here:
CREATE TABLE installation ( id INT AUTO_INCREMENT PRIMARY KEY, brands VARCHAR(255) NOT NULL, created DATETIME, modified DATETIME, FOREIGN KEY brands_key (brands) REFERENCES homes(home_types_group) )
REFERENCES homes(home_types_group) : this is wrong, you can only reference a primary or unique column of some table for making foreign key. But home_types_group column is neither primary nor unique. Change it to id clumn of homes table
Try this
CREATE TABLE installation ( id INT AUTO_INCREMENT PRIMARY KEY, brands
int, created DATETIME, modified DATETIME, FOREIGN KEY fk_id(brands)
REFERENCES homes(id) );
CREATE TABLE types ( id INT AUTO_INCREMENT PRIMARY KEY, types int,
created DATETIME, modified DATETIME, FOREIGN KEY brands_key (types)
REFERENCES homes(id) );
You can create a foreign key by defining a FOREIGN KEY constraint when you create or modify a table. In a foreign key reference, a link is created between two tables when the column or columns that hold the primary key value for one table are referenced by the column or columns in another table
Here REFERENCES homes(home_types_group) is wrong so you should change it to homes(id), you can only reference a primary or unique column of some table for making foreign key.and both keys data type should be same that is
brands VARCHAR(255) NOT NULL
types VARCHAR(255) NOT NULL
are wrong it should be int

Why a can't connect my tables in MySQL?

shippings table structure
I want to connect in to another table like this(I got "1215 error"):
CREATE TABLE goods_and_shippings (
good_id INT NOT NULL,
s_date DATE NOT NULL,
shipping_id INT NOT NULL,
PRIMARY KEY (good_id),
FOREIGN KEY (s_date) REFERENCES shippings(s_date)
)
Connected columns have same data types as you can see (both DATE and NOT NULL) and all tables use InnoDB engine. But I have this snippet and it works:
CREATE TABLE goods_and_shippings (
good_id INT NOT NULL,
s_date DATE NOT NULL,
shipping_id INT NOT NULL,
PRIMARY KEY (good_id),
FOREIGN KEY (shipping_id) REFERENCES shippings(shipping_id)
)
All tables are empty for now. Here is query for creating shippings:
CREATE TABLE shippings (
shipping_id INT NOT NULL,
s_date DATE NOT NULL,
driver_id INT NOT NULL,
start_place VARCHAR(50) NOT NULL,
end_place VARCHAR(50) NOT NULL,
car_id INT NOT NULL,
price DECIMAL(5,2) NOT NULL,
PRIMARY KEY (shipping_id, s_date)
)
Here alters I've used after:
ALTER TABLE shippings ADD CONSTRAINT fk_car_id FOREIGN KEY (car_id) REFERENCES cars(car_id);
ALTER TABLE shippings ADD CONSTRAINT fk_driver_id FOREIGN KEY (driver_id) REFERENCES drivers(driver_id);
What's wrong in my queries? How to fix this and connect goods_and_shippings.s_date and shippings.s_date?
In general, foreign key references are to unique or primary keys. However, this condition is relaxed for INNODB, as explained in the documentation:
InnoDB permits a foreign key to reference any index column or group of
columns. However, in the referenced table, there must be an index
where the referenced columns are listed as the first columns in the
same order.
So, you can have a foreign reference to shipping_id because it is the first key in the primary key, but not to date. However, I would advise you to set up your foreign key relationships to complete primary keys. And, I usually have an auto-incrementing primary key in all tables, to facilitate such relationships.

Why won't my foreign key create in MySQL?

I've tried many different ways to create table with a foreign key and trying to insert into phpMyAdmin. However, it just not working as I was expected.
Here are what I've so far:
CREATE TABLE user (
user_id BIGINT(10) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
user_name VARCHAR(50) NOT NULL,
user_password VARCHAR(50) NOT NULL);
This works perfectly fine. However, if I try to add a table with a foreign key thus, it refuses to create:
CREATE TABLE article (
article_id INT(20) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
article_title VARCHAR(100) NOT NULL,
article_content VARCHAR(1000) NOT NULL,
user_id INT(10) NOT NULL,
FOREIGN KEY (user_id) REFERENCES user (user_id));
This would not work as expected and would not add the table to the MySQL database. I get this error:
Cannot add foreign key constraint
How can I fix it?
We discovered in the comments that if a primary key is defined thus:
user_id BIGINT(10) UNSIGNED
then a foreign key like this will not work, since it needs to match on signedness (and I think type too):
user_id INT(10) NOT NULL
This works fine:
user_id BIGINT(10) UNSIGNED NOT NULL
Here's a Fiddle to demonstrate it working.

no foreign key in table if engine is MyISAM

why i cannot create foreign key in my table payments.
crate table students(
text char(5)NOT NULL,
id int(11)NOT NULL AUTO_INCREMENT,
name varchar(250),
level varchar(250),
PRIMARY KEY (text,id)
)ENGINE=MyISAM;
the oder table is
crate table payments(
p_id int(11)NOT NULL AUTO_INCREMENT,
amount varchar(250),
id int
PRIMARY KEY (p_id)
FOREIGN KEY (id) REFERENCES students(id)
)ENGINE=MyISAM;
Because MyISAM does not support foreign keys. The FK declarations are parsed, but otherwise ignored. You need to use InnoDB tables for real FK support.

Mysql and FK's Problem

i'm having trouble with some tables here.
i have this table:
CREATE TABLE `smenuitem` (
`nome` VARCHAR(150) NULL DEFAULT NULL COLLATE 'utf8_unicode_ci',
`url` VARCHAR(150) NULL DEFAULT NULL COLLATE 'utf8_unicode_ci',
`tipo` CHAR(4) NULL DEFAULT NULL COLLATE 'utf8_unicode_ci',
`ordemmenu` INT(10) NULL DEFAULT NULL,
`codparent` INT(10) UNSIGNED NOT NULL,
`codmenuitem` INT(10) UNSIGNED NOT NULL,
`codmodulo` INT(10) UNSIGNED NOT NULL,
PRIMARY KEY (`codmodulo`, `codmenuitem`, `codmenuitem2`),
CONSTRAINT `FK_smenuitem_smodulos` FOREIGN KEY (`codmodulo`) REFERENCES `smodulos` (`codmodulo`)
)
COLLATE='utf8_unicode_ci'
ENGINE=InnoDB
ROW_FORMAT=DEFAULT
And an second one:
CREATE TABLE `smenuitememp` (
`codempresa` INT(10) UNSIGNED NOT NULL,
`codmodulo` INT(10) UNSIGNED NOT NULL,
`codmenuitem` INT(10) UNSIGNED NOT NULL,
PRIMARY KEY (`codmenuitem`, `codempresa`, `codmodulo`)
)
COLLATE='utf8_unicode_ci'
My problem it's i need to make an FK between codmenuitem
i have this sql command that are resulting on an error:
ALTER TABLE `smenuitememp` ADD CONSTRAINT `FK_smenuitememp_smenuitem` FOREIGN KEY (`codmenuitem`) REFERENCES `smenuitem` (`codmenuitem`);
When i try to execute it's return this error:
Someone has an idea?
Update... i was trying to solve the problem, and got an new question... T_T
CREATE TABLE `smenuitem` (
`nome` VARCHAR(150) NULL DEFAULT NULL COLLATE 'utf8_unicode_ci',
`url` VARCHAR(150) NULL DEFAULT NULL COLLATE 'utf8_unicode_ci',
`tipo` CHAR(4) NULL DEFAULT NULL COLLATE 'utf8_unicode_ci',
`ordemmenu` INT(10) NULL DEFAULT NULL,
`codparent` INT(10) UNSIGNED NOT NULL,
`codmenuitem` INT(10) UNSIGNED NOT NULL,
`codmodulo` INT(10) UNSIGNED NOT NULL,
PRIMARY KEY (`codmodulo`, `codmenuitem`),
INDEX `codmenuitem` (`codmenuitem`),
CONSTRAINT `FK_smenuitem_smodulos` FOREIGN KEY (`codmodulo`) REFERENCES `smodulos` (`codmodulo`)
)
COLLATE='utf8_unicode_ci'
ENGINE=InnoDB
ROW_FORMAT=DEFAULT
I solved the problem creating an index at the main table. But i don't know why i was having trouble without this index. If someone could ask me i would apreciate!
The foreign key column(s) must reference column(s) comprising a left-most prefix of the primary key or a unique key in the parent table.
In other words, the following examples work in InnoDB:
CREATE TABLE Foo ( a INT, b INT, c INT, PRIMARY KEY (a,b,c) );
CREATE TABLE Bar ( x INT, y INT );
ALTER TABLE Bar ADD FOREIGN KEY (x,y) REFERENCES Foo(b,c); -- WRONG
ALTER TABLE Bar ADD FOREIGN KEY (x,y) REFERENCES Foo(a,c); -- WRONG
ALTER TABLE Bar ADD FOREIGN KEY (x,y) REFERENCES Foo(a,b); -- RIGHT
ALTER TABLE Bar ADD FOREIGN KEY (x) REFERENCES Foo(b); -- WRONG
ALTER TABLE Bar ADD FOREIGN KEY (x) REFERENCES Foo(a); -- RIGHT
You got an error because you're trying to do the equivalent of (x) references Foo(b).
Your column codmenuitem is the second of three columns in the primary key of the parent.
It would work if smenuitememp.codemenuitem were to reference smenuitem.codmodulo, because that column is the leftmost column in the parent table's primary key.
Re your followup question:
Keep in mind the way foreign keys work. Every time you insert or update a row in the child table, it needs to look up a row in the parent table to verify that the value exists in the referenced column. If the column isn't indexed, it'll have to do a table-scan to achieve this lookup, and that would be very expensive, assuming your parent table grows.
If you try to look up a row based on the middle column of a multi-column index, the index doesn't help you. By analogy, it's like searching a telephone book for all people with a certain middle name.
Standard ANSI SQL requires that the referenced column be part of a PRIMARY KEY or UNIQUE KEY, and it requires that the foreign key columns match all the columns of a primary or unique constraint in the parent.
But InnoDB is more permissive. It still requires that the referenced column in the parent table be indexed so the lookup can be efficient, and that the referenced columns be the leftmost in the index. But a non-unique index is okay; it's allowed for a foreign key to reference it.
This can lead to weird cases like a child row that references more than one row in the parent, but it's expected that you will handle such anomalies.
I feel the need to emphasize the last point. You will get anomalous data if you define foreign keys to non-uniquely indexed columns in the parent. This will probably cause your queries to report rows multiple time when you do joins. You should not use this behavior of InnoDB; you should define foreign keys only to parent columns that are unique.

Categories