Error 1215 Can't add foreign key constraint - mysql

I've read several posts on this type of error (one of them was quite similar), but I haven't found one yet that resolves the error that I'm having with the foreign key. Since I can recreate the error, I think I have a pretty good idea of what it is. I am new to SQL, however, and I can't resolve the problem. Here's the code from the two affected tables:
create table artist (
artist_id int unsigned not null auto_increment,
first_name nvarchar(50) not null,
last_name nvarchar(50) not null,
about_artist nvarchar(550) not null,
start_of_event datetime,
end_of_event datetime,
item_id int unsigned not null,
user_id int unsigned not null,
last_modified timestamp,
primary key (artist_id),
foreign key (item_id) references
items (item_id),
foreign key (user_id) references
users (user_id)
);
create table items (
item_id int unsigned not null auto_increment,
artist_id int unsigned not null,
item_name nvarchar(50) not null,
item_description nvarchar(150) not null,
last_modified timestamp,
primary key (item_id),
foreign key (artist_id) references
artist(artist_id)
);
My item_id is item_id int unsigned not null, in the first table, but item_id int unsigned not null auto_increment, in the second table. The second table is the one where it is the primary key. I can't do two auto increments in one table, and if I reverse the order of the tables, the same thing happens with a different column. How can I resolve this? Thank you.

Thinking about my comment, I'm increasingly confident that the link table is the way you need to go.
create table artist (
artist_id int unsigned not null auto_increment,
first_name nvarchar(50) not null,
last_name nvarchar(50) not null,
about_artist nvarchar(550) not null,
start_of_event datetime,
end_of_event datetime,
user_id int unsigned not null,
last_modified timestamp,
primary key (artist_id),
foreign key (user_id) references
users (user_id)
);
create table items (
item_id int unsigned not null auto_increment,
artist_id int unsigned not null,
item_name nvarchar(50) not null,
item_description nvarchar(150) not null,
last_modified timestamp,
primary key (item_id)
);
create table artist_item (
artist_id int unsigned not null,
item_id int unsigned not null
foreign key (artist_id) references
artist(artist_id),
foreign key (item_id) references
items(item_id)
);
You could add an auto-increment field to artist_item, or have the two ID fields as a composite key.
With this, you can query for all items relating to an artist (e.g. one artist has several items):
select
*
from
artist_item join items on
artist_item.item_id = items.item_id
where
artist_item.artist_id = [ID]
or all artists related to an item (e.g. one item was worked on by several artists):
select
*
from
artist_item join artist on
artist_item.artist_id = artist.artist_id
where
artist_item.item_id = [ID]

Related

Can't figure out why mySql database syntax won't compile

