Help with a microblog (twitter clone) database structure? - mysql

I'm working on an exercise that wants me to create a small twitter clone, with users, tweets and following system. Well, i came up with the following database structure:
CREATE TABLE tweets (
tweet_id INT NOT NULL AUTO_INCREMENT,
tweet VARCHAR(140) NOT NULL,
PRIMARY KEY (tweet_id)
) ENGINE=INNODB;
CREATE TABLE users (
user_id INT NOT NULL AUTO_INCREMENT,
user VARCHAR(255) NOT NULL,
password VARCHAR(40) NOT NULL,
email VARCHAR(255) NOT NULL,
PRIMARY KEY (user_id)
) ENGINE=INNODB;
CREATE TABLE user_tweets (
id INT NOT NULL AUTO_INCREMENT,
id_user INT NOT NULL,
id_tweet INT NOT NULL,
PRIMARY KEY(id),
FOREIGN KEY (id_tweet)
REFERENCES tweets(tweeth_id)
ON UPDATE NO ACTION ON DELETE NO ACTION,
FOREIGN KEY (id_user)
REFERENCES users(user_id)) ENGINE=INNODB;
CREATE TABLE followers (
id_user INT NOT NULL REFERENCES users (user_id),
id_following INT NOT NULL REFERENCES users (user_id),
PRIMARY KEY (id_user, id_following)
) ENGINE=INNODB;
Is it valid? Am i missing something? Also:
How do i select the tweets from a user?
How do i select the followers from a user?
How do i select the people a user is following?
I'm getting a little lost with the foreign key concept. :(

Building on the answer by #Karel,
I'd use slightly different tables:
CREATE TABLE tweets (
tweet_id INT NOT NULL AUTO_INCREMENT,
user_id INT NOT NULL
tweet VARCHAR(140) NOT NULL,
PRIMARY KEY (tweet_id),
FOREIGN KEY user_id(user_id) REFERENCES users(user_id)
ON UPDATE CASCADE ON DELETE CASCADE
) ENGINE=INNODB;
CREATE TABLE users (
user_id INT NOT NULL AUTO_INCREMENT,
user VARCHAR(255) NOT NULL,
/*password VARCHAR(40) NOT NULL,*/<<--- NEVER STORE A PASSWORD IN THE CLEAR!
passhash VARCHAR(40) NOT NULL,
email VARCHAR(255) NOT NULL,
PRIMARY KEY (user_id)
) ENGINE=INNODB;
CREATE TABLE followers (
id_user INT NOT NULL REFERENCES users (user_id),
id_following INT NOT NULL REFERENCES users (user_id),
PRIMARY KEY (id_user, id_following)
) ENGINE=INNODB;
How do i select the tweets from a user?
SELECT * FROM tweets WHERE user_id = 458
How do i select the followers from a user?
SELECT * FROM users
INNER JOIN followers ON (users.users_id = followers.id_user)
WHERE followers.id_following = 458
How do i select the people a user is following?
SELECT * FROM users
INNER JOIN followers ON (followers.id_following = users.user_id)
WHERE followers.id_user = 458
Use a SHA2 hash to compare the password.
And don't forget to add a salt to the hashing to prevent rainbow attacks.
SELECT user_id
FROM users
WHERE users.user = 'OralB'
AND users.passhash = SHA2(CONCAT(users.user,'secretToothbrush'),512)
SHA1 is no longer secure, so I'd advice using SHA2 with a 512bit hash length.
Links
MySQL tutorial: http://www.tizag.com/mysqlTutorial/
Foreign keys: http://dev.mysql.com/doc/refman/5.5/en/innodb-foreign-key-constraints.html
SHA2: http://dev.mysql.com/doc/refman/5.5/en/encryption-functions.html#function_sha2
Concat: http://dev.mysql.com/doc/refman/5.0/en/string-functions.html#function_concat
Why salt: What is "salt" when relating to MYSQL sha1?

