Efficient mysql db structure advice - php

I'm developing a site that will be a subscription based service that will provide users several courses (videos) based on whatever they signed up for.
Currently I was considering the following db structure
Users
------
email | pwd | subscription_date | expiration_date
Unique Key would be "email"
Course_Subscription
-------
email | calculus_1 | calculus_2 | physics_1 | physics_2 ... | Nth course
the number of courses offered will probably start at approx 15, and gradually increase overtime. Also the course subscriptions will be boolean value of TRUE/FALSE
then a table for each course as follows:
Calculus_1
----------
id | title | description | video_url |
there could be more than 20 chapters in a single course.
A little bit of info on authentication process - it will go userlogin ---> course subscription ---> course chapters. Where both user login and course subscription will be verified against the email address. The videos will also be checked against the subscription table prior to being played.
My questions are:
Is this the best way to structure this? Or are there better alternatives?
Would this cause any problems in terms of performance? Or would it not be noticeable?
Here is a sample of a php script that I'll use to authenticate and populate the html
$sqlSubscription = "SELECT * FROM course_subscription WHERE `user` = $user && `calculus_1` = TRUE";
$subscriptionResult = mysql_query($sql) or mysql_die($sqlSubscription);
while ($row = mysql_fetch_assoc($subscriptionResult))
{
$user=$row["email"];
$calculus_1 =$row["calculus_1"];
if($user==1 && calculus_1==TRUE)
{
$sql = "SELECT * FROM calculus_1 ORDER BY `id`";
$result = mysql_query($sql) or mysql_die($sql);
if (mysql_num_rows($result) > 0)
{
$data = array();
while ($row = mysql_fetch_assoc($result))
{
$data[] = $rows;
echo "HTML THAT WILL CREATE A LIST BASED ON TABLE INFO"
}
}
}
}
The above code is for the menu that will populate a list of chapters based on their subscription. I know the code isn't perfect, I'm still working on it - but I wanted to nail down the structure of the db first now that I have a fairly decent idea of how I'll be accessing the information.

A design that requires changing that data model by adding new columns and tables just to add new data, like courses, is not a good design. You should have a table with courses and a table for subscriptions.
Also, email is not a very good choice of primary key. The primary key should never change, but people may want to change their email address. For this reason an autoincrement number is often used as the pk.
A schema that takes these suggestions into account would look like this:
students courses subscriptions
--------------- ----------- -------------
student_id course_id subscription_id
email name student_id (foreign key to students table)
name description course_id (foreign key to courses table)
subscription date video_url
You may have to adapt this to your specific requirements. For example the subscription expiry date: If the expiry date depends only on the the student and not on the course it can make sense to have it in the students table like you do now. But, if a student can subscribe to different courses at different dates and you want the possibility of having a different expiry date for each subscription it should be in the subscriptions table instead.

Your design would be horrible to maintain over time. What you are proposing means that every new course would add one more column to your course_subscription table, and a new table to the database.
I'd go for a structure where you have a user table, a course table describing the individual courses (including the video url, etc.), and a user_course_subscription table, that basically consists of a user_id and a course_id, and the start-date and end-date.
This removes the requirement of having a single column for every course, while still allowing you to add students to multiple courses. It's an example of the pretty standard "many to many" relationship, where the junction table (in this case user_course_subscription) just adds the link between the other two entities.

Related

PHP Link user table to another table

