How to design this simple database? - mysql

I have 2 tables - one storing user information (id, username, password) and the second one storing information about events (id, name, description, date, username(represents the user who created the event)). I would like to implement 'favourite events' functionality. This would allow the user to store his favourite events and later display them in a list. I am not sure how to implement this in terms of design. I need a simple solution. Something like storing the IDs of favourite events in a field in the user table. I am using mysql and PHP. Can anyone point me to the right direction?

You want to have a table linking the foreign keys from the user and event tables.
Users Table:
id, username, password
Events Table:
id, name, description, date, username
Favorites Table:
id, user_id, event_id
This way you can easily access the list of favorite events.
SELECT events.name, events.description, events.date
FROM events, users, favorites
WHERE favorites.user_id = users.id
AND favorites.event_id = events.id

What you need is the most classic and basic many-to-many relationship.
You'll need extra table (let's say: user_event_ref) that will store user and event ids.
User:
id
name
Event:
id
name
UserEventRef:
user_id
event_id
In usereventref each column is a Foreign Key, and both columns are parts of Primary Key.

There's always the option to add a tiny-int field to the Events table flagging an event as a favorite. This doesn't violate normalization in that whether or not an even is a favorite has no effect on the other events. It has the added benefit of automatically deleting the event from favorites if the event is deleted.
If a sorting scheme is needed for the favorites you can still modify the events table in the same manner. If details about the "favorite" such as when it was added to the list etc is needed then you should use an additional table as suggested.

Related

Own table in database or leaving a field empty?

In my project I have got the following tables:
Event (id, title, date, user_id)
Group (id, name, creator_id)
User (id, name, email,...)
group_user (group_id, user_id)
In the application a user can have a personal event or a group can have a event that will be shared will all users in the group.
A user is able to create an event , then the events user_id is this users ID.
Now i would like to create an event within a group - so I need a relationship between the event and the group.
Should I create the attribute group_id in the event table and leave it empty if the event just belongs to a user and not to a group?
Or should I consider creating a new table like groupEvent which has got the attribute group_id.
Or should I create a pivot table group_event that contains the groupID and the eventID as attributes.
Thanks for your help!!
One way I could think of is for you to get rid of the user_id foreign key in the Event table and instead have a User_Event table that maps users and events and a Group_Event table that maps groups and events. Not sure if this is the best design for your use case but this will avoid the need for two foreign keys in the Event table (of which one of them is NULL for every row).
Create 2 separate table Group_Event(id,group-id,event-id) and User_Event(id,user-id,event-id).
Advantages of this method is that
querying will be very easy.
you can add multiple events for a user.
you can add multiple events for a group.
But you should make sure that while adding an event to Group_Event
you should also add the same event to User_Event WHERE "User_Event.user-id" = "group_user.user_id" AND "group_user.group_id" = "Group_Event.group-id".

Database design issue in project?

I am designing a database for my app. In which I want to do mapping between multiple tables. Now situation is like There is one user table. User can have generate multiple orders. So I was thinking if I can put json obejct of order_id in a column in order table. Or I can create a user_id column in order table & repeat user_id for same user. So which is a better way of doing it?
PS: What is the standard way of doing it?
You should just have user_id in your order table, then make queries like
select * from orders where user_id = *some_user_id*
A user can place multiple orders which in turn can have multiple line items. Each line item can have n quantity of a specific product. So when product comes in picture, then it becomes many to many relationship between user and product because a user can place order for many products and a product can be ordered by many users. So my suggestion is -
Create a User table with UserID
Create a PurchaseOrder table with OrderID, UserID and LineItemID
Create a LineItem table with OrderID, ProductID and LineItemID
Create a SKU table with ProductID
A user can place multiple orders.
Based on this you should maintain three different tables as given below:
User (user_id,...)
Order (order_id,...)
UserOrder (user_id,order_id,...)
Only the primary keys in the above tables are focused
Storing comma separated list or json object will worsen the design. And this is strongly discouraged.
EDIT:
As #NevilleK suggested, the above design is typically used for many-to-many relationships. For one-to-many relationship you can create a foreign key constraint in orders table where user_id should refer to the user_id in the User table.
But still you can adopt the above design for one-to-many relationship since many-to-many qualifies for one-to-many too.
The best way is to have different table for your
User table - which hosts the user information
Transaction table - which will have order_id against each user_id.
Transaction table will carry all the transaction details with user_id. If you create a JSON object, how will you map the USER to the transaction. So at the time of retrieving the json information you will have to map it to the user table anyway. I suggest you the use the above said method, which will help you maintain and scale your application much easily.

How to design table when have two table reference single column in another table

