seeking table organization advice

They have: 461 posts

Joined: Jul 2003

my friends and i are making a rateme site (i just want something that needs php and db interaction they want this specific type of thing, complete with forums, so it's all from scratch)

there's one last php issue in the signup, then it's all about getting the db up and the interacton working. so i figure now would be a good time to find out what those with more experience think about my thoughts on how to set this up, and what they suggest since i'm sure some people out there have gone through this looking for how to optimize things, and others have gone over this before, and considering where i am, i think there's a good chance some of those people are here, and a good chance most here have more experience than me and suggestions that will help me. i'm looking for pointers on data types (if you feel i'm using an inappropriate one, i wanna know what's appropriate and why. my gut feeling is that there's a number of feilds i'll be told i should use something else with, and if i know why someone feels that way i'd agree)

there's a lot of information we collect for profiles, which we use iframes to break into sections. my gut feeling is that each iframe should be it's own table. my friends i'm working with want to search people by username, so that needs to be unique... personally i want to keep it case insensitive. i can't think of any other relevant information to preface the design i'm thinking of, so here's what i'm thinking.... (note: tables will have names in place of numbers, i'm just not sure of the names for some)

feild info (type i'm thinking of using) [comment about setting/size]

table 1 (basic user info)
username (char 15) [html limits to 15 characters; mysql will limit as well; will be set into a cookie as you login]
password (char 15) [6 to 15 characters]
email address (tinytext)
site access groups (varchar) [will be set in a cookie. determines if you can get to certain pages in forums etc.]
affiliation (tinytext) [gives us a way to note those that donate to the site...noted in profiles and posts... will be set in a cookie for access by posts]
last login (text) [referring url incase there's an issue with the user]
what's approved (tinytext) [what's already approved: a==the entire profile; b==bio; p==pics; n== new user (just signed up) or everything has been updated)
user id # (int--autoincrement)

table 2 (user stats)
user id (int--synchs to table1)
dob-day (tinyint) [select menu]
dob-month (tinyint) [select menu]
dob-year (tinyint) [select menu]
gender (char 6) [select menu]
sexual preference (char 17) [select menu]
marital status (char 17) [select menu]
country of origin (varchar)
height-feet (tinyint) [select menu]
height-inches (tinyint) [select menu]
waist (tinyint)
eye color (char 10)
hair color (char 6) [select menu]
weight (smallint)
body type (char 20) [select menu]
level of education (char 9) [select menu]
employment status (char 13) [select menu]
religion (char) [max length 100]
ethnic background (char) [max length 100]
city (char) [max length 100]
state/province/territory (varchar) [select list. longest is 30 characters. smallest is 4, not sure average]
chinese zodiac (char 10) [select list]
regular zodiac (char10) [select list]
self catagorization (char 17) [select list]
aim name (char 16) [aol limits to 16 characters]
icq (smallint)
mirc (varchar)
msn (tinytext)
yim name (varchar)

table 3 (bio)
user id (int--synchs to table1)
bio question 1 (tinytext)
bio question 2 (tinytext)
bio question 3 (tinytext)
bio question 4 (tinytext)
source (char 100)
open bio (text) [may add a php check to keep it under 2500 characters)

table 4 (interests)
user id (int--synchs to table1)
movies (tinytext) [will be made into a comma delineated string from post]
books (tinytext) [will be made into a comma delineated string from post]
music (tinytext) [will be made into a comma delineated string from post]
pets (tinytext) [will be made into a comma delineated string from post]
sports (tinytext) [will be made into a comma delineated string from post]
misc (tinytext) [will be made into a comma delineated string from post]

table 5 (friends list)
user id of "owner" (int--synchs to table1)
user id of friend (int)
username of friend (char 15)
comment on friend (tinytext)

table 6 (user post info)
user id (int--synchs to table1)
avatar location (tinytext) [will be set by user]
"shout" (tinytext) [will be set by admin... something to toss up in the post or future post level feild]
postcount (int) [may not display this in an attempt to avoid "postwhore wars"...where two or more users see who can have more posts in a period of time]

table 7 (basic forum info)
forum id # (tinyint)
forum title (tinytext)

table 8 (threads in forum--should there be one total or one per forum?)
thread id# (int)
forum id# that thread is in (tinyint)
author id (int) [who created the topic]

table 9 (posts in thread--should there be one total or one per thread?)
post # (int)
thread post is in (int)
user posting (char 16)
subject of thread (tinytext)
made date (datetime)
edit count (tinyint)
last modification (datetime)
replytext (text) [post being replied to; if any]
post (text)
poster location (text) [referring url incase there's an issue with the post/user]

POSIX. because a stable os that doesn't have memory leaks and isn't buggy is always good.

Mark Hensler's picture

He has: 4,048 posts

Joined: Aug 2000

CREATE TABLE users (
    `uid` int(10) unsigned NOT NULL auto_increment,
    `username` varchar(15) NOT NULL,
    `password` varchar(16) NOT NULL,
    `email` varchar(50) NOT NULL,
    `access_mask` smallint(5) unsigned NOT NULL default '0',
    `approved` tinyint(3) unsigned NOT NULL default '0',
    `last_login` datetime NOT NULL default '0000-00-00 00:00:00'
    PRIMARY KEY  (`uid`),
    UNIQUE KEY `username` (`username`)
) TYPE=MyISAM

CREATE TABLE sessions (
    `session_id` varchar(40) NOT NULL,
    `session_ip` varchar(15) NOT NULL,
    `uid` int(10) unsigned NOT NULL default '0',
    `login` datetime NOT NULL default '0000-00-00 00:00:00',
    `last_action` datetime NOT NULL default '0000-00-00 00:00:00',
    `last_location` varchar(50) NOT NULL,
    KEY `uid` (`uid`),
    KEY `session` (`session_ip`,`session_id`)
) TYPE=HEAP;

CREATE TABLE user_stats (
    `uid` int(10) unsigned NOT NULL,
    `dob` date NOT NULL default '0000-00-00',
    `gender` char(1) NOT NULL,
    `sex_pref` char(3) NOT NULL,
    `marital` char(1) NOT NULL,
    `smoker` char(1) NOT NULL,
    `drinker` char(1) NOT NULL,
    `origin` varchar(50) NOT NULL,
    `height` tinyint(3) unsigned NOT NULL default '0',
    `waist` tinyint(3) unsigned NOT NULL default '0',
    `eyes` varchar(10) NOT NULL,
    `hair` varchar(10) NOT NULL,
    `weight` smallint(5) unsigned NOT NULL default '0',
    `body` tinyint(3) unsigned NOT NULL default '0',
    `edu` tinyint(3) unsigned NOT NULL default '0',
    `employment` tinyint(3) unsigned NOT NULL default '0',
    `religion` smallint(5) unsigned NOT NULL default '0',
    `ethnic` smallint(5) unsigned NOT NULL default '0',
    `city` varchar(50) NOT NULL,
    `state` varchar(30) NOT NULL,
    `self_cat` smallint(5) unsigned NOT NULL default '0',
    `aim` varchar(16) NOT NULL,
    `icq` int(5) unsigned NOT NULL default '0',
    `mirc` charchar(20) NOT NULL,
    `msn` varchar(50) NOT NULL,
    `yim` varchar(20) NOT NULL
    PRIMARY KEY (`uid`),
    KEY `dob` (`dob`),
    KEY `gender` (`gender`),
    KEY `sex_pref` (`sex_pref`),
    KEY `marital` (`marital`),
) TYPE=MyISAM

CREATE TABLE user_bio (
    `uid` int(10) unsigned NOT NULL,
    `bio1` text NOT NULL,
    `bio2` text NOT NULL,
    `bio3` text NOT NULL,
    `bio4` text NOT NULL,
    PRIMARY KEY (`uid`),
) TYPE=MyISAM

CREATE TABLE user_interests (
    `uid` int(10) unsigned NOT NULL,
    `movies` text NOT NULL,
    `books` text NOT NULL,
    `music` text NOT NULL,
    `pets` text NOT NULL,
    `sports` text NOT NULL,
    `other` text NOT NULL,
    PRIMARY KEY (`uid`),
) TYPE=MyISAM

CREATE TABLE user_friends (
    `uid` int(10) unsigned NOT NULL,
    `fid` int(10) unsigned NOT NULL,
    `comment` tinytext NOT NULL,
    PRIMARY KEY (`uid`,`fid`),
) TYPE=MyISAM
'

TINYTEXT is only 256 characters. That's not big enough for several of the places where you indicated use. A TEXT field is 64KB, and a MEDIUMTEXT is 16MB.

I've substituted numeric fields where you had character fields in several areas. An example is `users.approved`. You indicated 3 switches. Instead of using a character field, wich may take up to 3 bytes to store your data, consider using a single byte tinyint field. 1 byte has 8 bits. Thats 8 switches. So, byte zero = 'entire profile', byte one = 'bio', and byte two = 'pics'.

I only have one `dob` field. This is because you can store everything in one field. If you want to query only the month, you can use MySQL functions in your query to return only the month.

`user_stats.gender` can be indicated by a single characer: m,f

`user_stats.height` can be stored in one field by converting feet to inches before storing in the database. This will also make it easier to select a range later.

`user_stats.body` only needs to hold the select menu's index number, not the text.

I completely removed the 'chinese zodiac' and 'regular zodiac' because knowing the user's DOB, you can come up with it.

ICQ numbers don't fit in smallint fields. They actually take a 4 byte integer.

I've missed some other fields here and there. I either missed them, or didn't understand their use. I also didn't look over the forum tables. I'd suggest you acquire some forum software, and try to tie in your project.

MySQL Docs:
6.2 Column Types

Mark Hensler
If there is no answer on Google, then there is no question.

They have: 461 posts

Joined: Jul 2003

Mark- thank you. you're the first person at any of the three forums i've found that has people that do thisstuff to respond. also this happens to be the last one i found.

Quote: I've missed some other fields here and there. I either missed them, or didn't understand their use. I also didn't look over the forum tables. I'd suggest you acquire some forum software, and try to tie in your project

i've updated mocst of them based on what you said because i agree, i'm looking at the others you've switched to ints to use index numbers and am wondering on some if it might help you to see the sign up preview on the webspace i'll be losing at the end of july where which i've been using to create possible design and such based on what those i'm working with have been telling me.

we're going to use one of the versions of the preview 6 set of profiles. we haven't decided which one because everyone has a different idea for where the rating bar should go and we haven't had a chance to sit down and talk it over, but here's the profile as of now:
http://people.brandeis.edu/~m3rajk/JMT/preview/preview-profile6a.html
and here's the sign up with some debugging stuff as we're trying to get it to validate. it loses step when you get to step 4. for some reason it's not being passed. that has been happeneing since i added the max upload size (we haven't test uploads because we're waiting to get the validation to work. we're not sure we'd be able to on there).
http://people.brandeis.edu/~m3rajk/JMT/preview/phpprev/signup.php

the reason we're not downloading phpbb invasion or one of the other boards is because this is an attempt to show off what i was able to do with php/mysql. so i want the entire thing to be my creation.

getting the forums up is secondary to getting the profiles working. we also haven't talked much about the messaging system. we all agree we want one, but one likes the version with mail and pop up alerts, the other person i'm working with like seperate mail and "instant messages" that pop up. they both have advantages and disadvantages in practice. i'm leaning toward the mail and pop ups since i think it would be easier. but the priority we decided on was profiles, forums, messaging system. so i've put the messaging system off and started looking at forums since i've seen they are definitely the lifeblood of a site

POSIX. because a stable os that doesn't have memory leaks and isn't buggy is always good.

Mark Hensler's picture

He has: 4,048 posts

Joined: Aug 2000

Quote: Originally posted by m3rajk
i'm looking at the others you've switched to ints to use index numbers and am wondering...

Which fields did you have questions on?

Mark Hensler
If there is no answer on Google, then there is no question.

They have: 461 posts

Joined: Jul 2003

there's a couple you have varchar(50) when i know at least one i use html to limit it to 100 characters.

i was wondering why the varchar is set to 50 there. and for weight i noticed you have tinyint(3) unsigned. even though i doubt anyone weighing over 1000 lbs would want to be on a site like this, since it is possible to have a 4 digit weight, should it not be tinyint(4) unsigned?

POSIX. because a stable os that doesn't have memory leaks and isn't buggy is always good.

Mark Hensler's picture

He has: 4,048 posts

Joined: Aug 2000

In the case of integer fields, the number in parenthesis does not effect the capacity of the field. That number simply indicates the maximum display size, which is really ignored unless you also define the field as ZEROFILL.

A tinyint is 1 byte. Unsigned, thats 256 max.
A smallint is 2 bytes. Unsigned, 65535.
(mediumint = 3 bytes, int = 4 bytes, and bigint = 8 bytes)

I changed `user_stats.city` from varchar(100) to varchar(50) because really, how many city names do not fit in 50 chars?

I changed `user_stats.religion` from varchar(100) to smallint(50) because I figured a select box would suffice for a list of religions. A 2 byte integer field will allow you to store the index of up to 65,535 different religions.

I noticed on your form, that you have a select box for hair color but not eye color. Why not for eye color? You could store that in an integer field as well. If you would settle for a 265 color selection, you could store the index in a tinyint field. That's 1 byte opposed to a possible 10 bytes with varchar(10).

I didn't change state/province to a integer field because I doubt everyone will live within the US. And allowing them to enter the text manually is easier than acquiring a list of all states/provinces world-wide.

I changed the tinytext fields in `user_interests` to text fields because tinytext is only 256 bytes, whereas text is 65,535 bytes.

Mark Hensler
If there is no answer on Google, then there is no question.

They have: 461 posts

Joined: Jul 2003

when i was writing it up a friend of mine linked me to a johnson & johnson page asking me which color contacts she should get. i figured most of them can be abbreviated.. and there was a wider selection than i'd have ever considered. but yeah, i see the point with eye color.

POSIX. because a stable os that doesn't have memory leaks and isn't buggy is always good.

They have: 461 posts

Joined: Jul 2003

well. i found the dates for regular zodiac. now i need to know the order for chinese zodiac. i know 79 was ram and 74 was tiger, and it's a 12 yr cycle, but that's all.once i know them all, the order and have a year to use as a calculating opint (hmmm... 1979?) then i can create a function for it like i did regular zodiac...

function findRZodiac($month, $day){ #finds regular zodiac
if((($month==1)&&($day>19))||($month==2)&&($day<19)){
return 'Aquarius'; # January 20 - February 18
}elseif((($month==2)&&($day>18))||($month==3)&&($day<21)){
return 'Pisces'; # February 19 - March 20
}elseif((($month==3)&&($day>20))||($month==4)&&($day<20)){
return 'Aries'; # March 21 - April 19
}elseif((($month==4)&&($day>19))||($month==5)&&($day<21)){
return 'Taurus'; # April 20 - May 20
}elseif((($month==5)&&($day>20))||($month==6)&&($day<22)){
return 'Gemini'; # May 21 - June 21
}elseif((($month==6)&&($day>21))||($month==7)&&($day<23)){
return 'Cancer'; # June 22 -July 22
}elseif((($month==7)&&($day>22))||($month==8)&&($day<23)){
return 'Leo'; # July 23 - August 22
}elseif((($month==8)&&($day>22))||($month==9)&&($day<23)){
return 'Virgo'; # August 23 - September 22
}elseif((($month==9)&&($day>22))||($month==10)&&($day<23)){
return 'Libra'; # September 23-October 22
}elseif((($month==10)&&($day>22))||($month==11)&&($day<22)){
return 'Scorpio'; # October 23 - November 21
}elseif((($month==11)&&($day>21))||($month==12)&&($day<22)){
return 'Sagittarius'; # November 22 - December 21
}elseif((($month==12)&&($day>21))||($month==1)&&($day<20)){
return 'Capricorn'; # December 22 -January 19
}
}

1900 works better since it's the earliest choice. infact, all i need then is to subtract 1900 from the year entered and then mod by 12.

only question is, how can i set the year to "please select" or something like that when it's not chosen while using the forloop i have? this function gets the chinese zodiac perfectly:

function findCZodiac($doby){
$sign=($doby-1900)%12; # $doby (user's year of birth) - 1900 (earliest year choosable) mod 12 (# of signs)
if($sign==0){ return 'Rat'; }
elseif($sign==1){ return 'Ox'; }
elseif($sign==2){ return 'Tiger'; }
elseif($sign==3){ return 'Rabbit'; }
elseif($sign==4){ return 'Dragon'; }
elseif($sign==5){ return 'Snake'; }
elseif($sign==6){ return 'Horse'; }
elseif($sign==7){ return 'Ram'; }
elseif($sign==8){ return 'Monkey'; }
elseif($sign==9){ return 'Rooster'; }
elseif($sign==10){ return 'Dog'; }
elseif($sign==11){ return 'Pig'; }
}

POSIX. because a stable os that doesn't have memory leaks and isn't buggy is always good.

Want to join the discussion? Create an account or log in if you already have one. Joining is fast, free and painless! We’ll even whisk you back here when you’ve finished.