How would you design this database? Individual and group ownership - mysql

I have a list of items, and items can be owned either by an individual person or a group of people.
So far I have 3 tables like:
People:
personID (primarykey)
personName
personAddress
...
Groups:
groupID (primarykey)
groupNumber
personID
Items:
itemID (primarykey)
itemName
itemDescription
itemWeight
...
How would you go about assigning ownership of items to an individual, or a specific group?
I did have 2 fields on the item, owner_personID and owner_groupID, but seems kinda janky, and have to manually manage which field to use at a time.
I also tried two linking tables, PeopleOwnerships, and GroupOwnerships, that store a list of items owned. With fields like, personID/groupID and itemID. But, seems even more jankier and can get messy. Have to be extra careful so that both individuals and groups don't own the same item at the same time.
I have also thought about putting all individuals in their own individual group, and just using the Groups table to refer to everything. But that also seems kind of weird.
I would also need to record the transfer of items, between people and groups, when ownership changes. I've thought about having a date field in the linking tables, and using the highest date to determine who owns what.

You could treat a person as a group of 1 person, and only allow groups to own items.
Something better may be to have a class called "Owner" which only has the ID of the item and its ID (the id of the owner), and get both classes Person and Group extending it.
About the transfers, I wouldn't rely that business logic on the database.

Related

How to normalize a MySQL database in a 'social media' type application

We have 2 tables as a starting point in a MySQL database for a 'social media' type WebApp:
People - there can be an unlimited and ever growing number of people (users) [A,B,C,D,E,F, ...]. Each person has a unique ID.
Groups - there can be an unlimited and ever growing number of groups created by users [G1, G2, G3, G4, G5, G6, ...]. Each group group has a unique ID.
A person can belong to as many groups as they like B.groups=[G1,G3,G5, ...].
A group can have an unlimited number of persons. G2.people=[A, C, H, Z, ...].
We need to efficiently query all the groups that a person belongs to and efficiently query all the people who belong to a group. Creating a table for each person to list groups and each group to list persons would result in a very large number of tables.
I understand that having tables with multiple 'null' values and a very large number of columns is inefficient and that including an array in a field is bad practice - that I need to 'normalize'. I just can't get my head around the table format that could normalize this data requirement. I have been reading many pages on SO and other material such as https://en.wikipedia.org/wiki/Database_normalization
I have considered a table Memberships with only 2 columns: GroupID & PersonID, where each individual relationship is stored. The table may get very long. Would this be good practice? Otherwise, please provide suggestions.

Database Design for a system that has Facebook like groups

I'm creating a system that has Groups. These can be thought of like Facebook Groups. Users can create new groups. Currently I have the following types of groups:
City Group - Groups based on a certain city. For example "London Buy and Sell Group"
School Group - Groups based on schools. For example "London University Study Group"
Interest Group - Groups that are not tied to a place. For example "Over 50's Knitting Group"
In the future more group types will be added. Each group can have different types of options, but all groups have the same basic data:
An ID
A creator ID
A name
An option description
I'm struggling on putting together a database design for this. My initial thought was to create different tables for the different groups.
For example have a single table called group. This table has an id, creator id, name, description, member count, timestamps.
Then have other tables to represent the other groups, and link them to group. So I have a city_group table that contains and id, group_id, city_id. And the same for the other group types.
The only problem I have with this is interest_group doesn't have any extra data that a normal group. But for the purpose of being able to query only Interest Groups I thought it might make sense to create an interest_group table. It would only have the following columns: id, group_id, timestamps ... which seems a bit wasteful to have a table just for this purpose.
Here's a diagram to make things easier:
Are there any issues with my solution, or any better ways to solve this design problem?
I've got an idea, which is a workaround basically: have another table like: group_type in which you have id(the PK) and then you have tablename (the full table name of the type).
Then, you should have a FK from your Group table linking to this group_type table.
id tablename
--------------------
1 School Group
2 Interest Group
After all this is done, you could build your queries based on the values from this table, as an example:
JOIN (SELECT tablename FROM group_type WHERE id=group.group_type_id) ON ..

Mysql setup for multiple users with large number of individual options