I'm getting this syntax error for a DB I am writing for my own personal project and am unsure why this error is occuring, any help would be much appreciated! The desired result is just compilation at this point, and the error is a simple syntax error.
The problem table is the Team table.
Error Code: 1215: Cannot add foreign key contraint.
-- CREATE DATABASE basketBall;
DROP TABLE LEAGUE;
-- DROP TABLE TEAM;
DROP TABLE SESSION;
CREATE TABLE LEAGUE (
id INT NOT NULL AUTO_INCREMENT,
name VARCHAR(100) NOT NULL UNIQUE,
PRIMARY KEY(id)
);
CREATE TABLE SESSION (
year INT NOT NULL,
season VARCHAR(50) NOT NULL,
division VARCHAR(5) NOT NULL,
PRIMARY KEY(year, season, division),
CONSTRAINT chk_season CHECK (season IN ('Fall', 'Winter', 'Spring', 'Summer'))
);
CREATE TABLE TEAM (
id INT NOT NULL AUTO_INCREMENT,
name VARCHAR(255) NOT NULL,
season VARCHAR(50) NOT NULL,
year INT NOT NULL,
division VARCHAR(5) NOT NULL,
PRIMARY KEY(id),
FOREIGN KEY(season) REFERENCES SESSION(season),
FOREIGN KEY(year) REFERENCES SESSION(year),
FOREIGN KEY(division) REFERENCES SESSION(division)
);
CREATE TABLE PLAYER (
id INT NOT NULL AUTO_INCREMENT,
fname VARCHAR(30) NOT NULL,
lname VARCHAR(30) NOT NULL,
lid INT,
PRIMARY KEY(id)
);
CREATE TABLE GAME (
id INT NOT NULL AUTO_INCREMENT,
time VARCHAR(5),
court VARCHAR(20),
date DATE,
PRIMARY KEY(id)
);
CREATE TABLE STATS (
pid INT NOT NULL,
gid int NOT NULL,
pts INT NOT NULL,
fgm INT NOT NULL,
fga INT NOT NULL,
fta INT NOT NULL,
ftm INT NOT NULL,
3fgm INT NOT NULL,
3fga INT NOT NULL,
oreb INT NOT NULL,
dreb INT NOT NULL,
ast INT NOT NULL,
stl INT NOT NULL,
blk INT NOT NULL,
turnover INT NOT NULL,
eff INT NOT NULL,
pf INT NOT NULL,
min INT NOT NULL,
PRIMARY KEY(pid, gid),
FOREIGN KEY(pid) REFERENCES PLAYER(id),
FOREIGN KEY(gid) REFERENCES GAME(id)
);
CREATE TABLE Players_on_Team (
tid INT NOT NULL,
pid INT NOT NULL,
PRIMARY KEY(tid, pid),
FOREIGN KEY(tid) REFERENCES TEAM(id)
);
CREATE TABLE League_Sessions (
lid INT NOT NULL,
year INT NOT NULL,
season VARCHAR(50) NOT NULL,
division VARCHAR(5) NOT NULL,
PRIMARY KEY(lid, year, season, division),
FOREIGN KEY(lid) REFERENCES LEAGUE(id)
);
A column that you reference in a foreign key must be indexed. These two foreign keys in TEAM:
FOREIGN KEY(season) REFERENCES SESSION(season),
FOREIGN KEY(division) REFERENCES SESSION(division)
refer to columns that don't have indexes of their own. They're parts of a multi-column index, but only a prefix of a multi-column index acts as an index on those specific columns.
You could add separate indexes on the season and division columns to the SESSION table. But it would probably be more appropriate to make a multi-column foreign key:
FOREIGN KEY (year, season, division) REFERENCES SESSION(year, season, division)
I just tried it and it executes without any errors.

Why can't I add foreign key constraints

this is my code:
CREATE DATABASE exams;
SHOW DATABASES;
CREATE TABLE IF NOT EXISTS students(
student_id INT UNSIGNED NOT NULL AUTO_INCREMENT,
first_name VARCHAR(20) NOT NULL,
middle_name VARCHAR(40),
last_name VARCHAR(40)NOT NULL,
email VARCHAR(60) NOT NULL,
password CHAR(40) NOT NULL,
reg_date DATETIME NOT NULL,
PRIMARY KEY (student_id),
UNIQUE(email));
SHOW table status
INSERT INTO exams_3121(student_id, first_name, middle_name, last_name, email, password, reg_date)
CREATE TABLE entries
(
entrie_id int NOT NULL,
student_id int NOT NULL,
subject_id int,
PRIMARY KEY (entrie_id),
FOREIGN KEY (student_id) REFERENCES student(student_id),
FOREIGN KEY (subject_id)REFERENCES subject(subject_id)
)
CREATE DATABASE subjects;
CREATE TABLE IF NOT EXISTS subjects(
subject_id INT UNSIGNED NOT NULL AUTO_INCREMENT,
subject_name VARCHAR(20) NOT NULL,
level_entery VARCHAR(40)NOT NULL,
exam_board VARCHAR(60) NOT NULL,
PRIMARY KEY (subject_id));
CREATE TABLE entries
(
entrie_id int NOT NULL,
entrie_id int NOT NULL,
subject_id int,
PRIMARY KEY (entrie_id),
FOREIGN KEY (student_id) REFERENCES student(student_id),
FOREIGN KEY (subject_id)REFERENCES subject(subject_id)
)
When I use this code it says cannot add foreign key constraint
and I don't know what to do. Please and thanks in advance.
There are two problems.
First, you got the names of the table you're referencing wrong. The name of the tables are students and subjects, but you wrote student and subject.
Second, the entries table has two entrie_id columns. One of them should be student_id.
CREATE TABLE entries
(
entrie_id int NOT NULL,
student_id int NOT NULL,
subject_id int,
PRIMARY KEY (entrie_id),
FOREIGN KEY (student_id) REFERENCES students(student_id),
FOREIGN KEY (subject_id) REFERENCES subjects(subject_id)
)
Also, if you're creating multiple databases and putting your tables in them, you'll need to refer to tables with their database prefixes if they're different from the one you selected as default with the USE command. As you've written it, you're not actually using the databases you created with CREATE DATABASE.