Hi I am in the process of making a website that includes a user registration system for my final year of high school major project. The website stores driving logs for learner drivers. I'm kind of confused as to how I should desgin the database. I have a users table which stores the personal information of each user of the site. However, I would like the user to be able to insert information into another table which would be their "logbook" and this to be displayed on the my account page. Do I need to create a table within the database for each user or is there a way of connecting the tables so that i do not have to.
You do not need to create a table for each user. Instead, add a column in your "logbook" table which will contain and refer to the "id" of the user it's tracking. This will likely be the primary key of your "users" table. Then, to get the logs for a specific user, you would query the logbook table for rows only with at specific user ID.
Furthermore, in a more sophisticated setup, you can add constraints to link the two columns. See http://dev.mysql.com/doc/refman/5.6/en/create-table-foreign-keys.html
U will not need table for each user...
Just one table will help u out...
The other table where u want to store user logs should only have reference to user I'd that u have created in users table..
Primary and foreign key - relational table concepts
For eg:
Let ur user has
1.userid
2.first name
3.lastname.... And other colums
Then ur userlogbook wala table should have
1.logid
2.userid
3.other columns...
Hope u got it..
You only need 1 table for the users, each user will be a row inside that table.
As you see in this table below, you need a way to be able to track which logbook record belongs to which user. That's done by storing the users ID (or any unique identifier, usually the primary key) to know exactly which user created the record.
-------------- -----------------
| User Table | | Logbook Table |
------------------------- -----------------------------------
| id | name | ...etc... | | id | user_id | date | ...etc... |
------------------------- -----------------------------------
| |
|_____________________________________|
I don't know how your system works, but I assume you know when a user is logged in right? Probably store their id in a session yeah? Well when you're inserting the logbook record, all you need to do is parse through their user ID in addition:
INSERT INTO logbook (id, user_id, .....) VALUES (NULL, $THE_USER_ID_FROM_SESSION, .....)
The above is pseudo code, you'd need to sanitize the input and actually assign the user id to a variable.
Now for fetching the user-specific information, all you need to do is add a simple WHERE clause:
SELECT id,column_1,column_2,... FROM logbook WHERE `user_id` = $THE_USER_ID_FROM_SESSION
The above is pseudo code, you'd need to sanitize the input and actually assign the user id to a variable.
There are a few questions I have, how much reading/writing are you going to be doing to the table? How are your tables set up?

Ideal way to manage DB's table.users for future development?

