Creating tables on registration in php - php

The question is not new in any way but it has a small twist to it.
My webpage is a membership page where users places bets. My idea is to create a new table for the users(with a naming convention like TABLE userBet+$userid) bets. User login information is already handled, my goal is now to save the bets of the user to a new table. A table which is created when users register. This will hopefully make score counting easier. Am I right or wrong? Could this be done in a better way? (Everything is done in PHP MySQL)
User registers -> Table for bets get created
"CREATE Table $userID ,id_bet, games, result, points"
And then matching this table against the correct result?
So again my questions: Is this a good way to do it? Is creating a table with the userID a smart thing to do?
EDIT
The bets is always 40 matches, which makes the tables Huge with columns and rows.
Should I make 40 Tables, one for each games instead? and put all users in there?

Am I right or wrong?
You are wrong. Dynamically altering your database schema will only make it harder to work with. There's no advantage you gain from doing so. You can do the same things by storing all bets within the same table, adding a column userid.

Posting as an answer due to author's request : )
Suggested database schema:
table matches:
id | name |
---------------
1 | A vs B |
table user_bets
id | user_id | match_id | points | result |
-------------------------------------------
1 | X | 1 | Y | Z |
Where match_id is related on matches.id
user_id = user.id
user_bets is only one table, containing all the info. No need of separate tables, as it was clear from the comments it's considered bad practice to alter the db schema via user input.

Related

MySQL primary keys with two ID fields

I have a MySQL table, people, that looks like this:
id | object_id | name | sex | published
----------------------------------------------
1 | 1 | fred | male | [timestamp]
2 | 2 | john | male | [timestamp]
The reason I have two ids is that in my CRUD app the user might edit an existing object, in which case it becomes a draft, so that I have two rows (the draft record and the already-existing record) with the same object_id, something like this:
id | object_id | name | sex | published
----------------------------------------------
2 | 2 | john | male | [timestamp]
3 | 2 | john | female | NULL
This allows me to keep track of records' drafts and publication status. When the row with id of 3 is published, its published field will be stamped and the already published row deleted.
Each person also has a job history, so I have a table history:
id | person_object_id | job
----------------------------------
1 | 2 | dev
2 | 2 | accountant
This is John's job history. I refer to John's object_id in the person_object_id field, because if I refered to his id I'd risk delinking the two tables if I deleted one of the John rows as in my example above.
So my question is: is it not inefficient to refer to a table, as I do above, using a non-primary key (object_id instead of id)? How can I refer to a primary key when I require a non-unique id to keep track of drafts/published rows?
It looks like you want to keep versions of your data and you've come across the age-old problem of how to maintain foreign key pointers to versioned data. The solution is actually easy and it turns out that it is a special case of second normal form.
Take the following employee data:
EmpNo FirstName LastName Birthdate HireDate Payrate DeptNo
Now you are tasked with maintaining versions of the data as it changes. You could then add a date field which shows when the data changed:
EmpNo EffDate FirstName LastName Birthdate HireDate Payrate DeptNo
The Effective Date field shows the date each particular row took effect.
But the problem is that EmpNo, which was a perfect primary key for the table, can no longer serve that purpose. Now there can be many entries for each employee and, unless we want to assign a new employee number every time an employee's data is updated, we have to find another key field or fields.
One obvious solution is to make the combination of EmpNo and the new EffDate field be the primary key.
Ok, that solves the PK problem, but now what about any foreign keys in other tables that refer to specific employees? Can we add the EffDate field to those tables, also?
Well, sure, we can. But that means that the foreign keys, instead of referring to one specific employee, are now referring to one specific version of one specific employee. Not, as they say, nominal.
Many schemes have been implemented to solve this problem (see the Wikipedia entry for "Slowly Changing Dimension" for a list of a few of the more popular).
Here's a simple solution that allows you to version your data and leave foreign key references alone.
First, we realize that not all data is ever going to change and so will never be updated. In our example tuple, this static data is EmpNo, FirstName, Birthdate, HireDate. The data that is liable to change then, is LastName, Payrate, DeptNo.
But this means that the static data, like FirstName is dependent on EmpNo -- the original PK. Changeable or dynamic data, like LastName (which can change due to marriage or adoption) is dependent on EmpNo and EffDate. Our tuple is no longer in second normal form!
So we normalize. We know how to do this, right? With our eyes closed. The point is, when we are finished, we have a main entity table with one and only one row for each entity definition. All the foreign keys can refer to this table to the one specific employee -- the same as when we've normalized for any other reason. But now we also have a version table with all the data that is liable to change from time to time.
Now we have two tuples (at least two -- there could have been other normalization processes performed) to represent our employee entity.
EmpNo(PK) FirstName Birthdate HireDate
===== ========= ========== ==========
1001 Fred 1990-01-01 2010-01-01
EmpNo(PK) EffDate(PK) LastName Payrate DeptNo
===== ======== ======== ======= ======
1001 2010-01-01 Smith 15.00 Shipping
1001 2010-07-01 Smith 16.00 IT
The query to reconstruct the original tuple with all the versioned data is simple:
select e.EmpNo, e.FirstName, v.LastName, e.Birthdate, e.Hiredate, v.Payrate, v.DeptNo
from Employees e
join Emp_Versions v
on v.EmpNo = e.EmpNo;
The query to reconstruct the original tuple with only the most current data is not terribly complicated:
select e.EmpNo, e.FirstName, v.LastName, e.Birthdate, e.Hiredate, v.Payrate, v.DeptNo
from Employees e
join Emp_Versions v
on v.EmpNo = e.EmpNo
and v.EffDate =(
select Max( EffDate )
from Emp_Versions
where EmpNo = v.EmpNo );
Don't let the subquery scare you. A careful examination shows that it locates the desired version row with an index seek instead of the scan that most other methods will generate. Try it -- it's fast (though, of course, mileage may vary across different DBMSs).
But here's where it gets really good. Suppose you wanted to see what the data looked like on a particular date. What would that query look like? Just take the query above and make a small addition:
select e.EmpNo, e.FirstName, v.LastName, e.Birthdate, e.Hiredate, v.Payrate, v.DeptNo
from Employees e
join Emp_Versions v
on v.EmpNo = e.EmpNo
and v.EffDate =(
select Max( EffDate )
from Emp_Versions
where EmpNo = v.EmpNo
and EffDate <= :DateOfInterest ); --> Just this difference
That last line makes it possible to "go back in time" to see what the data looked like at any specific time in the past. And, if DateOfInterest is the current system time, it returns the current data. This means that the query to see current data and the query to see past data are, in fact, the same query.
It doesn't really matter as long as you have an index on that column (not-unique index). Than it would be almost as fast