Mark One and Only One Record as "Primary"

I'm writing a genealogy application and I'm trying to figure out on aspect of my database model.
I have a table for people:
create table person (
id int unsigned not null primary key
)
And I have a table for names:
create table name (
id int unsigned not null primary key,
person_id int unsigned not null,
first_name varchar(191),
last_name varchar(191),
foreign key (person_id) references person (id)
)
A person can have multiple names because sometimes they have different names in different censuses and other records.
But a person also has one particular name which we should display by default.
My first thought was to add a primary column to the table name:
create table person (
id int unsigned not null primary key
)
create table name (
id int unsigned not null primary key,
person_id int unsigned not null,
first_name varchar(191),
last_name varchar(191),
`primary` tinyint(1) not null default 0,
foreign key (person_id) references person (id)
)
This has a data-integrity issue. Multiple names that belong to a single person could have the primary flag set.
Another way I thought of was to add a primary_name_id column to the person table. This could link back to the primary name in the name table:
create table person (
id int unsigned not null primary key,
primary_name_id int unsigned default null,
foreign key (primary_name_id) references name (id)
)
create table name (
id int unsigned not null primary key,
person_id int unsigned not null,
first_name varchar(191),
last_name varchar(191),
foreign key (person_id) references person (id)
)
This also has has an integrity issue. primary_name_id might point to a name row that belongs to a different person. Also, it requires the primary_name_id column to be nullable because when a person is first created he has no names yet.
The third way I thought about doing this is to include duplicates of the "name" fields in the person record:
create table person (
id int unsigned not null primary key,
first_name varchar(191),
last_name varchar(191),
)
create table additional_name (
id int unsigned not null primary key,
person_id int unsigned not null,
first_name varchar(191),
last_name varchar(191),
foreign key (person_id) references person (id)
)
This doesn't seem like an ideal solution either. Similar kinds of data are being stored in two places. Also changing a person's primary name would require a bit of work. I'd have to insert a new additional_name, update the person, and delete an old additional name.
Is there a better way to do this?
Your second method is basically the right way. But, you want to be sure that the name is for the person. So:
create table person (
id int unsigned not null primary key,
primary_name_id int unsigned default null,
foreign key (id, primary_name_id) references name (person_id, id)
);
create table name (
id int unsigned not null primary key,
person_id int unsigned not null,
first_name varchar(191),
last_name varchar(191),
foreign key (person_id) references person (id),
unique (person_id, id);
);
The unique constraint is a bit of redundancy, but it let's you ensure that the values match across the two tables -- appropriately.

How add a customer to an order when getting the customer details from a form

