I have attempted to create the following tables:
Customer:
CREATE TABLE Customer(customer_id INT UNSIGNED NOT NULL AUTO_INCREMENT,
surname VARCHAR(15) NOT NULL,
forename VARCHAR(15) NOT NULL,
DOB TIMESTAMP NOT NULL,
phone_no VARCHAR(20) NOT NULL,
email_address VARCHAR(30),
postcode VARCHAR(15) NOT NULL,
PRIMARY KEY(customer_id)) ENGINE=INNODB;
When I attempt to create the 'Booking' table afterwards, I get an error
"ERROR 1005(HY000): can't create table 'Test.Booking' (errno:150)"
I checked the error online and found out that it was relating to the Foreign key connection that I attempted to make between the tables; which I will give below.
Booking:
CREATE TABLE Booking (booking_id INT UNSIGNED NOT NULL AUTO_INCREMENT,
customer_id INT NOT NULL,
staying_from TIMESTAMP,
staying_until TIMESTAMP,
cost INT,
PRIMARY KEY(booking_id),
FOREIGN KEY(customer_id) REFERENCES Customer(customer_id)
ON UPDATE CASCADE ON DELETE RESTRICT) ENGINE=INNODB;
As documented under FOREIGN KEY Constraints:
Foreign keys definitions are subject to the following conditions:
[ deletia ]
Corresponding columns in the foreign key and the referenced key must have similar internal data types inside InnoDB so that they can be compared without a type conversion. The size and sign of integer types must be the same. The length of string types need not be the same. For nonbinary (character) string columns, the character set and collation must be the same.
In Customer you have INT UNSIGNED whereas in Booking you have INT.
Related
I have the following structure of my database, implementing a simple EAV model (see pic):
My product has a type, which through the junction table restricts prop_names, available for this product. And here everything is clear.
BUT:
Then I've added a prop_values table to keep the properties values for each product. It has reference to products through prod_sku and to prop_names through prop_id. And here the problem comes: One can add to any product any properties - even those, which are not allowed for this product type. Also, there can be duplications - two or more same properties for a single product.
Is there any way to restrict this on the database level?
After the #BillKarvin's answer, I've tried the below CREATE code, but failed with the 'Foreign key constraint is incorrectly formed' error when creating the last table (property_values).
I have found my error - I forgot to add a KEY to the products table. Below is the corrected (working) version of my code:
CREATE TABLE product_types (
id INT PRIMARY KEY,
product_type varchar(50) NOT NULL,
block_css_id varchar(50) NOT NULL,
block_description varchar(50) NOT NULL
);
CREATE TABLE products (
sku varchar(50) PRIMARY KEY,
name varchar(50) NOT NULL,
price decimal(20,2) unsigned NOT NULL,
id_product_type INT NOT NULL,
FOREIGN KEY (id_product_type) REFERENCES product_types (id),
KEY (sku, id_product_type)
);
CREATE TABLE property_names (
id INT PRIMARY KEY,
property_name varchar(50) NOT NULL,
property_css_id varchar(50) NOT NULL,
property_input_name varchar(50) NOT NULL
);
CREATE TABLE junction_ptype_propname (
id_productt_type INT NOT NULL,
id_property_name INT NOT NULL,
PRIMARY KEY (id_productt_type, id_property_name),
FOREIGN KEY (id_productt_type) REFERENCES product_types (id),
FOREIGN KEY (id_property_name) REFERENCES property_names (id)
);
CREATE TABLE property_values (
id INT NOT NULL PRIMARY KEY,
product_sku varchar(50) NOT NULL,
property_id INT NOT NULL,
property_value decimal(20,2) NOT NULL DEFAULT 0.00,
id_prod_type INT NOT NULL,
UNIQUE KEY (product_sku, property_id),
FOREIGN KEY (product_sku, id_prod_type) REFERENCES products (sku, id_product_type),
FOREIGN KEY (property_id, id_prod_type) REFERENCES junction_ptype_propname (id_property_name, id_productt_type)
);
I would design this in the following way:
There are few important differences from your model:
prop_values has a unique key on (prod_sku, prop_id) so you can only have one instance of a given property per product sku.
prop_values has a prod_type column, and this references products, using both columns (sku, prod_type).
prop_values has a compound foreign key to junction_ptype_propname instead of prop_name.
Now the prod_type in prop_values can have a single value per row, and it must reference the correct product type in both the products table and the junction_ptype_propname table. So it is constrained to be a valid property for the given product, and a valid property for the product type. You therefore cannot add a property to a product that isn't legitimate for that product's type.
Here's the DDL:
create table prod_types (
id int primary key,
type_name varchar(30) not null
);
create table products (
sku varchar(30) primary key,
name varchar(30) not null,
type int not null,
foreign key (type) references prod_types(id),
key(sku, type)
);
create table prop_names (
id int primary key,
prop_name varchar(30) not null
);
create table junction_ptype_propname (
id_prop_name int not null,
id_prod_type int not null,
primary key (id_prop_name, id_prod_type),
foreign key (id_prod_type) references prod_types(id),
foreign key (id_prop_name) references prop_names(id)
);
create table prop_values (
id int primary key,
prod_sku varchar(30) not null,
prod_type int not null,
prop_id int not null,
prop_value decimal not null,
unique key (prod_sku, prop_id),
foreign key (prod_sku, prod_type) references products(sku, type),
foreign key (prop_id, prod_type) references junction_ptype_propname(id_prop_name, id_prod_type)
);
This question is fun because it's a case of using Fifth Normal Form. Many articles on database design claim that normal forms past the Third Normal Form aren't used. But your model disproves that.
Also, there can be duplications - two or more same properties for a
single product.
Use UNIQUE to prevent from duplications
w3schools.com - UNIQUE
Table 1
create table personal(
id int not null auto_increment unique,
name char(20) not null,
age int not null,
city varchar(20) not null default 'Delhi'
);
insert into personal(name,age,city) values
('anubhav',22,'delhi'),
('rohit',24,'agra');
Table 2
create table applications(
app_id int(5) not null auto_increment unique,
city varchar(10) not null default 'Delhi'
);
insert into applications(city) values
('kolkata'),
('mumbai'),
('mumbai'),
('delhi'),
('agra'),
('agra');
Then i apply foreign key here with the help of Alter command-
alter table personal add foreign key(city) references applications(app_id)
but i am getting an error: ERROR 1005 (HY000): Can't create table 'student.#sql-f40_3' (errno: 150)
MySQL specifies:
Conditions and Restrictions
1.Corresponding columns in the foreign key
and the referenced key must have similar data types. The size and sign
of fixed precision types such as INTEGER and DECIMAL must be the same.
The length of string types need not be the same. For nonbinary
(character) string columns, the character set and collation must be
the same.
2.MySQL requires indexes on foreign keys and referenced keys so that foreign key checks can be fast and not require a table scan. In the
referencing table, there must be an index where the foreign key
columns are listed as the first columns in the same order. Such an
index is created on the referencing table automatically if it does not
exist. This index might be silently dropped later if you create
another index that can be used to enforce the foreign key constraint.
index_name, if given, is used as described previously.
The data type must be the same.
You could do:
alter table personal add foreign key(city) references applications(city)
But, the columns on both tables should be indexed.
See here
you desing in not normalized
your personal table should only reference the id.
City name in the applications should be unique, so i added it in the create table, there is no need for two or more delhis in a table(see normalisation)
If you really want to use in personal the city name, you must like i already made refernece the coty name of appcations or define a KEY for that column.
Further the datatyoes of the columns must always be the saem in both table for the foreign key
create table personal(
id int not null auto_increment unique,
name char(20) not null,
age int not null,
city int not null default 0
);
create table applications(
app_id int not null auto_increment primary key,
city varchar(10) not null unique default 'Delhi'
);
alter table personal add foreign key(city) references applications(app_id)
You have small bugs such as not putting null in the insert for the autoincrement and if it is primary key you should not put not null.
Table personal
create table personal(
id int auto_increment primary key,
name char(20) not null,
age int not null,
city varchar(20) not null default 'Delhi'
);
insert into personal values (null,'anubhav',22,'delhi'),
(null,'rohit',24,'agra');
Table applications
create table applications(
app_id int(5) auto_increment primary key,
city varchar(10) not null default 'Delhi'
);
insert into applications values(null,'kolkata'),
(null,'mumbai'),
(null,'mumbai'),
(null,'delhi'),
(null,'agra'),
(null,'agra');
Alter table
alter table personal add foreign key(city) references applications(app_id)
CREATE TABLE eng(
d_id INT,
min_call_time DATETIME DEFAULT NULL,
max_call_time DATETIME DEFAULT NULL,
call INT DEFAULT 0,
min_meeting_time DATETIME DEFAULT NULL,
max_meeting_time DATETIME DEFAULT NULL,
cmeeting INT DEFAULT 0,
activities INT DEFAULT 0,
PRIMARY KEY (d_id)
);
CREATE TABLE cal(
id INT,
d_id INT,
c_meetings INT,
c_active INT,
c_cancelled INT,
min_start_time DATETIME,
max_start_time DATETIME,
PRIMARY KEY (id),
FOREIGN KEY (d_id) REFERENCES eng(d_id)
);
Error:
Error Code: 3780. Referencing column 'deal_id' and referenced column 'd_id' in foreign key constraint 'cal_ibfk_1' are incompatible.
I am using Mysql 8.0
Code works fine of DB fiddle though: https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=4b0d9723ae09dcebc677d2f014161222
Not working on Mysql.
This (Error number: 3780 Referencing column '%s' and referenced column '%s' in foreign key constraint '%s' are incompatible) is not the same as mine. Datatypes are the same in mine.
I really appreciate any help you can provide.
I think the issue here is the d_id column in the cal table is not declared as NOT NULL. This means that potentially a d_id value in that table could be NULL, and therefore could not be referenced back to d_id in the parent eng table. To remedy this problem, consider the following slight change to your cal table definition:
CREATE TABLE cal(
id INT,
d_id INT NOT NULL, -- change is here
c_meetings INT,
c_active INT,
c_cancelled INT,
min_start_time DATETIME,
max_start_time DATETIME,
PRIMARY KEY (id),
FOREIGN KEY (d_id) REFERENCES eng(d_id)
);
Note that primary key columns in MySQL are implicitly declared as NOT NULL, even if not implicitly defined as such. Therefore, your eng table is really being defined as:
CREATE TABLE eng(
d_id INT NOT NULL,
...,
PRIMARY KEY (d_id)
);
The issue with a potential NULL value for d_id in the child cal table is that NULL logically means "not known," and therefore such a value cannot possibly be connected back to the d_id primary key in the eng table.
I am getting error when I create table with foreign key
create table _users(_id int(20) unsigned NOT NULL AUTO_INCREMENT,
_user_fullname varchar(50)not null,
_user_username varchar(160) not null,
_user_password varchar(200) not null,_user_remember_me tinyint,
_user_email varchar(30),
_user_mobile varchar(15),
_user_age varchar(10)
,primary key(_id,_user_email,_user_mobile));
_users table created successfully..there were no error..
But When I want to create employee table :
CREATE TABLE employee ( _Id INT NOT NULL AUTO_INCREMENT,
_user_mobile VARCHAR(15) not null,
_name varchar(15),
_org varchar(10),
PRIMARY KEY (_Id),
foreign key (_user_mobile) references _users(_user_mobile));
Its showing error:
ERROR 1005 (HY000): Can't create table 'DB.employee' (errno: 150)
What am I doing wrong??
Hey In this case you just need to do one thing ,
you just need to add index to the reference column of the user table and then run the create table for employee
ALTER TABLE `_users` ADD INDEX (`_user_mobile`);
After running above query just run the below query :-
CREATE TABLE `employee`(
`_Id` INT(11) NOT NULL AUTO_INCREMENT,
`_user_mobile` VARCHAR(15) NOT NULL,
`_name` VARCHAR(15),
`_org` VARCHAR(10),
PRIMARY KEY (`_Id`),
FOREIGN KEY (`_user_mobile`) REFERENCES `_users`(`_user_mobile`) );
In this way you will get rid of the error 1005 of mysql which says that you need to have index on the reference column of parent table.
150 is a foreign key error:
C:\>perror 150
MySQL error code 150: Foreign key constraint is incorrectly formed
Getting the exact error message is very tricky. You need to run this query:
show engine innodb status
... and search in the output:
------------------------
LATEST FOREIGN KEY ERROR
------------------------
160627 14:09:32 Error in foreign key constraint of table test/employee:
foreign key (_user_mobile) references _users(_user_mobile)):
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.
Once you know that, it'd be easy to add the missing index:
ALTER TABLE `_users`
ADD UNIQUE INDEX `_user_email` (`_user_email`);
But I wouldn't if I were you. It's weird to use mobile phone number as key. Instead, just simplify the primary key:
create table _users(_id int(20) unsigned NOT NULL AUTO_INCREMENT,
_user_fullname varchar(50)not null,
_user_username varchar(160) not null,
_user_password varchar(200) not null,_user_remember_me tinyint,
_user_email varchar(30),
_user_mobile varchar(15),
_user_age varchar(10)
,primary key(_id));
... and use in the linked table:
CREATE TABLE employee ( _Id INT NOT NULL AUTO_INCREMENT,
_user_id int(20) unsigned not null,
_name varchar(15),
_org varchar(10),
PRIMARY KEY (_Id),
foreign key (_user_id) references _users(_id));
The problem is in the foreign key part. If you remove that, table will be created without a problem.
If you need to use that foreign key, you need to use InnoDB as the storage engine of MySQL. InnoDB allows a foreign key constraint to reference a non-unique key as can be seen in here.
So I don't understand why I cannot insert data in my table that have foreign constraint keys or even modify anything in it.
Here is an example of the tables that are created. I am trying to insert data in the addresses table:
///////////////////////ADDRESSES TABLE ////////////////////////
CREATE TABLE IF NOT EXISTS addresses (
id INT NOT NULL AUTO_INCREMENT,
addressline1 VARCHAR(255) NOT NULL,
addressline2 VARCHAR(255) NOT NULL,
postcode VARCHAR(255) NOT NULL,
phonenumber INT(13) NOT NULL,
country_id INT NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (country_id) REFERENCES countries(id)
ON UPDATE CASCADE
ON DELETE RESTRICT
) ENGINE=InnoDB ";
///////////////////////COUNTRIES TABLE ////////////////////////
CREATE TABLE IF NOT EXISTS countries (
id INT NOT NULL AUTO_INCREMENT,
countryname VARCHAR(255) NOT NULL,
PRIMARY KEY (id)
)
The issue here is that you are trying to insert into a referencing table (addresses) when the referenced entry (the country you reference) does not exist. That's what's triggering the FOREIGN KEY CONSTRAINT exception.
Try first inserting some countries into the countries table, then inserting some addresses where you reference those countries you entered in the first step.
As for your second question, that's a choice for you to make. I would probably choose to have the User have an Address (address field in the User table), but some of that depends on how the data is being used/updated.
Have a quick look through this resource if you're new to relational database design. It covers (in brief) topics like relationship types, key constraints, and normal forms.