This question already has answers here:
Is storing a delimited list in a database column really that bad?
(10 answers)
Closed 3 years ago.
I want to store user information in Mysql for my Python Program.
One of the things I want to store is username history (static list)
Another is which groups they are a member of (dynamic list)
I am new to storing data in Mysql so am trying to figure out the best structure to achieve this. It seems like I could create 1 table for each user and have the name hsitory as a column, but everything I read tells me this would be wasteful and inefficient.
so for example....
Table = users
user_ID | current_username | username_history | groups_joined | groups_banned
========|==================|==================|===============|==============
01567 | Dave |Michael,Geoff, |group1,group2, |group4,group5
| |Bob,Nigel,Colin |group2 |group5,group7
========|==================|==================|===============|==============
01568 | Fred |Martin,Simon, |group3,group4, |group4,group3
| |Leo,Nick,Arthur |group6 |group2,group12
My first thought was to do something like the above and when I have a list to store like username_history I would convert the list to a string with comma seperated values and store it in a LONGTEXT field as shown. Then to add usernames as the user changes them I could use concat to add to the string.
This would work I guess, but it feels ugly and im sure there must be a better way. Also I think this would be very inefficient if I needed to search for a name in username history, find out all users that were called Fred for example.
My next thought was to create an entire table per user and populate the username_column with one name per field.
But googling around I found similar questions from database noobs all with replies saying this would create thousands of tables and be very inefficient.
ok so now im looking at relational tables (correct terminology??)....
table = username_history
user_id | usernames
========|==========
01567 | but I still need a list here....
I'm sure this is a very common problem for beginners, but I just can't seem to get my head around how the structure for my usage would look.
Thanks to anyone taking the time to help and advise :)
Create a table username_history with:
create table username_history (
id int not null auto_increment,
user_id varchar(10),
username varchar(30),
created_at datetime default CURRENT_TIMESTAMP,
primary key (`id`),
index (user_id)
);
You can then get the usernames in list format using GROUP_CONCAT-function.
You really need three tables:
Groups
Users
UserGroups
The first contains a list of the groups which user may join. It could be as simple as a unique ID and Group Name.
The second table is similar to your table in the question. For this purpose, the only columns we are concerned with are the unique ID for each user and their user name.
The third table has two columns: user_id and group_id. When a user joins a group, a row is inserted into this table with the unique IDs of the user and group.
You could also have a column with a timestamp of when the row was added, and a column for the user's status if needed.
The timestamp column would let you know when the user joined the group.
The status column could indicate if the user is banned from the group, or if the user left the group.
Related
We have a DB on SQL, where we have a table (1) for users and a table (2) for user's saved information. Each piece of information is one line in table (2). So my question is the following - If we are intending to grow number of users to more than 1.000.000 and each user can have more than 10 piece of information, which of the following is a better way to build our DB:
a) Having 2 tables - 1 for users and 1 for information from all users, related to users with ID
b) Having a separate table for each user.
Thanks in advance.
Definitely it should be having a single table for the user is much better. Think from the DB prospective. You are thinking about the search time in a 1.000.000 row for a sorted ID. In the second case you have to search 1.000.000 table to get into a right table. So better go for option A.
I'm going to agree that option A is the better of the two options presented.
That being said, I would personally break up the information for the users into more tables as well. This would all be connected using foreign keys and will allow for more specific querying of the information.
SQL is not really horizontally scalable, so if you end up with users with less or more information than others, then you'll have NULL columns and this requires dealing with in various ways.
By using separate tables, you can still have all of the information contained, but not have to worry if one user has a home and cell phone number, while another only has a cell number.
If and when you do need to access a lot of the information at once, SQL is very good at dealing with this through joins and the like.
Option B is not bad, it just does not fit SQL. I would work if the DB in question was document based instead of tables. In that case, creating a single document for each user is a good idea, and likely preferred.
Option C)
table for users with a unique UserID as Clustered Index (Primary Key)
table for Type of saved information with a unique InformationID as Clustered Index (Primary Key)
table for UserInformation with unique UserInformationID as Clustered Index (Primary Key), a column for UserID (nonclustered index, foreign key to user table) and a column for InformationID (nonclustered index, foreign key to Information table). Have a "Value" or similar column to hold the data being save as it relates to the type of information.
Example:
Users Table
UserID UserName
1 | UserName1
2 | UserName2
Information Table
InfoID InfoName
1 | FavoriteColor
2 | FavoriteNumber
3 | Birthday
UserInformation Table
ID UserID InfoID Value
1 | 1 | 1 | Blue
2 | 1 | 2 | 7
3 | 1 | 3 | '11/01/1999'
4 | 2 | 3 | '05/16/1960'
This method allows for you to save any combination of values for any user without recording any of the non-supplied user information. It keeps the information table 'clean' because you won't need to keep adding columns for each new piece of information you wish to track. Just add a new record to the Info table, and then record only the values submitted to the UserInformation table.
I am currently making a database, and truth to be told I'm not exactly very good at it (kinda being forced to do it). Its a game database, and I have a table called game_table that I use for storing game sessions that users create.
The question is, what is the best way to store a list of invited users, requested users, confirmed users, declined users and pending users? Currently I am serializing the user IDs (e.g. invited users = "11235|2510|34630|45715|64530"). However, the main problem is that the field becomes not searchable, and it becomes a problem if I want to retrieve a list of games that a user is invited to. To solve that problem, I store a separate field in the user_table for invited_games (also serialized game IDs).
The problem with that, is that it is getting hard to maintain whenever I want to add new features, and it is too easy to make mistakes with keeping the serialized data in sync. Is it better to have separate tables like:
invited_users_table
Game_ID | User_ID
51 | 5193
51 | 10458
51 | 235
901 | 1536
901 | 4573
Or is there some other better way of storing these types of data? Please help, and thanks!
From what you say, it sounds like you need one table with three columns:
GameId
UserId
UserType
The latter would take on values such as "invited", "confirmed", "requested" and so on.
You would want separate tables if you had more information about the different groups. For instance, you might have a "who invited" column for invited users, or a "confirmation time" for confirmed users. If the number of specific columns needed for the different groups is large-ish, then you might want to think about a more complex data structure. If there are just a handful of such columns, you can add them into the table described above.
Yes, it is better to have a separate table for invited users.
Yet better would be to have game_user_relation table, which will store the game id, the user id and the relationship between them. Kinda:
create table game_user_relation(
game_id int not null,
user_id int not null,
relation_type varchar (10) not null,
primary key(game_id, user_id, relation_type)
) engine=InnoDB;
This table will allow one user to have many relations to one game.
Or, if you need to have exactly one user relate to one game - remove relation_type from primary key.
This way you could select all needed data from one table.
our database contain 5+ tables
user
----------
user_id (PK) int NOT NULL
name varchar(50) NOT NULL
photo
--------
photo_id (PK) int NOT NULL
user_id (FK) int NOT NULL
title varchar(50) NOT NULL
comment
-------
comment_id (PK) int NOT NULL
photo_id int NOT NULL
user_id int NOT NULL
message varchar(50) NOT NULL
all primary key id's are unique id's.
all data are linked to http://domain.com/{primary_key_id}
after user visit the link with id, which is unique for all tables.
how should i implement to find what table this id belongs to?
solution 1
select user_id from user where user_id = {primary_key_id}
// if not found, then move next
select photo_id from photo where photo_id = {primary_key_id}
... continue on, until we find which table this primary key belongs to.
solution 2
create object table to hold all the uniqe id and there data type
create trigger on all the tables for AFTER INSERT, to create row in object table with its data type, which was inserted to a selected table
when required, then do select statement to find the table name the id belongs to.
second solution will be double insert. 1 insert for row to actual table with complete data and 2 insert for inserting unique id and table name in object table, which we created on step 1.
select type from object_table where id = {primary_key_id}
solution 3
prepend table name + id = encode into new unique integer - using php
decode id and get the original id with table name (even if its just as number type)
i don't know how to implement this in php, but this solution sounds better!? what are your suggestion?
I don't know what you mean by Facebook reference in the comments but I'll explain my comment a little further.
You don't need unique ID's across five DB tables, just one per table. You have couple of options how to create your links (you can create the links yourself can you?):
using GET variables: http://domain.com/page.html?pk={id}&table={table}
using plain URL: http://domain.com/{id}{table}
Depending on the syntax of the link you choose the function to parse it. You can for example use one or both of the following:
http://php.net/manual/en/function.explode.php
http://www.php.net/manual/en/function.parse-url.php
When you get the simple model working you may add encoding/decoding/hashing functions. But do you really need them? And in what level? (I have no experience in that area so I'll shut up now.)
Is it actually important to maintain uniqueness across tables?
If no, just implement the solution 3 if you can (e.g. using URL encoding).
If yes, you'll need the "parent" table in any case, so the DBMS can enforce the uniqueness.
You can still try to implement the solution 3 on top of that,
or add a type discriminator1 there and you'll be able to (quickly) know which table is referenced for any given ID.
1 Take a look at the lower part of this answer. This is in fact a form of inheritance.
I'm having a hard time representing the following situation in the database:
A user can declare multiple addresses (such as Home, Office, Mailing etc. as requested by client).
I have an auto-incremented primary key called UserID that represents one user account. I've been thinking of making a BelongsToUserID column to represent each user's form field to look like:
I can't do this because each row can only be occupied by UserID row.
Any thoughts on how to achieve this?
You want a separate table holding the addresses. Perhaps something like:
| id(primary key) | type(enum home/work/etc.) | userID | address |
you can make this in two ways
first one is simple but not adviced is that you don't make any primary key and use composite key pair as the candidate key and choose primary from that. as the table is missing the primary key its not adviced
second approach is good and i also use that is to make a master table and use that as the relation-table there and use another table to actually store the data.
in master table you can have id, userid, address_bit, and in second table you can have id, address_bit, address.
please tell me any other solution if you found one. It might help me to learn new :)
I need to sell items on my fictitious website and as such have come up with a couple of tables and was wondering if anyone could let me know if this is plausible and if not where i might be able to change things?
I am thinking along the lines of;
Products table : ID, Name, Cost, mediaType(FK)
Media: Id, Name(book, cd, dvd etc)
What is confusing me is that a user might have / own many products, but how would you store an array of product id's in a single column?
Thanks
You could something like store a JSON array in a text or varchar field and let the application handle parsing it.
MySQL doesn't have a native array type, unlike say PostgreSQL, but in general I find if you're trying to store an array you're probably doing something wrong. Of course every rule has its exceptions.
What your probably want is a user table and then a table that correlates products to users. If a product is only going to relate to one user then you can add a user ID column to your Products table. If not, then you'll want another lookup table which handles the many to many relationship. It would look something like this:
------------------------
| user_id | product_id |
------------------------
| 1 | 1 |
| 1 | 2 |
| 1 | 3 |
| 2 | 2 |
| 3 | 1 |
| 3 | 5 |
------------------------
I think one way of storing all the products which user has in one column is to store it as a string where product ids are separated by some delimiters like comma. Though this is not the way you want to solve. The best way to solve this problem would be to have a seperate user table and than have a user product table where you associate userid with product id. You could than simple use a simple query to get list of all the products owned by a particular userid
As a starting point, try to think of the system in terms of the major parts - you would have a 'warehouse', so you need a table to list the products you have, and you are going to possibly have users who register their details with you for regular visits - so an account per user. You would generally hold all details of a single product in the same row of the same table (unless you have a really complex product to detail, but not likely). If you're going to keep track of products bought per user account, there's always the option of keeping the order history as a delimited list in a large text field. For example: date,id,id,id,id;date,id,id. Or you could simply refer to order numbers and have a separate table for orders placed [by any customer].
What is confusing me is that a user might have / own many products, but how would you store an array of product id's in a single column?
This is called a "many-to-many" relationship. In essence you would have a table for users, a table for products, and a table to map them like this:
[table] Users
- id
- name
[table] Products
- id
- name
- price
[table] Users_Products
- user_id
- product_id
Then when you want to know what products a user has, you could perform a query like:
SELECT product_id FROM Users_Products WHERE user_id=23;
Of course, user id 23 is fictituous for examples sake. The resulting recordset would contain the id's of all the products the user owns.
You wouldn't store an array of things into a single column. In fact you usually wouldn't store them in separate columns either.
You need to step away from design for a bit and go investigate third normal form. That should be you starting point and, in the vast majority of cases, your ending point for designing database schemas.
The correct way of handling variable size "arrays" is with two tables with a many to one relationship, something like:
Users
User ID (primary key)
Name
Other user info
Objects:
Object Id (primary key)
User id (foreign key, references Users(User id)
Other object info
That's the simplest form where one object is tied to a specific user, but a specific user may have any number of objects.
Where an object can be "owned" by multiple users (I say an object meaning (for example) the book "Death of a Salesman", but obviously each user has their own copy of an object), you use a joining table:
Users
User ID (primary key)
Name
Other user info
Objects:
Object Id (primary key)
User id (foreign key, references Users(User id))
Other object info
UserObjects:
User id (foreign key, references Users(User id))
Object id (foreign key, references Objects(Object id))
Count
primary key (User id, Object id)
Similarly, you can handle one or more by adding an object id to the Users table.
But, until you've nutted out the simplest form and understand 3NF, they won't generally matter to you.