I am having trouble adding a customer and their order to an order table once they have checked out.
Here is my SQL for creating the four tables I am using:
CREATE TABLE IF NOT EXISTS Product(
ID int NOT NULL AUTO_INCREMENT,
Name varchar(255) NOT NULL,
Description text(65535) NOT NULL,
Quantity int NOT NULL,
Photo varchar(255),
Price float NOT NULL,
Category varchar(50),
PRIMARY KEY (ID)
) ENGINE=innoDB;
CREATE TABLE IF NOT EXISTS Customer(
ID int NOT NULL AUTO_INCREMENT,
FirstName varchar(255) NOT NULL,
LastName varchar(255) NOT NULL,
Email varchar(255) NOT NULL,
PhoneNumber varchar(11) NOT NULL,
Address varchar(50),
Town varchar(50),
County varchar(50),
PostCode varchar(50),
PRIMARY KEY (ID)
) ENGINE=innoDB;
CREATE TABLE IF NOT EXISTS OrderTable(
ID int NOT NULL AUTO_INCREMENT,
Date date NOT NULL,
PRIMARY KEY (ID),
TotalPrice float NOT NULL,
Customer_ID int NOT NULL,
CONSTRAINT fk_Order_1
FOREIGN KEY (Customer_ID)
REFERENCES coursework_db.Customer (ID)
) ENGINE=innoDB;
CREATE TABLE IF NOT EXISTS OrderItem(
ID int NOT NULL AUTO_INCREMENT,
PRIMARY KEY (ID),
Product_ID int NOT NULL,
Order_ID int NOT NULL,
Quantity int NOT NULL,
TotalPrice float NOT NULL,
CONSTRAINT fk_OrderItem_1
FOREIGN KEY (Product_ID)
REFERENCES coursework_db.Product(ID),
CONSTRAINT fk_OrderItem_2
FOREIGN KEY (Order_ID)
REFERENCES coursework_db.OrderTable(ID)
) ENGINE=innoDB;
The problem I am having is how to select the customer from the table once they have been added to the database to use as a foreign key in the OrderTable table.
At the moment I have the details of the customer stored in local storage which can easily be accessed, but once the customer is added to the database they will get an ID. This is the only way I could think to select a unique customer.
Insert the customer details first. Then get the ID of the newly inserted customer and use it while inserting the order details!
You could use the LAST_INSERT_ID() after you insert the user details to the db to get the ID of the customer.
Or if you are using PHP, then:
if you're using PDO, use PDO::lastInsertId
if you're using Mysqli, use mysqli::$insert_id
Hope this helps.

Mysql Foreign keys error 150

I'm a mysql beginner and I'm currently working on foreign keys.
I would like to create three tables: users, items, orders and link them together
Users table:
CREATE TABLE users (
user_id INT(10) UNSIGNED ZEROFILL NOT NULL AUTO_INCREMENT,
name VARCHAR(20) NOT NULL,
PRIMARY KEY(user_id)
);
Items table:
CREATE TABLE items (
item_id INT(10) UNSIGNED ZEROFILL NOT NULL AUTO_INCREMENT,
name VARCHAR(20) NOT NULL,
PRIMARY KEY(item_id)
);
Orders table:
CREATE TABLE orders (
order_id INT(10) UNSIGNED ZEROFILL NOT NULL AUTO_INCREMENT,
item_id INT,
quantity INT(10) NOT NULL,
user_id INT,
PRIMARY KEY (order_id),
FOREIGN KEY (item_id) REFERENCES items (item_id),
FOREIGN KEY (user_id) REFERENCES users (user_id)
);
But I got the error 1005: can't create table 'new.orders' (error:150)
What is wrong with my code?
Thanks!
The data types of the primary table's column and the referencing table's columns must match exactly. In your definitions, items.item_id is INT UNSIGNED, while the foreign key orders.item_id is INT (implicitly SIGNED). The same is true for user_id.
Change the definition as follows, adding UNSIGNED for those two:
CREATE TABLE orders (
order_id INT(10) UNSIGNED ZEROFILL NOT NULL AUTO_INCREMENT,
item_id INT UNSIGNED,
quantity INT(10) NOT NULL,
user_id INT UNSIGNED,
PRIMARY KEY (order_id),
FOREIGN KEY (item_id) REFERENCES items (item_id),
FOREIGN KEY (user_id) REFERENCES users (user_id)
);
It then builds correctly: http://sqlfiddle.com/#!2/cfab8
There is no column student_id in items table. Did you mean user_id in users table?