Trouble filtering information with relational databases in MySQL/PHP

I'm working on my first project (a project management system) to understand PHP and MySQL better. I currently have 3 tables in my database, one that lists all the projects ('projects' table), one that stores the users username and password ('users' table) and then a third, small 'permissions' table that is meant to filter out what projects a user can see from the projects table.
The third 'permissions' table consists of an unique id, and then a "user_id" and a "project_id" in the other two columns. The "user_id" references the id of the user in the "users" table, and the "project_id" references the id of a project in the projects table.
Note that more than one user can have access to a single project, that's why there isn't just a single column for this in the projects table, and I read that using comma separated lists for the multiple usernames is a bad way to go about it. As such I have set up foreign keys on "user_id" and "project_id" that reference the id of each accordingly.
Now I'm not sure if this is a good way to set things up but it seems okay in my head.
Really what I want to do is retrieve all the projects a certain user has access to. So something kind of like (but obviously works):
SELECT * FROM projects WHERE user_id = 3;
Is there a simpler way to do this? Something to do with the join command but I could never get it right.
Thanks in advance!
EDIT:
Apologies for the ambiguity, gets a bit tricky to explain.
Essentially I just want a way to filter what rows are displayed from the projects table by the user_id in the users table (note again more than one user can access a project so I can just put a "user_id" column in the projects table and leave out the third table altogether).
My tables are pretty much like so:
projects:
|id|project_title|project_notes|project_status|
|1 |A Project |Some Notes |Finished |
|2 |A 2nd Project|Some more... |In Progress |
users:
|id|username|password|
|1 |johndoe |*********|
|2 |benhill |*********|
permissions:
|id|user_id|project_id|
|1 |1 |2 |
|2 |2 |2 |
user_id = id from users table.
project_id = id from projects table.
Then in HTML/PHP I only want to retrieve the projects that a user has access too.
Unfortunately your question isn't very clear but I assume you want to have a single query to find all project that a particular user has access to, you can simply join up the tables with the id as such:
SELECT * from projects INNER JOIN permissions ON
projects.id = permissions.project_id WHERE
permissions.user_id = 3
Assume the user you are looking for has id of 3
Assuming you have
Users (Id, Name)
Projects (Id, Name)
Permissions (UserId, ProjectId)
and you want to "retrieve all the projects a certain user has access to", and you have the user id stored in a variable $userId, you could use a simple query like this:
select * from Projects pr
join Permissions pe on pr.Id = pe.ProjectId
and pe.UserId = $userId
Google around for more info on SQL syntax and joins. Here's a link I just found that looks like a good place to start: http://www.sitepoint.com/understanding-sql-joins-mysql-database/

Trying to find how to link three tables together

