I'm having trouble figuring out the best way to store what information my users want to see. I apologize for not being able to find an easy way to explain my problem, but here goes (the fruits are for example's sake):
Let's say my users have an option to keep track of the following fruits in their fridge:
Apples, Oranges, Grapes, Pears
The database is already setup with a table called 'fruits', where Apples is id_fruit=1, Oranges is id_fruit=2, etc.
Like I said all users have the OPTION to keep track of these fruits, however... I currently can not figure out an easy way to store the users selection of WHICH fruits they want to track. If user 1 doesn't like Apples, he can just go into his settings, uncheck Apples and no longer have Apples show up in his dashboard.
The only way I can think to store this information is to create a table that contains for fields user_id, apples, orange, grapes, pears. And then storing the user_id and Yes/No or 0/1 for the fruits.
This causes major grief if I ever want to add more fruits, or whatever.
What is the best way to store this information in MySQL, using PHP. And how would I retrieve that info.
User logs in, check the DB for which fruits he wants to see, and display only those fruits he has chosen.
Any help would be greatly appreciated.
This is a classic has-and-belongs-to-many, or simply many-to-many, relationship.
Table `users`
=============
id
name
...
Table `fruits`
==============
id
name
...
Table `users_fruits`
====================
id
user_id
fruit_id
In users_fruits you store one row per user-fruit relationship: (user_id: 42, fruit_id: 3).
Create a table tracking the actual relation.
You have one user table, with user id's. You have one fruit table, with fruit id's.
Create a table with user-fruit-relations. Let it have three colums, id, user_id and fruit_id.
If user 1 tracks fruits 2,3 and 5, insert those three rows in the table. That is, three rows with user_id = 1 and the different fruit_id's for each row.
Related
I'm building a simple login/registration feature, and I'm having a little trouble.
The issue is this, the user system I'm designing is supposed to accommodate different types of users, like (Blue users, Red users, Black users etc). So I was considering porting their different user data to separate database tables, and even giving them separate registration pages, because the content they would view on the site would vary depending on their color.
For example:
Blue Users:
INSERT 'username' INTO `blue` where...
Red Users:
INSERT 'username' INTO `red` where...
But I want to know if there's a way to log them into the site from the same login page without resorting to sending them to different pages when they want to login. I tried the following:
"SELECT `id` FROM `blue`,`red` WHERE `username`...
but it did not work, so I'm asking if there's a way to register the different user types on the same page and log them in on the same page while still giving them their different content.
One problem is probably that the "id" value is an auto-incremented primary key, right? Therefore it would be unique to only the table that they are in, but not over all tables (blue, red, black)
You would then always have to make sure to have unique usernames and ids over all groups or let them select what group they are when they log in and then only load data from that table.
If you have already solved the uniqueness problem, you should be able to simply use the union querys already suggested by other users. You can't use blue, red, because that is short for blue JOIN red, which of course will only result in data where columns with the same name are equal across blue and red.
Assuming that the user can be just in one table, you could use UNION...
SELECT id FROM blue WHERE username...
UNION
SELECT id FROM red WHERE username...
... but as a piece of advice, if user info is the same for all, you better have one table for usertypes and another for users, and link them with a foreign key...
USERTYPES TABLE
id_usertype
usrt_name
USERS TABLE
id_user
id_usertype (this should be a foreign key)
usrname
I hope it helps.
I have a table in database and there is column which contains multiple questions separated by commas(hockey,cooking,movies).
My question is that right now I'm firing a select query which is like this:-
$query="$sql="SELECT * from user where hobbies='$form_id'";
Actually in $form_id I'm passing the value say(games), now I want to display all the rows in the database which contains 'games'in them. Remember i have to compare this value with multiple values in the columns in that particulars of the database.
I'm using corephp with mysql as database. I really don't know how to do this please help me out.
SELECT * FROM user WHERE hobbies LIKE '%$form_id%';
but you should change your database schema like:
users(id, name, firstname, ...)
hobbies(id, name)
user_hobbies(id_user, id_hobby)
In reaction to John Conde's remark, the problem here is lying to your data model.
If a person can have several hobbies, you shouldn't store those hobbies in a field of the "person" table. Long story short, you should have 3 tables :
"Person" Table => Everything related to the person, and unique : name, birthdate, etc... NO HOBBIES !
"Hobbies" table => Everything related to the hobbies. The most simple form would be 2 fields : id & hobbyname. You could imagine adding more details in other fields, like is it an indoor or outdoor hobby, etc...
"PersonHobbies" table, used to link both : In that one, you'll probably have only 2 fields, 1 for the person id, one for the hobby id. Then if a person has 3 hobbies, you just write 3 records to that table with the same user id and a different hobby id
There are many advantages to this normalization. the biggest one is that it makes your queries easier to select but also update hobbies of a user. It also makes it easier to count how many hobbies each person has and so on. so, you SHOULD ALWAYS normalize your data, it doesn't take much more time when creating database and waves you a lot of time afterwards
I have a MySQL database with a growing number of users and each user has a list of items they want and of items they have - and each user has a specific ID
The current database was created some time ago and it currently has each users with a specific row in a WANT or HAVE table with 50 columns per row with the user id as the primary key and each item WANT or HAVE has a specific id number.
this currently limits the addition of 50 items per user and greatly complicates searches and other functions with the databases
When redoing the database - would it be viable to instead simply create a 2 column WANT and HAVE table with each row having the user ID and the Item ID. That way there is no 'theoretical' limit to items per user.
Each time a member loads the profile page - a list of their want and have items will then be compiled using a simple SELECT WHERE ID = ##### statement from the have or want table
Furthermore i would need to make comparisons of user to user item lists, most common items, user with most items, complete user searches for items that one user wants and the other user has... - blah blah
The amount of users will range from 5000 - 20000
and each user averages about 15 - 20 items
will this be a viable MySQL structure or do i have to rethink my strategy?
Thanks alot for your help!
This will certainly be a viable structure in mysql. It can handle very large amounts of data. When you build it though, make sure that you put proper indexes on the user/item IDs so that the queries will return nice and quick.
This is called a one to many relationship in database terms.
Table1 holds:
userName | ID
Table2 holds:
userID | ItemID
You simply put as many rows into the second table as you want.
In your case, I would probably structure the tables as this:
users
id | userName | otherFieldsAsNeeded
items
userID | itemID | needWantID
This way, you can either have a simple lookup for needWantID - for example 1 for Need, 2 for Want. But later down the track, you can add 3 for wishlist for example.
Edit: just make sure that you aren't storing your item information in table items just store the user relationship to the item. Have all the item information in a table (itemDetails for example) which holds your descriptions, prices and whatever else you want.
I would recommend 2 tables, a Wants table and a Have table. Each table would have a user_id and product_id. I think this is the most normalized and gives you "unlimited" items per user.
Or, you could have one table with a user_id, product_id, and type ('WANT' or 'HAVE'). I would probably go with option 1.
As you mentioned in your question, yes, it would make much more sense to have a separate tables for WANTs and HAVEs. These tables could have an Id column which would relate the row to the user, and a column that actually dictates what the WANT or HAVE item is. This method would allow for much more room to expand.
It should be noted that if you have a lot of of these rows, you may need to increase the capacity of your server in order to maintain quick queries. If you have millions of rows, they will have a great deal of strain on the server (depending on your setup).
What you're theorizing is a very legitimate database structure. For a many to many relationship (which is what you want), the only way I've seen this done is to, like you say, have a relationships table with user_id and item_it as the columns. You could expand on it, but that's the basic idea.
This design is much more flexible and allows for the infinite items per user that you want.
In order to handle wants and have, you could create two tables or you could just use one and have a third column which would hold just one byte, indicating whether the user/item match is a want or a need. Depending on the specifics of your projects, either would be a viable option.
So, what you would end up with is at least the following tables:
Table: users
Cols:
user_id
any other user info
Table: relationships
Cols:
user_id
item_id
type (1 byte/boolean)
Table: items
Cols:
item_id
any other item info
Hope that helps!
Say I have a table customers with the following fields and records:
id first_name last_name email phone
------------------------------------------------------------------------
1 Michael Turley mturley#whatever.com 555-123-4567
2 John Dohe jdoe#whatever.com
3 Jack Smith jsmith#whatever.com 555-555-5555
4 Johnathan Doe 123-456-7890
There are several other tables, such as orders, rewards, receipts which have foreign keys customer_id relating to this table's customers.id.
As you can see, in their infinite wisdom, my users have created duplicate records for John Doe, complete with inconsistent spelling and missing data. An administrator notices this, selects customers 2 and 4, and clicks "Merge". They are then prompted to select which value is correct for each field, etc etc and my PHP determines that the merged record should look like this:
id first_name last_name email phone
------------------------------------------------------------------------
? John Doe jdoe#whatever.com 123-456-7890
Let's assume Mr. Doe has placed several orders, earned rewards, generated receipts.. but some of these have been associated with id 2, and some have been associated with id 4. The merged row needs to match all of the foreign keys in other tables that matched the original rows.
Here's where I'm not sure what to do. My instinct is to do this:
DELETE FROM customers WHERE id = 4;
UPDATE customers
SET first_name = 'John',
last_name = 'Doe',
email = 'jdoe#whatever.com',
phone = '123-456-7890'
WHERE id = 2;
UPDATE orders, rewards, receipts
SET customer_id = 2
WHERE customer_id = 4;
I think that would work, but if later on I add another table that has a customer_id foreign key, I have to remember to go back and add that table to the second UPDATE query in my merge function, or risk loss of integrity.
There has to be a better way to do this.
I got here form google this is my 2 cents:
SELECT `TABLE_NAME`
FROM `information_schema`.`KEY_COLUMN_USAGE`
WHERE REFERENCED_TABLE_SCHEMA='DATABASE'
AND REFERENCED_TABLE_NAME='customers'
AND REFERENCED_COLUMN_NAME='customer_id'
add the db for insurance (you'll never know when somebody copies the db).
Instead of looking for a column name, here we look at the foreign keys themselves
If you change the on delete restrictions to restrict nothing can be deleted before the children are deleted/migrated
The short answer is, no there isn't a better way (that I can think of).
It's a trade off. If you find there are a lot of these instances, it might be worthwhile to invest some time writing a more robust algorithm for checking existing customers prior to adding a new one (i.e. checking variations on first / last names, presenting them to whoever is adding the customer, asking them 2 or 3 times if they are REALLY sure they want to add this new customer, etc.). If there are not a lot of these instances, it might not be worth investing that time.
Short of that, your approach is the only way I can think of. I would actually delete both records, and create a new one with the merged data, resulting in a new customer id rather than re-using an old one, but that's just personal preference - functionally it's the same as your approach. You still have to remember to go back and modify your merge function to reflect new relationships on the customer.id field.
At a minimum, to prevent any triggers on deletions causing some cascading effect, I would FIRST do
update SomeTable set CustomerID = CorrectValue where CustomerID = WrongValue
(do that across all tables)...
THEN
Delete from Customers where CustomerID = WrongValue
As for duplicate data... Try to figure out which "Will Smith, Bill Smith, William Smith" if you are lacking certain information... Some could be completely legitimate different people.
As an update to my comment:
use information_schema;
select table_name from columns where column_name = 'customer_id';
Then loop through the resulting tables and update accordingly.
Personally, I would use your instinctive solution, as this one may be dangerous if there are tables containing customer_id columns that need to be exempt.
I have a table that holds user information. One of the columns holds the position of the user in the game they are in.
When a game is being created, I need to update the positions of the users of each team.
Here is an example:
Game id : 7
Team 1 users : 1,2
Team 2 users : 3,4
team1_position : array(1,2)
team2_position : array(13,14)
What I want to do is update the user table using the array of positions in the SET area.
My goal is to be able to update the users without the need for their id (I have different size game boards, so I have multiple position arrays for each board size)
How can I do something like this:
UPDATE user
SET position='(team1_position)'
WHERE game = '7' AND team = '1'
I feel like it would be a waste of resources to select all the id's of each team and update them separately.
I have a hard time understanding what you are trying to do, better explanation would be nice. From what I understand you are selecting data from tables in order to update other tables. Have you tried using an "UPDATE .. JOIN .." query? This should allow you to update multiple rows from one table based on associative data from another table.
For example
UPDATE user
JOIN game ON
user.id=game.id_user
SET user.position=game.team1_position
Obviously this wont work with your code as I have very little info to go on, but that should give you an idea of what to go with.
Sorry if I'm totally off in understanding your problem, as said it's a bit hard to understand your exact issue based on what you've given us.