You don't need a table 'user_tweet' because a tweet can only belong to 1 user, so it would be more logical to have a 'user_id' in you tweet-table
a crosstable like user_tweet is only useful when there is a many-to-many relationship (for example a teacher teaches multiple classgroups, classgroups get classes from multiple teachers)
if you do this you can select the tweets from a user by this sql-statement:
SELECT Tweet
FROM Tweets t (your table name)
WHERE t.User_ID == UserID_Whose_Tweets_you_want
you should now be able to get the followers with a similar query ;D
Hope you can do anything with this!

Related

Is it the best approach? Database modelling, 1-1 Relationship, foreign key as primary key

So I will explain my problem:
I have two types of users on my database: Admin and community_user..
Both share several attributes (Name, phone, status...)
But admin has an VARCHAR(50) specific field called "Position" as a mandatory field
and user has a field called "Vinculation", also a VARCHAR(60) as an optional field.
Both are strings typed by the user who have full freedom to type whatever they want to.
Does this modelling make sense? Using primary key as foreign key?
CREATE TABLE User (
PRIMARY KEY (id_user),
id_user INT NOT NULL AUTO_INCREMENT,
phone VARCHAR(50) NOT NULL,
user_status VARCHAR(50)
);
CREATE TABLE Manager (
id_user INT NOT NULL,
PRIMARY KEY (id_user),
FOREIGN KEY (id_user)
REFERENCES User(id_user)
ON DELETE CASCADE,
position VARCHAR(50) NOT NULL
);
/*Testing, you can ignore hehe*/
INSERT INTO User
(phone, user_status)
VALUES
("+5581", "carpe diem" ),
("+5583", "carpe cryy"),
("+5590", "carpe uhuu");
INSERT INTO Manager
(id_user, position)
VALUES
(1,"Sales Manager" ),
(2,"Accounting Manager"),
(3,"Community Manager");
SELECT * FROM User RIGHT JOIN Manager ON User.id_user = Manager.id_user

Proper way to create table friends in single statement

I have table users
CREATE TABLE IF NOT EXISTS users(
id int AUTO_INCREMENT PRIMARY KEY,
user_id INTEGER NOT NULL UNIQUE,
goal VARCHAR(255) DEFAULT NULL,
age INTEGER DEFAULT NULL,
gender VARCHAR(255) DEFAULT NULL,
country VARCHAR(255) DEFAULT NULL,
city VARCHAR(255) DEFAULT NULL,
comment VARCHAR(255) DEFAULT NULL)
I want to create table friends. One key feature that is every user by default friend for itself.
This is my current statement
create table friends (user_id int, friend_id int, FOREIGN KEY (user_id) REFERENCES users (user_id), foreign key (friend_id) references users (user_id)) as select user_id from users;
update friends set shown_id = user_id;
I think it looks pretty kludgy, creating a table and changing it immediately, may be there a better way to implement it?
Another important note: the database loses connection after creating the friends table.
create table friends (user_id int, friend_id int, FOREIGN KEY (user_id) REFERENCES users (user_id), foreign key (friend_id) references users (user_id)) as select user_id from users;
ERROR: 2006: MySQL server has gone away
The global session got disconnected..
Attempting to reconnect to 'mysqlx://root#localhost:33060/test_db'....
The global session was successfully reconnected.
Don't know where shown_id came from, but I guess it's a typo.
Instead of populating only one column (user_id) of your friends table, you can add another user_id column to the select statement with friend_id alias. Immediate update query is not needed.
create table friends (
user_id int,
friend_id int,
foreign key (user_id) references users (user_id),
foreign key (friend_id) references users (user_id)
) as (
select user_id, user_id as friend_id
from users
);
Original answer https://dba.stackexchange.com/a/266893/208647

MySQL create table one to many, what is the best option below?