At the moment I have three tables that I am trying to connect and figure out what queries will get the results I need and also follow best practices. MySQL is still pretty new to me, and this is my first stumbling block that I can't figure out.
I am trying to build a simple URL shortener that can "link" multiple long URLs to one short URL. I basically want to have a link www.example.com/google then have google.com, google.co.uk, google.it, etc... and GEO target when the user accesses the link.
My three tables are set up as:
short_id | user_id | short_url //Short URL Table
long_id | user_id | long_url | country_code //Long URL table
user_id | name | password | email | created //User table
I am not sure if foreign keys are the best route. Also, I understand how to add a user, but what queries would I have to run to have a user add a short/long url and have the user_id field in "user" table match the user_id fields in the other tables.
Thanks for the help.
select * from short_url_table
left join long_url_table
using (user_id)
left join user_table
using (user_id) ;

Rating System in PHP and MySQL

If we look at the stackoverflow website we have votes. But the question is what is the bestway to store who has voted and who has not. Lets also simplify this even more and say that we can only vote Up, and we can only Remove the Up vote.
I was thinking having the table to be in such form
question - Id(INT) | userId(INT) | title(TEXT) | vote(INT) | ratedBy(TEXT)
Thre rest is self explanitory but ratedBy is a Comma Seperated Id values of the Users.
I was thinking to read the ratedBy and compare it with the userId of the current logged in User. If he dosent exist in the ratedBy he can vote Up, otherwise he can remove his vote. Which in turn will remove the value from ratedBy
I think to make another table "vote" is better. The relationship between users and votes is n to n, therefore a new table should be created. It should be something like this:
question id (int) | user id (int) | permanent (bool) | timestamp (datetime)
Permanent field can be used to make votes stay after a given time, as SO does.
Other fields may be added according to desired features.
As each row will take at least 16B, you can have up to 250M rows in the table before the table uses 4GB (fat32 limit if there is one archive per table, which is the case for MyISAM and InnoDB).
Also, as Matthew Scharley points out in a comment, don't load all votes at once into memory (as fetching all the table in a resultset). You can always use LIMIT clause to narrow your query results.
A new table:
Article ID | User ID | Rating
Where Article ID and User ID make up the composite key, and rating would be 1, indicating upvote, -1 for a downvote and 0 for a removed vote (or just remove the row).
I believe your design won't be able to scale for large numbers of voters.
The typical thing to do is to create to tables
Table 1: question - Id(INT) | userId(INT) | title(TEXT)
Table 2: question - ID(INT) | vote(INT) | ratedBy(TEXT)
Then you can count the votes with a query like this:
SELECT t1.question_Id, t1.userId, t1.title, t2.sum(vote)
FROM table1 t1
LEFT JOIN table2 t2 ON t1.question_id = t2.question_id

Multiple users table VS 1 users table?

I am in dilemma situation. I am not sure if its a good idea to separate the users table. I notice my game highscores table performances, as the numbers growing, the loading is getting slower and slower.
My current users table store all users, which currently about 10k users. I am thinking of splitting the users table (for future) into like this:
Login Table => store user login details
==========================================
= id | username | password | tableid =
==========================================
= 1 | user1 | user1xx | 1 =
= 2 | user2 | user2xx | 1 =
...
= 20k1 | user20k1 | user20k1 | 2 =
etc
Users Data
==========================================
= id | money | items | preferences =
==========================================
= 1 | xx | xx | xx =
= 2 | xx | xx | xx =
...
= 20k1 | xx | xx | xx =
etc
So, when I try to get users data I just LEFT JOIN query to get the data.
My question is, are there any differences (speed, performances etc) between storing users data in multiple tables and storing users data in single table? (assume indexes and primary key are the same)
My current tables indexes:
Games highscores table => columns: id, gameid, name, score, date
Primary key : id
Indexes: gameid
Login Table => Columns: id, username, password
Primary key: id (userid)
Indexes: username
Users data => Columns: alots
Indexes: id
It sounds that the real question you have here is this: why ma app is slow. First of all splitting data between several tables is not going to help performance. If done right (for reasons other than performance) it will not hurt performance but I doubt it will help.
What's more, in my experience it is a bad idea to optimize based on gut feel. Somehow guesses about what holds your program back are usually wrong. You end up doing a lot of rewriting without any gain in speed.
The first step to speed it up is to find the real bottleneck. You need to add instrumentation and collect some stats to figure out - is it database or app server. Is it a particular sproc or might be the bandwidth of your network. Or may be it is some javascript on your pages.
Only after you know what to fix you can try to fix it.
Sounds like splitting the table won't do you any good. It seems like a 1:1 correlation would occur between the tables, and that would simply add a second query whenever you wanted something from that table.
Try using Partitioning on the table to help with performance in that aspect.
Normalizing is only useful if you have redundant data (so, you have the same user in your user table 5 times). Helpful if you want to lower data usage with particular users' high scores for multiple games, but ultimately it probably won't give you a performance increase on the table.
If you're querying for bits of information and you have lots of (edit:)columns, it's actually a really good idea to have them separated and you don't need the tableid field in the users table, all you need is a foreign key in the information table that points to the associated user in the users table.
You can have multiple tables like that and join them as you like, performance will most likely increase.

Categories