MySQL Structure for a social network

AviateX14 picture AviateX14 · Mar 29, 2012 · Viewed 7.6k times · Source

(Before anyone asks, this is purely just for the learning experience, nothing more)

I'm experimenting by making a social network from scratch in PHP/MySQL, but I'm having trouble thinking of the optimal MySQL structure for it, currently I have:

This is a table which stores all user info:

fname varchar (300),
sname varchar (300),
pass varchar (400),
email varchar (300),
gender varchar (300),
dob varchar (200),
uid varchar (300),
PRIMARY KEY (id)

This is created when a user signs up, their own personal table:

id int(20) NOT NULL auto_increment,
            uid varchar (300),
            photo_url varchar (400),
            pfid varchar (300),
            phototime datetime,
            video_url varchar (400),
            vfid varchar (300),
            videotime datetime,
            status longtext,
            sid varchar (300),
            statustime datetime,
            blog longtext,
            bid varchar (300),
            blogtime datetime,
            about_bio longtext,
            about_current_job longtext,
            about_secondary_school longtext,
            about_primary_school longtext,
            about_college longtext,
            about_university longtext,
            about_workemail longtext,
            about_homeemail longtext,
            about_phonenumber longtext,
            about_relationshipstatus longtext,
            about_relationshipwith longtext,
            PRIMARY KEY (id)
            )";

The sessions table to track whether someone is logged in or not:

id int(20) NOT NULL auto_increment,
sid varchar(300),
uid varchar(300),
PRIMARY KEY (id)

Haven't gotten onto relationships yet but I was thinking:

id int(20) NOT NULL auto_increment,
requestby varchar(200),
requestto varchar(200),
status varchar(200)

Answer

Travesty3 picture Travesty3 · Mar 29, 2012

Well, you definitely shouldn't have one table per user. I think a database structure more like this would work really well:

CREATE TABLE users (
    userID INT NOT NULL AUTO_INCREMENT,
    firstName VARCHAR(30),
    lastName VARCHAR(30),
    password CHAR(32), -- should be encrypted, CHAR is better if the field is always the same length
    email VARCHAR(64) NOT NULL, -- not null if this is what you will use as a "username"
    PRIMARY KEY (userID)
);

CREATE TABLE personalInfo (
    userID INT NOT NULL,
    gender ENUM ('MALE', 'FEMALE'),
    dateOfBirth DATE,
    phoneNumber VARCHAR(15),
    personalEmail VARCHAR(64), -- may or may not be the same as the email field in the "users" table
    workEmail VARCHAR(64),
    bio TEXT,
    FOREIGN KEY (userID) REFERENCES users (userID)
);

/* this table is not specific to any single user. It is just a list of jobs that have been created */
CREATE TABLE jobs (
    jobID INT NOT NULL AUTO_INCREMENT,
    company VARCHAR(100),
    title VARCHAR(100),
    description TEXT,
    PRIMARY KEY (jobID)
);

/* the workInfo table will hold one entry per user per job. So if a user has held five jobs,
   there will be five rows with that userID in this table, each with a different jobID, which
   refers to an entry in the "jobs" table above. */
CREATE TABLE workInfo (
    userID INT NOT NULL,
    jobID INT NOT NULL,
    startDate DATE,
    endDate DATE, -- can set this to null if it's the user's current job
    FOREIGN KEY (userID) REFERENCES users (userID),
    FOREIGN KEY (jobID) REFERENCES jobs (jobID)
);

CREATE TABLE schools (
    schoolID INT NOT NULL AUTO_INCREMENT,
    schoolName VARCHAR(100),
    -- any other information you want to provide about the school (city, address, phone, etc)
    PRIMARY KEY (schoolID)
);

CREATE TABLE schoolPrograms (
    programID INT NOT NULL AUTO_INCREMENT,
    programName VARCHAR(100),
    -- any other information you want to provide about the program (department, teachers, etc)
    PRIMARY KEY (programID)
);

CREATE TABLE educationInfo (
    userID INT NOT NULL,
    schoolID INT,
    programID INT,
    startDate DATE,
    endDate DATE,
    FOREIGN KEY (userID) REFERENCES users (userID),
    FOREIGN KEY (schoolID) REFERENCES schools (schoolID),
    FOREIGN KEY (programID) REFERENCES schoolPrograms (programID)
);

CREATE TABLE relationships (
    userID INT NOT NULL,
    userID2 INT, -- allowed to be null if the user is single or does not specify who they are in a relationship with
    status ENUM ('SINGLE', 'IN A RELATIONSHIP', 'MARRIED', 'IT''S COMPLICATED' /* etc */),
    FOREIGN KEY (userID) REFERENCES users (userID)
);

/* each photo is created here. This way, when a user wants to share a photo,
   we don't have to duplicate each column. We just create another row in
   the "userPhotos" table below that) REFERENCES the same photoID. */
CREATE TABLE photos (
    photoID INT NOT NULL AUTO_INCREMENT,
    url VARCHAR(200),
    caption VARCHAR(200),
    dateOfUpload TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (photoID)
);

CREATE TABLE userPhotos (
    userID INT NOT NULL,
    photoID INT NOT NULL,
    FOREIGN KEY (userID) REFERENCES users (userID),
    FOREIGN KEY (photoID) REFERENCES photos (photoID)
);

/* vidoes, handled exactly the same as photos */
CREATE TABLE videos (
    videoID INT NOT NULL AUTO_INCREMENT,
    url VARCHAR(200),
    caption VARCHAR(200),
    dateOfUpload TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (videoID)
);

CREATE TABLE userVideos (
    userID INT NOT NULL,
    videoID INT NOT NULL,
    FOREIGN KEY (userID) REFERENCES users (userID),
    FOREIGN KEY (videoID) REFERENCES videos (videoID)
);

CREATE TABLE status (
    userID INT NOT NULL,
    status TEXT,
    FOREIGN KEY (userID) REFERENCES users (userID)
);