I am confusing about how to design table when have two table reference single column in another table.
For example, I have two type of user ( lets call them user1 and user2 ) because these two type user have multiple different information so I create two table for each of them, and each user have one account to login to system. So I create a table call account and let two table user1 and user2 reference to ID in table account. So when I have one account and I want to know which one this account belong to. It's quite inconvenient because I have to look for in two table.
Does it have solution for this problem ?
If you have an entity user, create just one table user for them.
A user is a user, no matter if he has some special role. There will be some common fields for all users, e.g. a name.
table user:
user id
user name
age
homepage
To have specific information for different types of users, you create specialisation table with information about these roles:
table role1:
user id
roleinfo1
roleinfo2
table role2:
user id
roleinfo3
roleinfo4
roleinfo5
This way, a user can have multiple roles at the same time, but you can of course limit them to just one.
If a user can only be one of those roles (that's called disjunct), you have the additional statndard way to add a column role to your user-table and put all the information side-by-side in the user table, leaving the ones that don't belong to the user-role null:
table user:
user id
user name
age
homepage
roletype
roleinfo1
roleinfo2
roleinfo3
roleinfo4
roleinfo5
Even if the user can belong to multiple classes and in case there is no overlap between the additional columns, you can of course use the last approach and add multiple flags (e.g. columns istype1 and istype2), though this is a non-standard-approach.
Update Just to clarify how you use the first solution: every user has an entry in table user, e.g. with user id = 1. This also makes sure that no user of roles user1 and user2 can have the same user id.
User id in the role tables is both primary key and a foreign key of the user table.
To make that user a user of role 1, you then add an entry to table role 1 with user id = 1. If he is (also) a user of role 2, you add an entry to table role2 with user id = 1.
You can join the tables to get the "whole" picture,
select * from user
left join role1 on user.`user id` = role1.`user id`
left join role2 on user.`user id` = role2.`user id`
This will, apart from the double id columns (that will basically can be treated as the marker istype1, istype2 in the comment to the seconds solution) and the missing role-column look exactly like the second method with just one table.
To check if user with user id = 1 is of role 1, you can check if role1.user id is null in this query, or check if user id = 1 is in table role1. To e.g. list all data for just role 1, you can use
select * from user join role1 on user.`user id` = role1.`user id`
(it uses a join instead of the left join, since and entry for role 1 has to exist).
In most cases you don't even need the specialized data, so you can just join your account-table with the user-table. In any case, you never have to worry about checking two tables (or even more, if you decide to add a 3rd kind of user).
Whats the point of the account table? If each user has one account, why don't you store the account columns in the User table.
Furthermore you can still make a parent user table for the columns they share and then make childtables for the specific users.
for example
Parent: User
Children: Employee/Customer

Establishing relationships in a database between multiple tables

I have a web application which allows users to join multiple groups.
I have a 'users' table which stores details about the users (id, email, password, etc.) and a 'groups' table which stores details about the available groups (id, name, owner of group).
I have been researching the best way to store group memberships (i.e. which users are in which group, bearing in mind they can be members of multiple) - however I am still not sure what the most efficient solution would be.
Would you recommend I:-
Create a second table called 'group_memberships' and store the user's ID along with the corresponding group ID?
Store an array alongside the group particulars in the 'groups' table with the user IDs of its members?
Approach this task a different way?
The DBMS I am using is phpMyAdmin.
I would advise you to go with option 1; where you have a Mapping Table for linking Users & Groups.
The Users Table will have PK on User_ID.
The Groups table will have PK on Group_ID.
The Mapping table will have User_ID(FK) and Group_ID(FK).
Now you should have PK on these two columns together.
This will ensure you don't have duplicate entries.
What you're describing is called a many-to-many relationship in database terms. A user can belong to multiple groups, and groups have more than one user (or else they wouldn't be "groups"!).
Your first idea, the group_memberships table, is the accepted best way to model this relationship. Although you'll want to name it users_groups or something similar to reflect the fact it relates or associates those two tables. At its most basic, this association table needs three columns:
ID (primary key)
user_id (foreign key)
group_id (foreign key)
By JOINing to this table ON either user_id or group_id, you can find the related records from either side of the relationship. And you can do it right from a SQL query, without any additional code like you'd need if you stored an array.
I would definitely go with option 1 - creating the junction table 'group_memberships' - I have used this approach many times without problems. Don't forget to add an Index on the new table 'group_memberships' for columns: 'groupID' and 'userID'.
Option 2 is not scalable for a large amount of data, especially if groups have a lot of users.
UPDATE:
For info on Indexes, here is a good (and short) blog: https://blog.viaduct.io/mysql-indexes-primer/.
The first option is a right choice. Actually it is a materialized view for both user table and group table.
Just think materialized view as a extra table or a redundant data structure that denormalizes the user properties and group properties together for quick search.
Since if we do not have the view, when we query a group id to list all its users, we have to filter millions of users to check if he/she is in the certain group. It is a performance nightmare!
Mysql has tools to build this view very efficiently. You may build secondary index on this view columns for quick search, say, group id, group name, user id, user name or something else you hope to search with.
good luck :-)

MySQL - Table Implementation

I had to implement the following into my database:
The activities that users engage in. Each activity can have a name with up to 80 characters, and only distinct activities should be stored. That is, if two different users like “Swimming”, then the activity “Swimming” should only be stored once as a string.
Which activities each individual user engages in. Note that a user can have more than one hobby!
So I have to implement tables for this purpose and I must also make any modifications to existing tables if and as required and implement any keys and foreign key relationships needed.
All this must be stored with minimal amount of storage, i.e., you must choose the appropriate data types from the MySQL manual. You may assume that new activities will be added frequently, that activities will almost never be removed, and that the total number of distinct activities may reach 100,000.
So I already have a 'User' table with 'user_id' as my primary key.
MY SOLUTION TO THIS:
Create a table called 'Activities' and have 'activity_id' as PK (mediumint(5) ) and 'activity' as storing hobbies (varchar(80)) then I can create another table called 'Link' and use the 'user_id' FK from user table and the 'activity_id' FK from the 'Activities' table to show user with the activities that they like to do.
Is my approach to this question right? Is there another way I can do this to make it more efficient?
How would I show if one user pursues more than one activity in the foreign key table 'Link'?
Your idea is the correct, and only(?) way.. it's called a many to many relationship.
Just to reiterate what you're proposing is that you'll have a user table, and this will have a userid, then an activity table with an activityid.
To form the relationship you'll have a 3rd table, which for performance sake doesn't require a primary key however you should index both columns (userid and activityid)
In your logic when someone enters an activity name, pull all records from the activity table, check whether entered value exists, if not add to table and get back the new activityid and then add an entry to the user_activity table linking the activityid to the userid.
If it already exists just add an entry linking that activity id to the userid.
So your approach is right, the final question just indicates you should google for 'many to many' relationships for some more info if needed.