I have below data and using mysql. Person_name is unique and TelephoneNumbers are unique per person.
Person_name1=TelephoneNumber1, TelephoneNumber2, TelephoneNumber3...
Person_name2=TelephoneNumber4, TelephoneNumber5, TelephoneNumber6...
Option 1. Create 1:Many master and child table.
CREATE TABLE Person (
personName varchar(50) NOT NULL,
id int NOT NULL AUTO_INCREMENT,
PRIMARY KEY (id),
UNIQUE KEY personName (personName)
);
CREATE TABLE Telephone (
telephoneNumber int,
mappingId int,
PRIMARY KEY (telephoneNumber),
foreign key(mappingId) references Person(id)
);
Option 2. Create one table with personName, telephoneNumber as Composite Key.
CREATE TABLE
Person_Telephone (
personName varchar(50) NOT NULL,
telephoneNumber int NOT NULL,
PRIMARY KEY(personName, telephoneNumber)
);
Option 1 is it over complicating creating two tables for just two fields?
Option 2 looks perfect and will there be any issues if Option 2 chosen over Option 1?
The option 2 gives you duplicate persons that you must control in every query.
The best is have the entities separate, it's a classic 1-N relation
Since users can have multiple phone numbers, I think 2 tables would be the best solution.
CREATE TABLE person (
PRIMARY KEY (id) AUTO_INCREMENT,
person_name VARCHAR(45) NOT NULL,
);
CREATE TABLE phone_number (
PRIMARY KEY (id) AUTO_INCREMENT,
phone_number VARCHAR(11) NOT NULL,
FOREIGN KEY (person_id) REFERENCES person(id)
)
Now you can simply JOIN the tables like this:
SELECT
t1.id,
t1.person_name,
t2.phone_number
FROM person t1
LEFT JOIN phone_number t2
ON (t1.id = t2.person_id);

error 1215: database design with foreign key