Need to mention first that i'am a newbie in PHP/MySQL. I would like to hear from you, from your experience, what's the best way or approach to deal with a table rows such as tbl.users for future development and compatibility with other features on web application ?
Currently, I have a tablename users like shown below:
id catid firstname lastname username email password status image
14 21 Joe1 Doe joe1.doe jd#m.cc sha512ed 1 pic.jpg
15 17 Joe2 Doe joe2.doe jd#m.cc sha512ed 1 pic.jpg
18 22 Joe3 Doe joe3.doe jd#m.cc sha512ed 1 pic.jpg
33 20 Joe4 Doe joe4.doe jd#m.cc sha512ed 1 pic.jpg
Now when I'm done with users, I would like to create an basic e-commerce with products, and clients, etc... And here comes the question, how should i work it out without need to recreate a tablename clients ?
Would be it clever to add a new column to tbl.users such as attributes and store some attribute there to extend the functionality such as client = 1 or something like that ?
So it will become like this:
id username ... attributes
14 joe1.doe ... rememberme = 1, client = 1
15 joe2.doe ... rememberme = 1, client = 0
18 joe3.doe ... rememberme = 0, client = 0
33 joe4.doe ... rememberme = 1, client = 1
Meaning that user.id = 14, 33 will become clients, and will be displayed appropriately in e-commerce component ?
If it's ok, how should I store that attributes information ? I guess the way I made it is not right.
i learned that its better not to mix tables, i mean if you have users table, dont add cart stuff info into it, will make it hard in the future to read the table, and you wont understand why you added that info into the users table.
the question is what clients are? non users, just visitors or users as well?
if they are users, you should make clients table, with unique id, user_id, client_id,
very basic table that will allow you to get the number of clients that user have, and in the future you can add more columns into the table like, items_bought and much more, you should do that if a user will get multi clients, witch i think is the case.
but if each user will have 1 client (i dont think its the case), you can add column into the user table client_of but then you can't store multi clients, only one.
so for the future, dont mix tables, each "theme" should have its own table, in my opinion of course.
P.S
you have many options when you have 2 tables, so dont add the same attr to both of the tables, add all the info of the users to the users table, if you need the user info of a client, get his id from the client table and then get the info from the users table, but if you need an info that only clients need, then add that attr to the client table.
edited:
quick example :
users table:
`id` `first_name` `last_name` `username` `password` `date`
`1` `alex` `maya` `alex.maya` `pass12` `yesterday`
`2` `bob` `smith` `bob.smith` `pass43` `today`
the client table:
`id` `user_id` `client_id`
`1` `1` `2`
`2` `2` `1`
this tables says that alex bought from bob and bob bought from alex, lets say i'm bob, and i want to see the info of the user that bought from me:
$sql = "SELECT client_id FROM clients WHERE user_id = {$user_id}"; // output = the id of the users who are his clients.
`
First, I recommend you read a bit more about the design database, particularly on how to obtain best tables by normalization.
You will see that you should first design your database graphically, making a simple diagram with entities and relations between them.
As object-oriented programming, you want to have more general tables with minimal data common to several types, for example a person table which you can then specialize in Customers, Vendors, Employees, etc., if your design requires it.
The next step is to ask how these entities are related, that way you can see that you need a new table for the relationship or simply add a unique ID in the other table.
Here I leave a link to learn the issues that I mentioned to you earlier: http://www.sqlcourse.com/index.html

How to design a database to keep track of books my family owns?

I am not necessarily looking for MySQL or PHP code. Rather I'm trying to get a concept of how to set everything up.
I want to create a database using MySQL (and using PHP to update it) of all the books my family owns. I want to set up different 'bookshelves' for each person in my family so we can see who has a certain book.
My first thought was to have a table for all the titles, authors, etc and have a field for user id to show who had the book. However, I might have a copy of Hunger Games and my grandmother might have a copy of Hunger Games. I want to be able to show it on both bookshelves. The only way my idea would work is if we had no duplicate books.
My next idea was to use a different table for each user and have a field that contains the book id for each book the user owns. I think this would work on a small scale but it does not seem like an efficient design. I am planning on making the database public for everyone in my town to use (thousands of people) once I get a stable website going so I want to start off with the right kind of design.
How should this be designed?
BOOK
--------
book_id
title
other_book_related_info
PERSON
-------
person_id
name
other_person_info
BOOK_PERSON
-------------
book_id
person_id
possibly-dates-when-this-person-owned-this-book
Here is one simple solution i can think of:
Book Table : List of all unique books
User Books : contains the user id and the book id. multiple users can own the same title.
Users : List of users;
This is pretty basic. Owner, book and author should be self explanatory. Add any additional fields to those tables you want. The bookshelf and book_authors are both cross reference tables so each book can have multiple owners and each book can have multiple authors.
**owner:**
owner_id
owner_name
...
**book:**
book_id
book_name
...
**author:**
author_id
author_name
...
**bookshelf:**
owner_id
book_id
**book_authors:**
book_id
author_id
You might like to differentiate between ownership of the book and current possession, since people will doubtless be borrowing. So the tables of BOOK (best call it ITEM if you're going to expand to DVD's etc) and PERSON, and the ownership table BOOK/MEDIA_OWNER, might be usefully accompanied by an ITEM_LOAN table.
You might like to also allow grouping of sets of items so that multiple volumes of a book, or discs of a show season, can be identified individually. Books (and films etc) also come in series, so think about how to represent that as well.
By the way, it's a generally accepted rule that if an edition of a work changes by more than 20% between print runs then it is a new impression, but it is not always granted a new ISBN. Depends on the publisher. Also, the hierarchy for books is based on Work -< Edition -< Impression, and these folks would be a good source of information of data structures relating to books.
Here's another solution:
**** BOOK ***
book_id
book_title
book_desc
book_bought
*** USERS ***
user_id,
name,
dateOfBirth
** Copies **
copy_id (PK)
user_id (FK)
book_id (FK)
NoOfCopies

How can I merge two redundant records in a MySQL table, maintaining all PK/FK relationships?

Say I have a table customers with the following fields and records:
id first_name last_name email phone
------------------------------------------------------------------------
1 Michael Turley mturley#whatever.com 555-123-4567
2 John Dohe jdoe#whatever.com
3 Jack Smith jsmith#whatever.com 555-555-5555
4 Johnathan Doe 123-456-7890
There are several other tables, such as orders, rewards, receipts which have foreign keys customer_id relating to this table's customers.id.
As you can see, in their infinite wisdom, my users have created duplicate records for John Doe, complete with inconsistent spelling and missing data. An administrator notices this, selects customers 2 and 4, and clicks "Merge". They are then prompted to select which value is correct for each field, etc etc and my PHP determines that the merged record should look like this:
id first_name last_name email phone
------------------------------------------------------------------------
? John Doe jdoe#whatever.com 123-456-7890
Let's assume Mr. Doe has placed several orders, earned rewards, generated receipts.. but some of these have been associated with id 2, and some have been associated with id 4. The merged row needs to match all of the foreign keys in other tables that matched the original rows.
Here's where I'm not sure what to do. My instinct is to do this:
DELETE FROM customers WHERE id = 4;
UPDATE customers
SET first_name = 'John',
last_name = 'Doe',
email = 'jdoe#whatever.com',
phone = '123-456-7890'
WHERE id = 2;
UPDATE orders, rewards, receipts
SET customer_id = 2
WHERE customer_id = 4;
I think that would work, but if later on I add another table that has a customer_id foreign key, I have to remember to go back and add that table to the second UPDATE query in my merge function, or risk loss of integrity.
There has to be a better way to do this.
I got here form google this is my 2 cents:
SELECT `TABLE_NAME`
FROM `information_schema`.`KEY_COLUMN_USAGE`
WHERE REFERENCED_TABLE_SCHEMA='DATABASE'
AND REFERENCED_TABLE_NAME='customers'
AND REFERENCED_COLUMN_NAME='customer_id'
add the db for insurance (you'll never know when somebody copies the db).
Instead of looking for a column name, here we look at the foreign keys themselves
If you change the on delete restrictions to restrict nothing can be deleted before the children are deleted/migrated
The short answer is, no there isn't a better way (that I can think of).
It's a trade off. If you find there are a lot of these instances, it might be worthwhile to invest some time writing a more robust algorithm for checking existing customers prior to adding a new one (i.e. checking variations on first / last names, presenting them to whoever is adding the customer, asking them 2 or 3 times if they are REALLY sure they want to add this new customer, etc.). If there are not a lot of these instances, it might not be worth investing that time.
Short of that, your approach is the only way I can think of. I would actually delete both records, and create a new one with the merged data, resulting in a new customer id rather than re-using an old one, but that's just personal preference - functionally it's the same as your approach. You still have to remember to go back and modify your merge function to reflect new relationships on the customer.id field.
At a minimum, to prevent any triggers on deletions causing some cascading effect, I would FIRST do
update SomeTable set CustomerID = CorrectValue where CustomerID = WrongValue
(do that across all tables)...
THEN
Delete from Customers where CustomerID = WrongValue
As for duplicate data... Try to figure out which "Will Smith, Bill Smith, William Smith" if you are lacking certain information... Some could be completely legitimate different people.
As an update to my comment:
use information_schema;
select table_name from columns where column_name = 'customer_id';
Then loop through the resulting tables and update accordingly.
Personally, I would use your instinctive solution, as this one may be dangerous if there are tables containing customer_id columns that need to be exempt.

Insert Registration Data in MySQL using PHP

I may not be asking this in the best way possible but i will try my hardest. Thank you ahead of time for your help:
I am creating an enrollment website which allows an individual OR manager to enroll for medical testing services for professional athletes. I will NOT be using the site as a query DB which anybody can view information stored within the database. The information is instead simply stored, and passed along in a CSV format to our network provider so they can use as needed after the fact. There are two possible scenarios:
Scenario 1 - Individual Enrollment
If an individual athlete chooses to enroll him/herself, they enter their personal information, submit their payment information (credit/bank account) for processing, and their information is stored in an online database as Athlete1.
Scenario 2 - Manager Enrollment
If a manager chooses to enroll several athletes he manages/ promotes for, he enters his personal information, then enters the personal information for each athlete he wishes to pay for (name, address, ssn, dob, etc), then submits payment information for ALL athletes he is enrolling. This number can range from 1 single athlete, up to 20 athletes per single enrollment (he can return and complete a follow up enrollment for additional athletes).
Initially, I was building the database to house ALL information regardless of enrollment type in a single table which housed over 400 columns (think 20 athletes with over 10 fields per athlete such as name, dob, ssn, etc).
Now that I think about it more, I believe create multiple tables (manager(s), athlete(s)) may be a better idea here but still not quite sure how to go about it for the following very important reasons:
Issue 1
If I list the manager as the parent table, I am afraid the individual enrolling athlete will not show up in the primary table and will not be included in the overall registration file which needs to be sent on to the network providers.
Issue 2
All athletes being enrolled by a manager are being stored in SESSION as F1FirstName, F2FirstName where F1 and F2 relate to the id of the fighter. I am not sure technically speaking how to store multiple pieces of information within the same table under separate rows using PHP. For example, all athleteswill have a first name. The very basic theory of what i am trying to do is:
If number_of_athletes >1,
store F1FirstName in row 1, column 1 of Table "Athletes";
store F1LastName in row 1, column 2 of Table "Athletes";
store F2FirstName in row 2, column 1 of Table "Athletes";
store F2LastName in row 2, column 2 of table "Athletes";
Does this make sense? I know this question is very long and probably difficult so i appreciate the guidance.
You should create two tables: managers and athletes
The athletes table would contain a column named manager_id which would contain the id of the manager who signed the athlete up or NULL if the athlete signed himself up.
During output, create two CSV files (one for each table).
Further reading:
Defining Relationships
If you will retain the names for a future submission, then you should use a different design. You should also consider if a manager can also be an athlete. With those points in mind, consider having three tables: PEOPLE, REGISTRATION and REGISTRATION_ATHLETE. PEOPLE contains all athletes and manager. REGISTRATION is the Master table that has all the information for a submission of one or more individuals for testing. REGISTRATION_ATHLETE has one row for every Athlete to be tested.
People table:
---------------
People_ID
Type (A for Athlete, M for Manager B for Both)
First Name
Last Name
Birthdate
other columns of value
Registration table:
-------------------
Registration_ID
Registration_Date
People_ID (person requesting registration - Foreign Key to PEOPLE)
Payment columns....
Registration_Athlete table:
---------------------------
Registration_ID (Foreign Key to REGISTRATION)
People_ID (Foreign Key to PEOPLE)
I am not a mysql person, but I would think this simple type of structure would work.
Finally, storing credit card information is problematic as it runs into PCI (Payment Card Institute) rules, which you will want to avoid (think complicated and expensive). Consider processing payments through a third party, such as Google Checkout, etc. and not capturing the credit card.
Well based on your comment reply and what you are looking for. You could do this.
Create one database for Registration.
Create the columns ID, name, regDate, isManager, ManagerID (Whatever Else you need).
When a Manager enrolls set isManager to 1 and form a hash based on name and regdate, that would be the Managers Unique ID that would be added to all of the Athletes entries that the manager registers.
When a lone athlete registers don't worry about the ID and just set isManager to 0.
I think I may be oversimplifying it though. Wouldn't be the greatest for forming different types of queries but it should be alright if you are trying to minimize your db footprint

Categories