i'm building a study tool and i'm not sure of the best way to go about structuring my database.
Basically, i have a simple but big table with around 50000 bits of information in it.
info (50'000 rows)
id
info_text
user
id
name
email
password
etc
What i want is for the students to be able to marked each item as studied or to be studied(basically on and off), so that they can tick off each item when they have revised it.
I want to build tool to cope with thousands of users and was wondering what the most efficient/easiest option way of setting up the database and associated queries.
At the moment i would lean towards just having one huge table with two primary keys one with user id and then id of the info they had studied and then doing some sort of JOIN statement so i could only pull back the items that they had left to study.
user_info
user_id
info_id
Thanks in advance
Here is one way to model this situation:
The table in the middle has a composite primary key on USER_ID and ITEM_ID, so a combination of the two must be unique, even though individually they don't have to be.
A user (with given USER_ID) has studied a particular item (with given ITEM_ID) only if there is a corresponding row in the STUDIED table (with these same USER_ID and ITEM_ID values).
Conversely, the user has not studied the item, if and only if the corresponding row in STUDIED is missing. To pull all items a given user hasn't studied, you can do something like this:
SELECT * FROM ITEM
WHERE NOT EXISTS (
SELECT * FROM STUDIED
WHERE
USER_ID = <given_user_id>
AND ITEM.ITEM_ID = STUDIED.ITEM_ID
)
Or, alternatively:
SELECT ITEM.*
FROM ITEM LEFT JOIN STUDIED ON ITEM.ITEM_ID = STUDIED.ITEM_ID
WHERE USER_ID = <given_user_id> AND STUDIED.ITEM_ID IS NULL
The good thing about this design is that you don't need to care about STUDIED table in advance. When adding a new user or item, just leave the STUDIED alone - you'll gradually fill it later as users progress with their studies.
I would do something like this:
1) A users table with a uid primary key
2) A enrolled table (this table shows all courses that have enrolled students) with a primary key of (uid, cid)
3) A items (info) table holding all items to study, with a primary key of itemid
Then in the enrolled table just have one attribute (a binary flag) 1 means it has been studyed and 0 means they still need to study it.

Best way to store ordered lists in a database?

What's the best way to store "ordered lists" in a database, so that updating them (adding, removing and changing the order of entries) is easily done?
Consider a database where you have a table for users and movies. Each user has a list of favorite movies.
Since many users can like the same movie, I made users and movies separate tables and uses a third table to connect them, usermovies.
usermovies contains an id of a user and a movie and an "order number". The order number is used to order the list of movies for users.
For example, user Josh might have the following list:
Prometheus
Men in Black 3
The Dictator
and user Jack might have a list like:
The Dictator
Prometheus
Battleship
Snow White and the Huntsman
So, they share some favorites, but not necessarily in the same order.
I can get the list of movie IDs for each user using a query:
SELECT movie_id FROM usermovies WHERE user_id =? ORDER BY order_number
Then, with the ordered movie_ids, I can get the list of movies using another query
SELECT name FROM movies WHERE id in (?,?,?) ORDER BY FIELD (id, ?,?,?)
So queries work, but updating the lists seems really complex now - are there better ways to store this information so that it would be easy to get the list of movies for user x, add movies, remove them and change the order of the list?
If you are not looking for a "move up / move down" kinda solution, and then defaulting to adding at the bottom of the list, here are a few more pointers:
Inserting new rows into a specific position can be done like this: (inserting at position 3)
UPDATE usermovies SET order_number = ordernumber + 1
WHERE ordernumber > 3 and user_id = ?;
INSERT INTO usermovies VALUES (?, 3, ?);
And you can delete in a similar fashion: (deleting position 6)
DELETE usermovies WHERE order_numer = 6 and user_id=?;
UPDATE usermovies SET order_number = ordernumber - 1
WHERE ordernumber > 6 and user_id = ?;
A junction/link table with additional columns for the attributes of the association between movies and users is the standard way of realizing a many-many association with an association class - so what you have done seems correct.
Regarding the ease of insert/update/delete, you'll have to manage the entire association (all rows for the user-movie FKs) every time you perform an insert/update/delete.
There probably isn't a magical/simpler way to do this.
Having said this, you'll also need to run these operations in a transaction and more importantly have a 'version' column on this junction table if your application is multi-user capable.
To retrieve user favourites movies you could use a single query:
SELECT um.order_number, m.name FROM movies m
INNER JOIN usermovies um ON m.id = um.movie_id
WHERE um.user_id = ?
ORDER BY um.order_number
To add/remove a favourite movie simply add/remove related record in usermovies table.
To alter a movie order simply change all order_number field in user_movies table related to user.
In addition to what others have said, reordering existing favorites can be done in a single UPDATE statement, as explained here.
The linked answer explains reordering of two items, but can be easily generalized to any number of items.

store list of IDs mysql

I want to store a list of book IDs for a wishlist in mysql; here's what the relevant tables look like:
User_Wishlists
user_id, list_title, list_id (PK)
Wishlist
list_id (FK), book_id (PK)
The issue is with the book_ID. Most users will have multiple books on their lists, but it seems strange to have that represented by book1_id, book2_id, etc. in the table. Is there a better way to store a list of these book_IDs in mysql? I need to be able to retrieve and display a user's wishlist for them.
You need to have an association table that joins users to wishlists. Remember the zero, one, or N principle of database design. Either you have no relationship, a one to one, or a one to many. Using things like book1_id is almost always a defective design.
You may find this is a better structure:
Wishlist
wishlist_id, user_id, ...
WishlistEntry
wishlist_id, book_id, ...
Associate the wishlist with the user directly, then use the WishlistEnry table to find which books are on which wishlist.