MySQL advise on building a database with connected tables - mysql

I want to build a database which holds information about users in a table:
User
-username (primary key)
-first_name
-second_name
-Image
In this database there will be another table like so:
Image
-name (primary key)
-file_name
What I want to achieve
I want each user to have Image as one of its fields. I understand to do this I have to connect the tables.
What I know so far
Firstly I should define the tables as InnoDB, then using phpmyadmin click on relationView.
The Question
How do I achieve the relationship I described above using phpmyadmin?

If a user have only one image it is one to one relationship. Everything can do with a one table.
Something like this:
CREATE TABLE users (
userId INT UNSIGNED NOT NULL AUTO_INCREMENT,
userFirstName VARCHAR(80) NOT NULL,
userSecondName VARCHAR(80),
imageName VARCHAR(100) NOT NULL,
PRIMARY KEY (userId)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
Multiple images have to one user, there is a one to many relationship. So you can create two tables and one lookup table.
Like this:
CREATE TABLE users (
userId INT UNSIGNED NOT NULL AUTO_INCREMENT,
userFirstName VARCHAR(80) NOT NULL,
userSecondName VARCHAR(80),
imageName VARCHAR(100) NOT NULL,
PRIMARY KEY (userId)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
CREATE TABLE images (
imageId INT UNSIGNED NOT NULL AUTO_INCREMENT,
imageName VARCHAR(100) NOT NULL,
PRIMARY KEY (imageId)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
Lookup table:
CREATE TABLE user_image (
userId INT UNSIGNED,
imageId INT UNSIGNED
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

You should put a column on table Image that will be reference on the table User, if for intance, a user can have multiple images. ex,
User
username (primary key)
first_name
second_name
Image
name (primary key)
file_name
userName (Foreign Key)
translated into DDL:
CREATE TABLE `User`
(
userName VARCHAR(15),
first_name VARCHAR(15),
second_name VARCHAR(15),
CONSTRAINT tb_pk PRIMARY KEY (userName),
CONSTRAINT tb_uq UNIQUE (first_name, last_name)
);
CREATE TABLE `Image`
(
name VARCHAR(15),
file_name VARCHAR(75),
userName VARCHAR(15)
CONSTRAINT tb_pk PRIMARY KEY (name),
CONSTRAINT tb_fk FOREIGN KEY (userName) REFERENCES `User`(userName)
);

Related

MySQL - Populate table column with values from another table

Need some help please. Creating a basic relational database and trying to add column values from my account table to my login table. However, bit stuck on how to achieve this. I'm trying to take the AccountID, Username, Sign_in data to populate the Login table but nothing appear when executed.
my code:
CREATE TABLE IF NOT EXISTS Account
(
AccountID int NOT NULL AUTO_INCREMENT,
Title VARCHAR(64) NOT NULL,
FirstName varchar(16) NOT NULL,
LastName varchar(32) NOT NULL,
DOB DATE,
Email VARCHAR(255),
Username varchar(32) UNIQUE NOT NULL,
Sign_in varchar(32) UNIQUE NOT NULL,
PRIMARY KEY (AccountID)
);
ALTER TABLE Account AUTO_INCREMENT=1;
CREATE TABLE IF NOT EXISTS Login
(
LoginID int NOT NULL AUTO_INCREMENT PRIMARY KEY,
AccountID INT NOT NULL,
Username varchar(32) NOT NULL,
Sign_in varchar(32) NOT NULL,
LoginDate TIMESTAMP(6),
FOREIGN KEY (AccountID) REFERENCES Account(AccountID),
FOREIGN KEY (Username) REFERENCES Account(Username),
FOREIGN KEY (Sign_in) REFERENCES Account(Sign_in)
);
ALTER TABLE Login AUTO_INCREMENT=100;
and tried the query (edited from a similar query found on this forum) to no avail
INSERT INTO Login
(
AccountID,
Username,
Sign_in
)
SELECT
a.AccountID, a.Username, a.Sign_in
FROM Account a
INNER JOIN Login
ON a.AccountID = l.AccountID;
Select * from Login;
Help/advice appreciated.
You are missing the point of relational databases. You simply want to map to the primary key and then look up the other values. You don't want to store the values in two places.
So:
CREATE TABLE IF NOT EXISTS Account (
AccountID int AUTO_INCREMENT PRIMARY KEY,
Title VARCHAR(64) NOT NULL,
FirstName varchar(16) NOT NULL,
LastName varchar(32) NOT NULL,
DOB DATE,
Email VARCHAR(255),
Username varchar(32) UNIQUE NOT NULL,
Sign_in varchar(32) UNIQUE NOT NULL
);
CREATE TABLE IF NOT EXISTS Login (
LoginID int NOT NULL AUTO_INCREMENT PRIMARY KEY,
AccountID INT NOT NULL,
LoginDate TIMESTAMP(6),
FOREIGN KEY (AccountID) REFERENCES Account(AccountID)
);
Then if you want the username or sign_in, you use a JOIN to look up that information.
I don't see a reason to set the auto-increment values. There is generally no problem having them start at 1 in all tables.
Managed to work it out...
INSERT INTO Login (AccountID, Username, Sign_in)
SELECT AccountID, Username, Sign_in
FROM Account;
Did take on board the advice regarding the Primary Key ID suggestion though. Cheers

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.

Creating MySQL relationships with foreign keys and alter statements

I will try to be specific because I feel my understanding of the subject isn't quite precise as well. My problem is understanding how to create relations between tables with foreign keys which I add with alter statements. I have these tables.
CREATE TABLE article (
content TEXT NOT NULL,
published_on DATE NOT NULL,
created_on DATE NOT NULL,
);
CREATE TABLE category(
name VARCHAR(30) NOT NULL,
date_created DATE NOT NULL,
);
CREATE TABLE user(
income FLOAT(30, 30) NOT NULL,
password VARCHAR(30) NOT NULL,
picture_url TEXT NOT NULL,
);
CREATE TABLE tag(
description VARCHAR(30) NOT NULL,
second_priority FLOAT(30, 30) NOT NULL,
);
To which I have to make there relationships:
Tag has a one to one connection to Category
Category has a many to one connection to User
User has a one to many connection to Article
And to do that I use there statements:
ALTER TABLE tag ADD CONSTRAINT FOREIGN KEY (tag_id) REFERENCES category (category_id);
ALTER TABLE category ADD CONSTRAINT FOREIGN KEY (user_id) REFERENCES user (user_id);
ALTER TABLE user ADD CONSTRAINT FOREIGN KEY (user_id) REFERENCES article (user_id);
My problem is that the third one fails. When I switch the places of article and user the constraint passes. After a bit of digging and experimenting I found out that I can't constraint two keys from which one is either UNIQUE or PRIMARY KEY and the other one just NOT NULL. So far I don't know how to continue, can someone please enlighten me as to how to create a one to one, many to one, one to many and a many to many relationship between these tables because I am kinda lost and everything in my head is a mess.
FULL STUFF:
CREATE DATABASE exam_database;
USE exam_database;
CREATE TABLE article (
content TEXT NOT NULL,
published_on DATE NOT NULL,
created_on DATE NOT NULL,
user_id INT(30) NOT NULL
);
CREATE TABLE category(
name VARCHAR(30) NOT NULL,
date_created DATE NOT NULL,
category_id INT(30) NOT NULL PRIMARY KEY AUTO_INCREMENT UNIQUE,
user_id INT(30) NOT NULL
);
CREATE TABLE user(
income FLOAT(30, 30) NOT NULL,
password VARCHAR(30) NOT NULL,
picture_url TEXT NOT NULL,
user_id INT(30) NOT NULL PRIMARY KEY AUTO_INCREMENT UNIQUE
);
CREATE TABLE tag(
description VARCHAR(30) NOT NULL,
second_priority FLOAT(30, 30) NOT NULL,
tag_id INT(30) NOT NULL PRIMARY KEY AUTO_INCREMENT UNIQUE
);
ALTER TABLE tag ADD CONSTRAINT FOREIGN KEY (tag_id) REFERENCES category (category_id);
ALTER TABLE category ADD CONSTRAINT FOREIGN KEY (user_id) REFERENCES user (user_id);
ALTER TABLE user ADD CONSTRAINT FOREIGN KEY (user_id) REFERENCES article (user_id);
First Your structure has some errors:
Missing PK, Why using INT(30)? etc...
Your DB should looks like:
CREATE DATABASE exam_database;
USE exam_database;
CREATE TABLE article (
id INT NOT NULL PRIMARY KEY AUTO_INCREMENT UNIQUE,
user_id INT NOT NULL,
content TEXT NOT NULL,
published_on DATE NOT NULL,
created_on DATE NOT NULL
);
CREATE TABLE category(
id INT NOT NULL PRIMARY KEY AUTO_INCREMENT UNIQUE,
user_id INT NOT NULL,
name VARCHAR(30) NOT NULL,
date_created DATE NOT NULL
);
CREATE TABLE user (
id INT NOT NULL PRIMARY KEY AUTO_INCREMENT UNIQUE ,
income FLOAT(30, 30) NOT NULL,
password VARCHAR(30) NOT NULL,
picture_url TEXT NOT NULL
);
CREATE TABLE tag (
id INT NOT NULL PRIMARY KEY AUTO_INCREMENT UNIQUE,
category_id INT NOT NULL,
description VARCHAR(30) NOT NULL,
second_priority FLOAT(30, 30) NOT NULL
);
Second Your FKs should look like:
ALTER TABLE tag ADD CONSTRAINT FOREIGN KEY (category_id) REFERENCES category (id);
ALTER TABLE category ADD CONSTRAINT FOREIGN KEY (user_id) REFERENCES user (id);
ALTER TABLE article ADD CONSTRAINT FOREIGN KEY (user_id) REFERENCES user (id);

Foreign key as primary key doesn't work if FK table has composite primary key (FK is not part of the composite)

two tables, created using these scripts:
create table user_auth
(
username varchar(255) NOT NULL,
password varchar(255) NOT NULL,
user_id varchar(36) NOT NULL,
PRIMARY KEY(username, password)
)engine=innodb;
create table user
(
user_id varchar(36) NOT NULL,
PRIMARY KEY(user_id),
FOREIGN KEY(user_id) REFERENCES user_auth(user_id) ON DELETE CASCADE
)engine=innodb;
I get the error:
Can't create table 'xxx.user' (errno: 150)
A foreign key error.
IF instead I do this (remove foreign key constraint but still reference user_auth):
create table user_auth
(
username varchar(255) NOT NULL,
password varchar(255) NOT NULL,
user_id varchar(36) NOT NULL,
PRIMARY KEY(username, password)
)engine=innodb;
create table user
(
user_id varchar(36) NOT NULL REFERENCES user_auth(user_id) ON DELETE CASCADE,
PRIMARY KEY(user_id),
)engine=innodb;
Everything is just peachy, BUT I can insert a user_id into the user table without having a corresponding key in user_auth, which puts a hole in my referential integrity.
Now for kicks say I do this (remove composite key and make user_id a primary key in user_auth):
create table user_auth
(
user_id varchar(36) NOT NULL,
PRIMARY KEY(username, password)
)engine=innodb;
create table user
(
user_id varchar(36) NOT NULL,
PRIMARY KEY(user_id),
FOREIGN KEY(user_id) REFERENCES user_auth(user_id) ON DELETE CASCADE
)engine=innodb;
This also works, though I do not have the username/password composite to ensure uniqueness.
I have a feeling I'm missing something pretty key in how MySQL works. Please enlighten.
Thanks for your time!
UPDATE
In the article ypercube linked in their answer, point three mentions the order of the PK and corresponding FK must be the same. If I add user_id as a PK in user_auth in the following order, the script works:
create table user_auth
(
username varchar(255) NOT NULL,
password varchar(255) NOT NULL,
user_id varchar(36) NOT NULL,
PRIMARY KEY(user_id, username, password)
)engine=innodb;
create table user
(
user_id varchar(36) NOT NULL,
PRIMARY KEY(user_id),
FOREIGN KEY(user_id) REFERENCES user_auth(user_id) ON DELETE CASCADE
)engine=innodb;
So I can still SELECT and such, but now I can't make duplicate username/password combos and thus each account will be unique since a username/password/user_id record must exist before I can insert user data.
Try:
create table user_auth
(
username varchar(255) NOT NULL,
password varchar(255) NOT NULL,
user_auth_id varchar(36) NOT NULL,
PRIMARY KEY(username, password)
)engine=innodb;
create table user
(
user_id varchar(36) NOT NULL,
user_username varchar(36) NOT NULL,
user_pass varchar(36) NOT NULL,
INDEX(user_username, user_pass),
PRIMARY KEY(user_id),
FOREIGN KEY(user_username, user_pass) REFERENCES user_auth(username, password) ON DELETE CASCADE
)engine=innodb;
Reference: http://dev.mysql.com/doc/refman/5.5/en/innodb-foreign-key-constraints.html
Point 3 in http://dev.mysql.com/doc/refman/5.5/en/innodb-foreign-key-constraints.html says everything. So if I add user_id as a PK in user_auth (I thought I mentioned I tried this, but it seems I missed the script example), then it still might not work:
create table user_auth
(
username varchar(255) NOT NULL,
password varchar(255) NOT NULL,
user_id varchar(36) NOT NULL,
PRIMARY KEY(username, password, user_id) -- <== DOES NOT WORK
)engine=innodb;
create table user
(
user_id varchar(36) NOT NULL,
PRIMARY KEY(user_id),
FOREIGN KEY(user_id) REFERENCES user_auth(user_id) ON DELETE CASCADE
)engine=innodb;
But, if I change the order around...
create table user_auth
(
username varchar(255) NOT NULL,
password varchar(255) NOT NULL,
user_id varchar(36) NOT NULL,
PRIMARY KEY(user_id, username, password) -- <== WORKS!
)engine=innodb;
create table user
(
user_id varchar(36) NOT NULL,
PRIMARY KEY(user_id),
FOREIGN KEY(user_id) REFERENCES user_auth(user_id) ON DELETE CASCADE
)engine=innodb;
Because in order to user the PK of user_auth as an FK, they must be in the same order as indices, (comment if I am misunderstanding something).
But in terms of table design we still have an issue, the composite key means I could have duplicate user_ids in user_auth, so a smarter design would be:
create table user_auth
(
username varchar(255) NOT NULL,
password varchar(255) NOT NULL,
user_id varchar(36) NOT NULL,
PRIMARY KEY(user_id),
UNIQUE KEY(username) -- <== I should allow duplicate passwords, so just usernames should be unique
)engine=innodb;
create table user
(
user_id varchar(36) NOT NULL,
PRIMARY KEY(user_id),
FOREIGN KEY(user_id) REFERENCES user_auth(user_id) ON DELETE CASCADE
)engine=innodb;
Much better
The main take-away is that the order of your composite keys matters!

Foreign key constraints seem ignored by mysql

I am just making a foreign key reference of parent table in a child table. When I try to delete the row from the parent table whose reference is there in child table, surprisingly it allows me to delete it. I have tried to create child table explicitly by writing on delete restrict and also without it, but to no help. Any ideas why this is happening? Below is the code I am using while creating the tables.
CREATE TABLE region
(
id int PRIMARY KEY AUTO_INCREMENT,
name varchar(50) NOT NULL
);
CREATE TABLE aggregator
(
id int PRIMARY KEY AUTO_INCREMENT,
name varchar(50) NOT NULL
);
CREATE TABLE gateway
(
id int PRIMARY KEY AUTO_INCREMENT,
name varchar(50) NOT NULL,
region_id int ,
aggregator_id int ,
is_public boolean DEFAULT 0 NOT NULL,
FOREIGN KEY (region_id) REFERENCES region(id),
FOREIGN KEY (aggregator_id) REFERENCES aggregator(id)
);
Both parent and child table need to be INNODB tables.
Try:
CREATE TABLE region
(
id int PRIMARY KEY AUTO_INCREMENT,
name varchar(50) NOT NULL
) ENGINE=INNODB;
CREATE TABLE aggregator
(
id int PRIMARY KEY AUTO_INCREMENT,
name varchar(50) NOT NULL
) ENGINE=INNODB;
CREATE TABLE gateway
(
id int PRIMARY KEY AUTO_INCREMENT,
name varchar(50) NOT NULL,
region_id int ,
aggregator_id int ,
is_public boolean DEFAULT 0 NOT NULL,
FOREIGN KEY (region_id) REFERENCES region(id),
FOREIGN KEY (aggregator_id) REFERENCES aggregator(id)
) ENGINE=INNODB;
Do mean to say that if you delete parent table and child table deletes automatic? If yes then once go through cascading rules.