mysql db structure and relationship - php

I need help in how to setup my tables in my mysql database.
I have an user. An user gets 10 tokens to use as they wish. A token can be used only for one thing only. They can use it to create a cartoon page, game page, bio page, question page, and etc. The token can be reassigned to another page also.
I want to see what the best way to structure my database would be and the relationships.
I am thinking of having a user table, token table, cartoon table, game table, bio table, and question table. But how do I relate to all of them.

Relational database table design is not a hard science. It's a highly flexible paradigm that can and will change depending on the nature of your application. That being said, there are certain design principles which you should typically adhere to. See e.g. http://en.wikipedia.org/wiki/Database_design.
That being said, I'll take a shot at this from an approach that seems highly dynamic, since I'm not sure about the application specifics. Firstly, you will most definitely need a users table that might look like:
users:
first_name
last_name
user_id
n_tokens
I put this here in case a user's number of tokens is dynamic
Now that you have a way of specifying a user, you'll want to see how that user has used his/her tokens:
tokens:
token_id
This is used to specify what this (or these) token(s) are used for.
user_id
This should have a duplicate foreign key constraint on users.user_id.
n_tokens
This is different from users.n_tokens. It is not clear from your problem
whether or not you'll always have 1 token per feature. This value is a
forward-looking approach at possible future enhancements.
pagetype_id
This is to specify what type of page type the token is used for. It'll have
a foreign key constraint on pagetypes.pagetype_id (see below).
As noted above, you want people to use tokens on specific page types, like cartoon pages, bio pages, etc. which this table defines:
pagetypes:
pagetype_id
Used to define a unique identifier to this type of page
pagetype_name
String field to label the page types, e.g. "cartoon," "bio," etc.
Now, you may have several tables defining the types of pages, so I'll specify the layout for just one:
bio_pages:
pagetype_id
This id has a duplicate foreign key constraint on pagetypes.pagetype_id.
The value will ALWAYS be constant for this table. This is not the most
normalized design, as you MAY want to have a more generic 'pages' table,
but several complex joins can be confusing to some developers and even
worse, slow for queries.
token_id
Foreign key constraint on tokens.token_id.
OTHER
The rest of the fields are user-defined, as you wish to specify what
belongs on a bio page.
SUMMARY
To summarize the above table layouts, you'll want to design the database so that self-contained entities do not span multiple tables, and multiple entities don't combine into one table. With that said, I separated out the users table from the tokens table from the different <pagetype>_pages tables. To make the design more intuitive I'll make some sample queries that might help with your understanding of the layout.
To get all the bio pages that a user has created:
SELECT bio_pages.*
FROM bio_pages
INNER
JOIN tokens
ON bio_pages.token_id=tokens.token_id
INNER
JOIN users
ON tokens.user_id=users.user_id
WHERE users.first_name='john'
AND users.last_name='doe'
To get the total number of coins that a user has used, and also the maximum number of coins they can use:
SELECT SUM(tokens.n_tokens) AS used_tokens,
users.n_tokens AS max_tokens
FROM tokens
INNER
JOIN users
ON tokens.user_id=users.user_id
WHERE users.first_name='john'
AND users.last_name='doe'
GROUP BY users.user_id
Hopefully this all makes sense and is intuitive. Please let me know if anything is unclear.

Related

MySQL efficient: multiple tables or columns with nulls

I am developing a MySQL db for a user list, and I am trying to determine the most efficient way to design it.
My issue comes in that there are 3 types of users: "general", "normal", and "super". General and normal users differ only in the values of certain columns, so the schema to store them is identical. However, super users have at least 4 extra columns of info that needs to be stored.
In addition, each user needs a unique user_id for reference from other parts of the site.
So, I can keep all 3 users in the same table, but then I would have a lot of NULL values stored for the general and normal user rows.
Or, I can split the users into 2 tables: general/normal and super. This would get rid of the abundance of NULLs, but would require a lot more work to keep track of the user_ids and ensure they are unique, as I would have to handle that in my PHP instead of just doing a SERIAL column in the single table solution above.
Which solution is more efficient in terms of memory usage and performance?
Or is there another, better solution I am not seeing?
Thanks!
If each user needs a unique id, then you have the answer to your question: You want one users table with a UserId column. Often, that column would be an auto-incremented integer primary key column -- a good approach to the implementation.
What to do about the other columns? This depends on a number different factors, which are not well explained in your question.
You can store all the columns in the same table. In fact, you could then implement views so you can see users of only one type. However, if a lot of the extra columns are fixed-width (such as numbers) then space is still allocated. Whether or not this is an issue is simply a question of the nature of the columns and the relative numbers of different users.
You can also store the extra columns for each type in its own table. This would have a foreign key relationship to the original table, using the UserId. If both these keys are primary keys, then the joins should be very fast.
There are more exotic possibilities as well. If the columns do not need to be indexed, then MySQL 5.7 has support for JSON, so they could all go into one column. Some databases (particularly columnar-oriented ones) allows "vertical partitioning" where different columns in a single table are stored in separate allocation units. MySQL does not (yet) support vertical partitioning.
why not build an extra table; but only for the extra coloumns you need for super users? so 2 tables one with all the users and one with super users's extra info
If you want to have this type of schema. try to create a relation
like:
tb_user > user_id , user_type_id(int)
tb_user_type > user_type_id(int) , type_name
this way you will have just 2 tables and if the type is not set you can set a default value to a user.