I am trying to create three tables such as associate, manager and attendance. The attendance table should be having employee and manager details from the other two table which should enable marking the attendance. I created this SQL script. I'm not sure where I am making mistake.
CREATE TABLE associate (
id INT NOT NULL,
idmanager INT NOT NULL,
emp_id DATE NOT NULL,
emp_name VARCHAR(25) NOT NULL,
FOREIGN KEY (id) REFERENCES attendance (associate_id) ON DELETE CASCADE,
FOREIGN KEY (idmanager) REFERENCES attendance (manager_idmanager) ON DELETE CASCADE,
PRIMARY KEY (id)
) ENGINE=INNODB;
CREATE TABLE manager (
id INT NOT NULL,
mgr_usr_id VARCHAR(15) NOT NULL,
mgr_name VARCHAR(25) NOT null,
KEY (id),
KEY (mgr_usr_id),
FOREIGN KEY (id) REFERENCES associate (idmanager) ON DELETE CASCADE,
PRIMARY KEY (id)
) ENGINE=INNODB;
CREATE TABLE attendance (
sno INT NOT NULL,
manager_idmanager INT NOT NULL,
associate_id INT NOT NULL,
date_stamp DATETIME,
state BIT NOT NULL,
PRIMARY KEY (sno)
) ENGINE=INNODB;
Screenshot
It's an issue of ordering. For example, the first statement executed is
CREATE TABLE associate (
which references attendance. However, the attendance table has not yet been created. Switch the order so that any tables that reference other tables come last.
Alternatively, don't put the FOREIGN KEY constraints in the CREATE statements, but them at the end of your script with ALTER TABLE statements. Consider:
CREATE TABLE associate (
id INT NOT NULL,
idmanager INT NOT NULL,
emp_id DATE NOT NULL,
emp_name VARCHAR(25) NOT NULL,
PRIMARY KEY (id)
) ENGINE=INNODB;
CREATE TABLE attendance (
sno INT NOT NULL,
manager_idmanager INT NOT NULL,
associate_id INT NOT NULL,
date_stamp DATETIME,
state BIT NOT NULL,
PRIMARY KEY (sno)
) ENGINE=INNODB;
ALTER TABLE associate ADD FOREIGN KEY (id) REFERENCES associate(id) ON DELETE CASCADE;
Edit
The above is just syntax. To model the requested problem consider orthogonality of information. You might also see/hear "normalization." The basic concept is this: have only one copy of your information. The schema should have a single point of authority for all data. For example, if a user has a birthdate, make sure you don't have an ancillary column that also stores their birthday; it's superfluous information and can lead to data errors.
In this case, what is the relationship? What must come first for the other to exist? Can an attendance be had without a manager? How about a manager without attendance? The former makes no sense. In this case then, I would actually use a third table, to form a hierarchy.
Then, consider that maybe roles change in a company. It would not behoove the DB architect to hard code roles as tables. Consider:
CREATE TABLE employee (
id INTEGER NOT NULL AUTO_INCREMENT,
name VARCHAR(25) NOT NULL,
PRIMARY KEY (id)
) ENGINE=INNODB;
CREATE TABLE role (
id INTEGER NOT NULL AUTO_INCREMENT,
name VARCHAR(30) NOT NULL,
description VARCHAR(254) NOT NULL,
PRIMARY KEY( id ),
UNIQUE( name )
) ENGINE=INNODB;
INSERT INTO role (name, description) VALUES
('associate', 'An associate is a ...'),
('manager', 'A manager follows ...');
CREATE TABLE employee_role (
employee_id INTEGER NOT NULL,
role_id INTEGER NOT NULL,
PRIMARY KEY (employee_id, role_id),
FOREIGN KEY (idemployee_id) REFERENCES employee_id (id) ON DELETE CASCADE,
FOREIGN KEY (role_id) REFERENCES role (id) ON DELETE CASCADE
) ENGINE=INNODB;
CREATE TABLE attendance (
sno INTEGER NOT NULL,
employee_id INTEGER NOT NULL,
date_stamp DATETIME,
state BIT NOT NULL,
PRIMARY KEY (sno),
FOREIGN KEY (idemployee_id) REFERENCES employee_id (id) ON DELETE CASCADE
) ENGINE=INNODB;
From this schema, the attendance needs only one foreign key because everyone is an employee. Employee's can have multiple roles, and they can change. Further, role definitions can change without needing to resort to costly DDL statements (data definition layer changes, like ALTER TABLE), and can be modified with simple DML (data manipulation layer changes, like UPDATE TABLE). The former involves rewriting all entries in the tables, and changing schemas, while the latter involves changing individual entries.

Mysql Foreign Key Usage

I'm trying my first hand at creating a mysql database for a simple blog. I'm having trouble understanding foreign keys and their appropriate relations. If someone can explain in "layman's" terms I'll be very happy.
I have a table called users that has the basics of fields (username, email, password etc) which I've created a user_type field and set it to INT. I've created the corresponding table called user_type and added two fields (one being the type_id = primary key and the other been the type = VARCHAR).
My question is:
Am I correct in understanding that I connect the two tables together by setting the foreign key link from the user_type INT in the users table to reference the type_id from the user_type table?
Your understanding is correct.
From SQL FOREIGN KEY Constraint
A FOREIGN KEY in one table points to a PRIMARY KEY in another table.
So in your example, the user_type id in table user_types would be the primary key, and the user_type int in table users would be the foreign key entry.
This enforces that an entry in table user_types has to exist before it can be used in table users.
You referencing from user to usertype:
n users have one user_type
If you create the table with an sql statement it should include something like this in the user part:
DROP TABLE IF EXISTS `user` ;
CREATE TABLE IF NOT EXISTS `user` (
`ID` INT NOT NULL AUTO_INCREMENT ,
`username` VARCHAR(55) NOT NULL ,
`email` VARCHAR(55) NOT NULL ,
`password` VARCHAR(55) NOT NULL ,
`user_type` INT NOT NULL ,
PRIMARY KEY (`ID`) ,
INDEX `user_to_usertype_idx` (`user_type` ASC) ,
CONSTRAINT `user_to_usertype`
FOREIGN KEY (`user_type` )
REFERENCES `user_type` (`type_id` )
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
You have to create user_type before you create user, otherwise you will get a failure.