What is the proper way to store user preferences in a database?

I have a MySQL database that stores user emails and news articles that my service provides. I want users to be able to save/bookmark articles they would like to read later.
My plan for accomplishing this was to have a column, in the table where I store the users' emails, that holds comma-delineated strings of unique IDs, where the unique IDs are values assigned to each article as they are added into the database. These articles are stored in a separate table and I use UUID_SHORT() to generate the unique IDs of type BIGINT.
For example, let's say in the table where I store my articles, I have
ArticleID OtherColumn
4419350002044764160 other stuff
4419351050184556544 other stuff
In the table where I store user data, I would have
UserEmail ArticlesSaved OtherColumn
examlple1#email.com 4419350002044764160,4419351050184556544,... other stuff
examlple2#email.com 4419350002044764160,4419351050184556544,... other stuff
to indicate the first two users have saved the articles with IDs 4419350002044764160 and 4419351050184556544.
Is this a proper way to store something like this on a database? If there is a better method, could someone explain it please?
One other option I was thinking of was having a separate table for each user where I can store the IDs of the articles they saved into a column, though the answer for this post that this is not very efficient: Database efficiency - table per user vs. table of users
I would suggest one table for the user and one table his/her bookmarked articles.
USERs
id - int autoincrement
user_email - varchar50
PREFERENCES
id int autoincrement
article_index (datatype that you find accurate according to your structure)
id_user (integer)
This way it will be easy for a user to bookmark and unbookmark an article. Connecting the two tables are done with id in users and id_user in preferences. Make sure that each row in the preferences/bookmarks is one article (don't do anything comma seperated). Doing it this way will save you much time/complications - I promise!
A typical query to fetch a user's bookmarked pages would look something like this.
SELECT u.id,p.article_index,p.id_user FROM users u
LEFT JOIN preferences ON u.id=p.id_user
WHERE u.id='1' //user id goes here, make sure it's an int.. apply appropriate security to your queries.
"Proper" is a squirrely word, but the approach you suggest is pretty flawed. The resulting database no longer satisfies even first normal form, and that predicts practical problems even if you don't immediately see them. Some of the problems you would be likely to encounter are
the number of articles each user can "save" will be limited by the data type of the ArticlesSaved column;
you will have issues around duplicate "saved" article IDs; and
queries about which articles are saved will be more difficult to formulate and will probably run slower; in part because
you cannot meaningfully index the the ArticlesSaved column.
The usual way to model a many-to-many relationship (such as between users and articles) is via a separate table. In this case, such a table would have one row for each (user, saved article) pair.
Saving data in CSV format in a database field is (almost) never a good idea. You should have 3 tables :
1 table describing users with everything concerning directly the user
1 table describing articles with data about it
1 table with 2 columns "userid" and "articleid" linking both. If a user bookmarks 10 articles, this table will have 10 records with a different aticleid each time.

How to organize and manage 'nested' tables within a database?

I've just started exploring SQL databases, but I've run into an issue with how I store 'compound' structures in an existing table (if that's even the right way to go about it). For example, let's say that I have a database table with rows of users, where each user has a Unique ID, a hashed password, an email address, a phone number, etc.
Simple enough. But, then I want to allow each user to create and store an array of posts. Each post would have a post id, content, date, and various other metadata. If this was C++, I would probably have an array/vector of Posts as a member of the User class, and than I'd store an array/vector of User objects somewhere. Is it possible to store a table within a table in SQL, so that each user has access to their own individual table of posts?
Or, would it be better to create two separate tables (a users table, and a posts table), using some common element (like user ID or user name) to retrieve user-specific data from the posts table, and vice-versa?
I'm trying to understand how to implement a complex database that might be able to manage a large number of users, with user-specific sets of data like posts, messages, etc. So what might be a good approach to take going forward?
As you already mentioned, in relational data model, you can define two tables like below:
table 1 : Users
user_id user_name
----------- ------------------
1 'Tom'
2 'John'
table 2 : Posts
post_id user_id content post_date
-------- ---------- ------------------- ---------------------
1 1 'Hello, I am Tom.' 2014-04-02 14:14
2 1 'good bye' 2014-04-02 20:10
3 2 'I am John' 2014-04-02 22:22
You can read an introductory article here:
Relational_model:
http://en.wikipedia.org/wiki/Relational_model
Hope this helps.
You don't store table within table. You can store data in multiple tables and assign primary key for one table and foreign key for another table.
Read about Primary key, Foreign key and Relational Model.
Once your these concepts are cleared read about Database Normalization
You don't store tables within tables. As your third paragraph suggests, the strategy is to use some common key to "relate" table rows to each other.
The "unique ID" you describe is usually called a "primary key". You might have a table of users with a primary key that auto-increments each time you add a record. A function would be available to you so that after inserting, you could determine what the primary key is of the record you just added, so that you can add records to other tables that refer to the primary key of the users table.
You should probably read about Database normalization ant the relational model, specifically about the differences between Normal Forms.
With regard to selection of a field to relate posts to users, I suggest you don't use the username, and instead use some internal reference that isn't visible to the users. While your application might not allow it now, if you wanted to offer users the opportunity to change their username, tying internal database structure to something based on user input would only cause problems in the future.

Besy way to store data about data that is already stored in a database?

I am working on creating a favorites section on my website where users can simply store certain items in their favorites section for easy access. Each of the items are already well-defined and have multiple attributes. So my question is lets say I had 10,000 users and I would like to implement a 'favorites' system, what would be the best way to keep track of what favorite items have been added by each user?
I was thinking implementing this the following way: link each favorited item id to a username and then run a query for if the user with a particular username is logged in than retrieve all the favorited items by that username.
I appreciate any help with figuring out of a good way to do this. My goal is to store in a way that is later easy to retrieve and use the data and minimize redundant information.
It's pretty easy, you need to create a new table with 3 fields:
id
favoriteID
userID
Every time a user adds a new favourite, it adds a new record to this table, storing both the ID of the favorite, and the ID of the user. There is no redundant information and it's easy to retrieve the details of either the favorite or the user by implementing a join query. This is what relational databases are for.
Within an RDBMS you would probably have a many to many table with the user id and article id. You do not need an independent id column:
create table favourites (user_id int, article_id int);
These of course reference your user table and articles table. (Or whatever you have in place of articles.)
You would then need to retrieve all rows for a single user when wanting to show that user's favourites. You might also want to make a combined UNIQUE index on the columns to prevent duplicates.
You may have faster response with something like cassandra where you can simply retrieve based on the key of the user_id and get all their favourites in one easy spot. But then you're dealing with mutilple systems.
I've heard, but haven't had a chance to look into, that MySQL can now support a Key-Value system similar to Cassandra and that may be your best bet.

Are identical primary keys bad practice?

I am trying to create a site where users can register and create a profile, therefore I am using two MySQL tables within a database e.g. users and user_profile.
The users table has an auto increment primary key called user_id.
The user_profile table has the same primary key called user_id however it is not auto increment.
*see note for why I have multiple tables.
When a user signs up, data from the registration form is inserted into users, then the last_insert_id() is input into the user_id field of the user_profile table. I use transactions to ensure this always happens.
My question is, is this bad practice?
Should I have a unique auto increment primary key for the user_profile table, even though one user can only ever have one profile?
Maybe there are other downsides to creating a database like this?
I'd appreciate if anyone can explain why this is a problem or if it's fine, I'd like to make sure my database is as efficient as possible.
Note: I am using seperate tables for user and user_profile because user_profile contains fields that are potentially null and also will be requested much more than the user table, due to the data being displayed on a public profile.
Maybe this is also bad practice and they should be lumped in one table?
I find this a good approach, I'd give bonus point if you use a foreign key relation and preferably cascade when deleting the user from the user table.
As too separated the core user data in one table, and the option profile data in another - good job. Nothing more annoying then a 50 field dragonish entry with 90% empty values.
It is generally frowned upon, but as long as you can provide the reasoning for the 1 to 1 relationship I'm sure it is fine.
I have used them when I have hundreds of columns (and it would be more logical to split them out into separate tables)
or I need a thinner table to speed up fullscans
In your case I would use a single table and create a couple of views.
see: http://dev.mysql.com/doc/refman/5.0/en/create-view.html
In general a single table approach is more logical, quicker, simpiler, and uses less space.
I don't think it's a bad practice. Sometimes it's quite useful, especially if you want one class to deal with authentication, and not load all profile data. You can then modify how your authentication works, build web services and so on, with little care about maintaining data structures about profiles information which is likely to change as your project evolves.
This is very good practice.
It's right at the core of writing good, modular, normalised relational database structures.

Categories